1 //===- SPIRVValue.h - Class to represent a SPIR-V Value ---------*- 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 the values defined in SPIR-V spec with op codes.
37 ///
38 /// The name of the SPIR-V values follow the op code name in the spec.
39 /// This is for readability and ease of using macro to handle types.
40 //
41 //===----------------------------------------------------------------------===//
42 
43 #ifndef SPIRV_LIBSPIRV_SPIRVVALUE_H
44 #define SPIRV_LIBSPIRV_SPIRVVALUE_H
45 
46 #include "SPIRVDecorate.h"
47 #include "SPIRVEntry.h"
48 #include "SPIRVType.h"
49 
50 namespace llvm {
51 class APInt;
52 } // namespace llvm
53 
54 #include <iostream>
55 
56 namespace SPIRV {
57 
58 class SPIRVValue : public SPIRVEntry {
59 public:
60   // Complete constructor for value with id and type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType,SPIRVId TheId)61   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
62              SPIRVType *TheType, SPIRVId TheId)
63       : SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
64     validate();
65   }
66   // Complete constructor for value with type but without id
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType)67   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
68              SPIRVType *TheType)
69       : SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
70     setHasNoId();
71     SPIRVValue::validate();
72   }
73   // Complete constructor for value with id but without type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVId TheId)74   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId)
75       : SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
76     setHasNoType();
77     SPIRVValue::validate();
78   }
79   // Complete constructor for value without id and type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode)80   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
81       : SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
82     setHasNoId();
83     setHasNoType();
84     SPIRVValue::validate();
85   }
86   // Incomplete constructor
SPIRVValue(Op TheOpCode)87   SPIRVValue(Op TheOpCode) : SPIRVEntry(TheOpCode), Type(NULL) {}
88 
hasType()89   bool hasType() const { return !(Attrib & SPIRVEA_NOTYPE); }
getType()90   SPIRVType *getType() const {
91     assert(hasType() && "value has no type");
92     return Type;
93   }
94   bool isVolatile() const;
95   bool hasAlignment(SPIRVWord *Result = 0) const;
96   bool hasNoSignedWrap() const;
97   bool hasNoUnsignedWrap() const;
98 
99   void setAlignment(SPIRVWord);
100   void setVolatile(bool IsVolatile);
101   void setNoSignedWrap(bool HasNoSignedWrap);
102   void setNoUnsignedWrap(bool HasNoUnsignedWrap);
103   void setFPFastMathMode(SPIRVWord FPFastMathMode);
104 
validate()105   void validate() const override {
106     SPIRVEntry::validate();
107     assert((!hasType() || Type) && "Invalid type");
108   }
109 
setType(SPIRVType * Ty)110   void setType(SPIRVType *Ty) {
111     Type = Ty;
112     assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction);
113     if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction))
114       setHasType();
115     else
116       setHasNoType();
117   }
118 
getRequiredCapability()119   SPIRVCapVec getRequiredCapability() const override {
120     SPIRVCapVec CV;
121     if (!hasType())
122       return CV;
123     return Type->getRequiredCapability();
124   }
125 
getRequiredExtension()126   llvm::Optional<ExtensionID> getRequiredExtension() const override {
127     llvm::Optional<ExtensionID> EV;
128     if (!hasType())
129       return EV;
130     EV = Type->getRequiredExtension();
131     assert(Module &&
132            (!EV.hasValue() || Module->isAllowedToUseExtension(EV.getValue())));
133     return EV;
134   }
135 
136 protected:
setHasNoType()137   void setHasNoType() { Attrib |= SPIRVEA_NOTYPE; }
setHasType()138   void setHasType() { Attrib &= ~SPIRVEA_NOTYPE; }
139 
140   SPIRVType *Type; // Value Type
141 };
142 
143 template <spv::Op OC> class SPIRVConstantBase : public SPIRVValue {
144 public:
145   // Complete constructor for integer constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,uint64_t TheValue)146   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
147                     uint64_t TheValue)
148       : SPIRVValue(M, 0, OC, TheType, TheId) {
149     setWords(&TheValue);
150   }
151   // Incomplete constructor for AP integer constant
152   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
153                     const llvm::APInt &TheValue);
154   // Complete constructor for float constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,float TheValue)155   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
156                     float TheValue)
157       : SPIRVValue(M, 0, OC, TheType, TheId) {
158     setWords(reinterpret_cast<uint64_t *>(&TheValue));
159   }
160   // Complete constructor for double constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,double TheValue)161   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
162                     double TheValue)
163       : SPIRVValue(M, 0, OC, TheType, TheId) {
164     setWords(reinterpret_cast<uint64_t *>(&TheValue));
165   }
166   // Incomplete constructor
SPIRVConstantBase()167   SPIRVConstantBase() : SPIRVValue(OC), NumWords(0) {}
getZExtIntValue()168   uint64_t getZExtIntValue() const { return getValue<uint64_t>(); }
getFloatValue()169   float getFloatValue() const { return getValue<float>(); }
getDoubleValue()170   double getDoubleValue() const { return getValue<double>(); }
getNumWords()171   unsigned getNumWords() const { return NumWords; }
getSPIRVWords()172   const std::vector<SPIRVWord> &getSPIRVWords() { return Words; }
173 
174 protected:
175   constexpr static SPIRVWord FixedWC = 3;
176 
177   // Common method for getting values of size less or equal to 64 bits.
getValue()178   template <typename T> T getValue() const {
179     constexpr auto ValueSize = static_cast<unsigned>(sizeof(T));
180     assert((ValueSize <= 8) && "Incorrect result type of requested value");
181     T TheValue{};
182     unsigned CopyBytes = std::min(ValueSize, NumWords * SpirvWordSize);
183     std::memcpy(&TheValue, Words.data(), CopyBytes);
184     return TheValue;
185   }
186 
187   void setWords(const uint64_t *TheValue);
recalculateWordCount()188   void recalculateWordCount() {
189     NumWords =
190         (Type->getBitWidth() + SpirvWordBitWidth - 1) / SpirvWordBitWidth;
191     WordCount = FixedWC + NumWords;
192   }
validate()193   void validate() const override {
194     SPIRVValue::validate();
195     assert(NumWords >= 1 && "Invalid constant size");
196   }
encode(spv_ostream & O)197   void encode(spv_ostream &O) const override {
198     getEncoder(O) << Type << Id;
199     for (const auto &Word : Words)
200       getEncoder(O) << Word;
201   }
setWordCount(SPIRVWord WordCount)202   void setWordCount(SPIRVWord WordCount) override {
203     SPIRVValue::setWordCount(WordCount);
204     NumWords = WordCount - FixedWC;
205   }
decode(std::istream & I)206   void decode(std::istream &I) override {
207     getDecoder(I) >> Type >> Id;
208     Words.resize(NumWords);
209     for (auto &Word : Words)
210       getDecoder(I) >> Word;
211   }
212 
213   unsigned NumWords;
214 
215 private:
216   std::vector<SPIRVWord> Words;
217 };
218 
219 using SPIRVConstant = SPIRVConstantBase<OpConstant>;
220 using SPIRVSpecConstant = SPIRVConstantBase<OpSpecConstant>;
221 
222 template <Op OC> class SPIRVConstantEmpty : public SPIRVValue {
223 public:
224   // Complete constructor
SPIRVConstantEmpty(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)225   SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
226       : SPIRVValue(M, 3, OC, TheType, TheId) {
227     validate();
228   }
229   // Incomplete constructor
SPIRVConstantEmpty()230   SPIRVConstantEmpty() : SPIRVValue(OC) {}
231 
232 protected:
validate()233   void validate() const override { SPIRVValue::validate(); }
234   _SPIRV_DEF_ENCDEC2(Type, Id)
235 };
236 
237 template <Op OC> class SPIRVConstantBool : public SPIRVConstantEmpty<OC> {
238 public:
239   // Complete constructor
SPIRVConstantBool(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)240   SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
241       : SPIRVConstantEmpty<OC>(M, TheType, TheId) {}
242   // Incomplete constructor
SPIRVConstantBool()243   SPIRVConstantBool() {}
244 
245 protected:
validate()246   void validate() const override {
247     SPIRVConstantEmpty<OC>::validate();
248     assert(this->Type->isTypeBool() && "Invalid type");
249   }
250 };
251 
252 typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
253 typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
254 typedef SPIRVConstantBool<OpSpecConstantTrue> SPIRVSpecConstantTrue;
255 typedef SPIRVConstantBool<OpSpecConstantFalse> SPIRVSpecConstantFalse;
256 
257 class SPIRVConstantNull : public SPIRVConstantEmpty<OpConstantNull> {
258 public:
259   // Complete constructor
SPIRVConstantNull(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)260   SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
261       : SPIRVConstantEmpty(M, TheType, TheId) {
262     validate();
263   }
264   // Incomplete constructor
SPIRVConstantNull()265   SPIRVConstantNull() {}
266 
267 protected:
validate()268   void validate() const override {
269     SPIRVConstantEmpty::validate();
270     assert((Type->isTypeComposite() || Type->isTypeOpaque() ||
271             Type->isTypeEvent() || Type->isTypePointer() ||
272             Type->isTypeReserveId() || Type->isTypeDeviceEvent() ||
273             (Type->isTypeSubgroupAvcINTEL() &&
274              !Type->isTypeSubgroupAvcMceINTEL())) &&
275            "Invalid type");
276   }
277 };
278 
279 class SPIRVUndef : public SPIRVConstantEmpty<OpUndef> {
280 public:
281   // Complete constructor
SPIRVUndef(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)282   SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
283       : SPIRVConstantEmpty(M, TheType, TheId) {
284     validate();
285   }
286   // Incomplete constructor
SPIRVUndef()287   SPIRVUndef() {}
288 
289 protected:
validate()290   void validate() const override { SPIRVConstantEmpty::validate(); }
291 };
292 
293 template <spv::Op OC> class SPIRVConstantCompositeBase : public SPIRVValue {
294 public:
295   // There are always 3 words in this instruction except constituents:
296   // 1) WordCount + OpCode
297   // 2) Result type
298   // 3) Result Id
299   constexpr static SPIRVWord FixedWC = 3;
300   using ContinuedInstType = typename InstToContinued<OC>::Type;
301   // Complete constructor for composite constant
SPIRVConstantCompositeBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,const std::vector<SPIRVValue * > TheElements)302   SPIRVConstantCompositeBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
303                              const std::vector<SPIRVValue *> TheElements)
304       : SPIRVValue(M, TheElements.size() + FixedWC, OC, TheType, TheId) {
305     Elements = getIds(TheElements);
306     validate();
307   }
308   // Incomplete constructor
SPIRVConstantCompositeBase()309   SPIRVConstantCompositeBase() : SPIRVValue(OC) {}
getElements()310   std::vector<SPIRVValue *> getElements() const { return getValues(Elements); }
311 
312   // TODO: Should we attach operands of continued instructions as well?
getNonLiteralOperands()313   std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
314     std::vector<SPIRVValue *> Elements = getElements();
315     return std::vector<SPIRVEntry *>(Elements.begin(), Elements.end());
316   }
317 
getContinuedInstructions()318   std::vector<ContinuedInstType> getContinuedInstructions() {
319     return ContinuedInstructions;
320   }
321 
addContinuedInstruction(ContinuedInstType Inst)322   void addContinuedInstruction(ContinuedInstType Inst) {
323     ContinuedInstructions.push_back(Inst);
324   }
325 
encodeChildren(spv_ostream & O)326   void encodeChildren(spv_ostream &O) const override {
327     O << SPIRVNL();
328     for (auto &I : ContinuedInstructions)
329       O << *I;
330   }
331 
332 protected:
validate()333   void validate() const override {
334     SPIRVValue::validate();
335     for (auto &I : Elements)
336       getValue(I)->validate();
337   }
338 
setWordCount(SPIRVWord WordCount)339   void setWordCount(SPIRVWord WordCount) override {
340     SPIRVEntry::setWordCount(WordCount);
341     Elements.resize(WordCount - FixedWC);
342   }
343 
encode(spv_ostream & O)344   void encode(spv_ostream &O) const override {
345     getEncoder(O) << Type << Id << Elements;
346   }
347 
decode(std::istream & I)348   void decode(std::istream &I) override {
349     SPIRVDecoder Decoder = getDecoder(I);
350     Decoder >> Type >> Id >> Elements;
351 
352     for (SPIRVEntry *E : Decoder.getContinuedInstructions(ContinuedOpCode)) {
353       addContinuedInstruction(static_cast<ContinuedInstType>(E));
354     }
355   }
356 
357   std::vector<SPIRVId> Elements;
358   std::vector<ContinuedInstType> ContinuedInstructions;
359   const spv::Op ContinuedOpCode = InstToContinued<OC>::OpCode;
360 };
361 
362 using SPIRVConstantComposite = SPIRVConstantCompositeBase<OpConstantComposite>;
363 using SPIRVSpecConstantComposite =
364     SPIRVConstantCompositeBase<OpSpecConstantComposite>;
365 
366 class SPIRVConstantSampler : public SPIRVValue {
367 public:
368   const static Op OC = OpConstantSampler;
369   const static SPIRVWord WC = 6;
370   // Complete constructor
SPIRVConstantSampler(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord TheAddrMode,SPIRVWord TheNormalized,SPIRVWord TheFilterMode)371   SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
372                        SPIRVWord TheAddrMode, SPIRVWord TheNormalized,
373                        SPIRVWord TheFilterMode)
374       : SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
375         Normalized(TheNormalized), FilterMode(TheFilterMode) {
376     validate();
377   }
378   // Incomplete constructor
SPIRVConstantSampler()379   SPIRVConstantSampler()
380       : SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), Normalized(SPIRVWORD_MAX),
381         FilterMode(SPIRVSFM_Invalid) {}
382 
getAddrMode()383   SPIRVWord getAddrMode() const { return AddrMode; }
384 
getFilterMode()385   SPIRVWord getFilterMode() const { return FilterMode; }
386 
getNormalized()387   SPIRVWord getNormalized() const { return Normalized; }
getRequiredCapability()388   SPIRVCapVec getRequiredCapability() const override {
389     return getVec(CapabilityLiteralSampler);
390   }
391 
392 protected:
393   SPIRVWord AddrMode;
394   SPIRVWord Normalized;
395   SPIRVWord FilterMode;
validate()396   void validate() const override {
397     SPIRVValue::validate();
398     assert(OpCode == OC);
399     assert(WordCount == WC);
400     assert(Type->isTypeSampler());
401   }
402   _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode)
403 };
404 
405 class SPIRVConstantPipeStorage : public SPIRVValue {
406 public:
407   const static Op OC = OpConstantPipeStorage;
408   const static SPIRVWord WC = 6;
409   // Complete constructor
SPIRVConstantPipeStorage(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord ThePacketSize,SPIRVWord ThePacketAlign,SPIRVWord TheCapacity)410   SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
411                            SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign,
412                            SPIRVWord TheCapacity)
413       : SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize),
414         PacketAlign(ThePacketAlign), Capacity(TheCapacity) {
415     validate();
416   }
417   // Incomplete constructor
SPIRVConstantPipeStorage()418   SPIRVConstantPipeStorage()
419       : SPIRVValue(OC), PacketSize(0), PacketAlign(0), Capacity(0) {}
420 
getPacketSize()421   SPIRVWord getPacketSize() const { return PacketSize; }
422 
getPacketAlign()423   SPIRVWord getPacketAlign() const { return PacketAlign; }
424 
getCapacity()425   SPIRVWord getCapacity() const { return Capacity; }
getRequiredCapability()426   SPIRVCapVec getRequiredCapability() const override {
427     return getVec(CapabilityPipes, CapabilityPipeStorage);
428   }
429 
430 protected:
431   SPIRVWord PacketSize;
432   SPIRVWord PacketAlign;
433   SPIRVWord Capacity;
validate()434   void validate() const override {
435     SPIRVValue::validate();
436     assert(OpCode == OC);
437     assert(WordCount == WC);
438     assert(Type->isTypePipeStorage());
439   }
440   _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity)
441 };
442 
443 class SPIRVForward : public SPIRVValue, public SPIRVComponentExecutionModes {
444 public:
445   const static Op OC = internal::OpForward;
446   // Complete constructor
SPIRVForward(SPIRVModule * TheModule,SPIRVType * TheTy,SPIRVId TheId)447   SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId)
448       : SPIRVValue(TheModule, 0, OC, TheId) {
449     if (TheTy)
450       setType(TheTy);
451   }
SPIRVForward()452   SPIRVForward() : SPIRVValue(OC) { assert(0 && "should never be called"); }
_SPIRV_DEF_ENCDEC1(Id)453   _SPIRV_DEF_ENCDEC1(Id)
454   friend class SPIRVFunction;
455 
456 protected:
457   void validate() const override {}
458 };
459 
460 } // namespace SPIRV
461 
462 #endif // SPIRV_LIBSPIRV_SPIRVVALUE_H
463