1//===- SPIRVDecorate.h - SPIR-V Decorations ----------------------*- C++ -*-===//
2//
3//                     The LLVM/SPIRV Translator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
9//
10// Permission is hereby granted, free of charge, to any person obtaining a
11// copy of this software and associated documentation files (the "Software"),
12// to deal with the Software without restriction, including without limitation
13// the rights to use, copy, modify, merge, publish, distribute, sublicense,
14// and/or sell copies of the Software, and to permit persons to whom the
15// Software is furnished to do so, subject to the following conditions:
16//
17// Redistributions of source code must retain the above copyright notice,
18// this list of conditions and the following disclaimers.
19// Redistributions in binary form must reproduce the above copyright notice,
20// this list of conditions and the following disclaimers in the documentation
21// and/or other materials provided with the distribution.
22// Neither the names of Advanced Micro Devices, Inc., nor the names of its
23// contributors may be used to endorse or promote products derived from this
24// Software without specific prior written permission.
25// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
31// THE SOFTWARE.
32//
33//===----------------------------------------------------------------------===//
34/// \file
35///
36/// This file defines SPIR-V decorations.
37///
38//===----------------------------------------------------------------------===//
39
40#ifndef SPIRVDECORATE_HPP_
41#define SPIRVDECORATE_HPP_
42
43#include "SPIRVEntry.h"
44#include "SPIRVUtil.h"
45#include "SPIRVStream.h"
46#include <string>
47#include <vector>
48#include <utility>
49
50namespace SPIRV{
51class SPIRVDecorationGroup;
52class SPIRVDecorateGeneric:public SPIRVAnnotationGeneric{
53public:
54  // Complete constructor for decorations without literals
55  SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
56      SPIRVEntry *TheTarget);
57  // Complete constructor for decorations with one word literal
58  SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
59      SPIRVEntry *TheTarget, SPIRVWord V);
60  // Incomplete constructor
61  SPIRVDecorateGeneric(Op OC);
62
63  SPIRVWord getLiteral(size_t) const;
64  Decoration getDecorateKind() const;
65  size_t getLiteralCount() const;
66  /// Compare for kind and literal only.
67  struct Comparator {
68    bool operator()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B);
69  };
70  /// Compare kind, literals and target.
71  friend bool operator==(const SPIRVDecorateGeneric &A,
72      const SPIRVDecorateGeneric &B);
73
74  SPIRVDecorationGroup* getOwner() const {
75    return Owner;
76  }
77
78  void setOwner(SPIRVDecorationGroup* owner) {
79    Owner = owner;
80  }
81
82  SPIRVCapVec getRequiredCapability() const {
83    return getCapability(Dec);
84  }
85
86  SPIRVWord getRequiredSPIRVVersion() const override {
87    switch (Dec) {
88    case DecorationSpecId:
89      if (getModule()->hasCapability(CapabilityKernel))
90        return SPIRV_1_1;
91      else
92        return SPIRV_1_0;
93
94    case DecorationMaxByteOffset:
95      return SPIRV_1_1;
96
97    default:
98      return SPIRV_1_0;
99    }
100  }
101
102protected:
103  Decoration Dec;
104  std::vector<SPIRVWord> Literals;
105  SPIRVDecorationGroup *Owner; // Owning decorate group
106};
107
108class SPIRVDecorateSet: public std::multiset<const SPIRVDecorateGeneric *,
109    SPIRVDecorateGeneric::Comparator> {
110    public:
111  typedef std::multiset<const SPIRVDecorateGeneric *,
112      SPIRVDecorateGeneric::Comparator> BaseType;
113  iterator insert(const value_type& Dec) {
114    auto ER = BaseType::equal_range(Dec);
115    for (auto I = ER.first, E = ER.second; I != E; ++I) {
116      SPIRVDBG(spvdbgs() << "[compare decorate] " << *Dec
117                        << " vs " << **I << " : ");
118      if (**I == *Dec)
119        return I;
120      SPIRVDBG(spvdbgs() << " diff\n");
121    }
122    SPIRVDBG(spvdbgs() << "[add decorate] " << *Dec << '\n');
123    return BaseType::insert(Dec);
124  }
125};
126
127class SPIRVDecorate:public SPIRVDecorateGeneric{
128public:
129  static const Op OC = OpDecorate;
130  static const SPIRVWord FixedWC = 3;
131  // Complete constructor for decorations without literals
132  SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget)
133    :SPIRVDecorateGeneric(OC, 3, TheDec, TheTarget){}
134  // Complete constructor for decorations with one word literal
135  SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V)
136    :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget, V){}
137  // Incomplete constructor
138  SPIRVDecorate():SPIRVDecorateGeneric(OC){}
139
140  _SPIRV_DCL_ENCDEC
141  void setWordCount(SPIRVWord);
142  void validate()const {
143    SPIRVDecorateGeneric::validate();
144    assert(WordCount == Literals.size() + FixedWC);
145  }
146
147};
148
149class SPIRVDecorateLinkageAttr:public SPIRVDecorate{
150public:
151  // Complete constructor for LinkageAttributes decorations
152  SPIRVDecorateLinkageAttr(SPIRVEntry *TheTarget,
153      const std::string &Name, SPIRVLinkageTypeKind Kind)
154    :SPIRVDecorate(DecorationLinkageAttributes, TheTarget) {
155      for (auto &I:getVec(Name))
156        Literals.push_back(I);
157      Literals.push_back(Kind);
158      WordCount += Literals.size();
159    }
160  // Incomplete constructor
161  SPIRVDecorateLinkageAttr():SPIRVDecorate(){}
162
163  std::string getLinkageName() const {
164    return getString(Literals.cbegin(), Literals.cend() - 1);
165  }
166  SPIRVLinkageTypeKind getLinkageType() const {
167    return (SPIRVLinkageTypeKind)Literals.back();
168  }
169
170  static void encodeLiterals(SPIRVEncoder& Encoder,
171                             const std::vector<SPIRVWord>& Literals) {
172#ifdef _SPIRV_SUPPORT_TEXT_FMT
173    if(SPIRVUseTextFormat) {
174      Encoder << getString(Literals.cbegin(), Literals.cend() - 1);
175      Encoder.OS << " ";
176      Encoder << (SPIRVLinkageTypeKind)Literals.back();
177    } else
178#endif
179     Encoder << Literals;
180  }
181
182  static void decodeLiterals(SPIRVDecoder& Decoder, std::vector<SPIRVWord>& Literals) {
183#ifdef _SPIRV_SUPPORT_TEXT_FMT
184    if(SPIRVUseTextFormat) {
185      std::string Name;
186      Decoder >> Name;
187      SPIRVLinkageTypeKind Kind;
188      Decoder >> Kind;
189      std::copy_n(getVec(Name).begin(), Literals.size()-1, Literals.begin());
190      Literals.back() = Kind;
191   } else
192#endif
193     Decoder >> Literals;
194  }
195};
196
197class SPIRVMemberDecorate:public SPIRVDecorateGeneric{
198public:
199  static const Op OC = OpMemberDecorate;
200  static const SPIRVWord FixedWC = 4;
201  // Complete constructor for decorations without literals
202  SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
203      SPIRVEntry *TheTarget)
204    :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget),
205      MemberNumber(Member){}
206
207  // Complete constructor for decorations with one word literal
208  SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
209      SPIRVEntry *TheTarget, SPIRVWord V)
210    :SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V),
211      MemberNumber(Member){}
212
213  // Incomplete constructor
214  SPIRVMemberDecorate():SPIRVDecorateGeneric(OC), MemberNumber(SPIRVWORD_MAX){}
215
216  SPIRVWord getMemberNumber() const { return MemberNumber;}
217  std::pair<SPIRVWord, Decoration> getPair() const {
218    return std::make_pair(MemberNumber, Dec);
219  }
220
221  _SPIRV_DCL_ENCDEC
222  void setWordCount(SPIRVWord);
223
224  void validate()const {
225    SPIRVDecorateGeneric::validate();
226    assert(WordCount == Literals.size() + FixedWC);
227  }
228protected:
229  SPIRVWord MemberNumber;
230};
231
232class SPIRVDecorationGroup:public SPIRVEntry{
233public:
234  static const Op OC = OpDecorationGroup;
235  static const SPIRVWord WC = 2;
236  // Complete constructor. Does not populate Decorations.
237  SPIRVDecorationGroup(SPIRVModule *TheModule, SPIRVId TheId)
238    :SPIRVEntry(TheModule, WC, OC, TheId){
239    validate();
240  };
241  // Incomplete constructor
242  SPIRVDecorationGroup():SPIRVEntry(OC){}
243  void encodeAll(spv_ostream &O) const;
244  _SPIRV_DCL_ENCDEC
245  // Move the given decorates to the decoration group
246  void takeDecorates(SPIRVDecorateSet &Decs) {
247    Decorations = std::move(Decs);
248    for (auto &I:Decorations)
249      const_cast<SPIRVDecorateGeneric *>(I)->setOwner(this);
250    Decs.clear();
251  }
252
253  SPIRVDecorateSet& getDecorations() {
254    return Decorations;
255  }
256
257protected:
258  SPIRVDecorateSet Decorations;
259  void validate()const {
260    assert(OpCode == OC);
261    assert(WordCount == WC);
262  }
263};
264
265class SPIRVGroupDecorateGeneric:public SPIRVEntryNoIdGeneric{
266public:
267  static const SPIRVWord FixedWC = 2;
268  // Complete constructor
269  SPIRVGroupDecorateGeneric(Op OC, SPIRVDecorationGroup *TheGroup,
270      const std::vector<SPIRVId> &TheTargets)
271    :SPIRVEntryNoIdGeneric(TheGroup->getModule(), FixedWC + TheTargets.size(),
272        OC),
273     DecorationGroup(TheGroup), Targets(TheTargets){
274  }
275  // Incomplete constructor
276  SPIRVGroupDecorateGeneric(Op OC)
277    :SPIRVEntryNoIdGeneric(OC), DecorationGroup(nullptr){}
278
279  void setWordCount(SPIRVWord WC) {
280    SPIRVEntryNoIdGeneric::setWordCount(WC);
281    Targets.resize(WC - FixedWC);
282  }
283  virtual void decorateTargets() = 0;
284  _SPIRV_DCL_ENCDEC
285protected:
286  SPIRVDecorationGroup *DecorationGroup;
287  std::vector<SPIRVId> Targets;
288};
289
290class SPIRVGroupDecorate:public SPIRVGroupDecorateGeneric{
291public:
292  static const Op OC = OpGroupDecorate;
293  // Complete constructor
294  SPIRVGroupDecorate(SPIRVDecorationGroup *TheGroup,
295      const std::vector<SPIRVId> &TheTargets)
296    :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
297  // Incomplete constructor
298  SPIRVGroupDecorate()
299    :SPIRVGroupDecorateGeneric(OC){}
300
301  virtual void decorateTargets();
302};
303
304class SPIRVGroupMemberDecorate:public SPIRVGroupDecorateGeneric{
305public:
306  static const Op OC = OpGroupMemberDecorate;
307  // Complete constructor
308  SPIRVGroupMemberDecorate(SPIRVDecorationGroup *TheGroup,
309      const std::vector<SPIRVId> &TheTargets)
310    :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
311  // Incomplete constructor
312  SPIRVGroupMemberDecorate()
313    :SPIRVGroupDecorateGeneric(OC){}
314
315  virtual void decorateTargets();
316};
317
318}
319
320
321#endif /* SPIRVDECORATE_HPP_ */
322