1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 /*========================== begin_copyright_notice ============================
10 
11 This file is distributed under the University of Illinois Open Source License.
12 See LICENSE.TXT for details.
13 
14 ============================= end_copyright_notice ===========================*/
15 
16 /*========================== begin_copyright_notice ============================
17 
18 Copyright (C) 2014 Advanced Micro Devices, Inc. All rights reserved.
19 
20 Permission is hereby granted, free of charge, to any person obtaining a
21 copy of this software and associated documentation files (the "Software"),
22 to deal with the Software without restriction, including without limitation
23 the rights to use, copy, modify, merge, publish, distribute, sublicense,
24 and/or sell copies of the Software, and to permit persons to whom the
25 Software is furnished to do so, subject to the following conditions:
26 
27 Redistributions of source code must retain the above copyright notice,
28 this list of conditions and the following disclaimers.
29 Redistributions in binary form must reproduce the above copyright notice,
30 this list of conditions and the following disclaimers in the documentation
31 and/or other materials provided with the distribution.
32 Neither the names of Advanced Micro Devices, Inc., nor the names of its
33 contributors may be used to endorse or promote products derived from this
34 Software without specific prior written permission.
35 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
41 THE SOFTWARE.
42 
43 ============================= end_copyright_notice ===========================*/
44 
45 // This file defines the values defined in SPIR-V spec with op codes.
46 // The name of the SPIR-V values follow the op code name in the spec.
47 // This is for readability and ease of using macro to handle types.
48 
49 #ifndef SPIRVVALUE_HPP_
50 #define SPIRVVALUE_HPP_
51 
52 #include "SPIRVEntry.h"
53 #include "SPIRVType.h"
54 #include "SPIRVDecorate.h"
55 #include "Probe/Assertion.h"
56 
57 #include <iostream>
58 #include <map>
59 #include <memory>
60 
61 namespace igc_spv{
62 
63 class SPIRVValue: public SPIRVEntry {
64 public:
65   // Complete constructor for value with id and type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType,SPIRVId TheId)66   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
67       SPIRVType *TheType, SPIRVId TheId)
68     :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
69     validate();
70   }
71   // Complete constructor for value with type but without id
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType)72   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
73       SPIRVType *TheType)
74     :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
75     setHasNoId();
76     validate();
77   }
78   // Complete constructor for value with id but without type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVId TheId)79   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
80       SPIRVId TheId)
81     :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
82     setHasNoType();
83     validate();
84   }
85   // Complete constructor for value without id and type
SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode)86   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
87     :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
88     setHasNoId();
89     setHasNoType();
90     validate();
91   }
92   // Incomplete constructor
SPIRVValue(Op TheOpCode)93   SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {}
94 
hasType()95   bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);}
getType()96   SPIRVType *getType()const {
97     IGC_ASSERT_MESSAGE(hasType(), "value has no type");
98     return Type;
99   }
100   bool isVolatile()const;
101   bool hasAlignment(SPIRVWord *Result=0)const;
102   bool hasNoSignedWrap() const;
103   bool hasNoUnsignedWrap() const;
104 
105   void setAlignment(SPIRVWord);
106   void setVolatile(bool IsVolatile);
107   void setNoSignedWrap(bool HasNoSignedWrap);
108   void setNoUnsignedWrap(bool HasNoUnsignedWrap);
109 
validate()110   void validate()const {
111     SPIRVEntry::validate();
112     IGC_ASSERT_MESSAGE((!hasType() || Type), "Invalid type");
113   }
114 
setType(SPIRVType * Ty)115   void setType(SPIRVType *Ty) {
116     Type = Ty;
117     IGC_ASSERT(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction);
118     if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction))
119       setHasType();
120     else
121       setHasNoType();
122   }
123 
getRequiredCapability()124   CapVec getRequiredCapability() const {
125     CapVec CV;
126     if (!hasType())
127       return CV;
128     if (Type->isTypeFloat(16))
129        CV.push_back(SPIRVCapabilityKind::CapabilityFloat16);
130     else if (Type->isTypeFloat(64))
131        CV.push_back(SPIRVCapabilityKind::CapabilityFloat64);
132     else if (Type->isTypeInt(16))
133        CV.push_back(SPIRVCapabilityKind::CapabilityInt16);
134     else if (Type->isTypeInt(64))
135        CV.push_back(SPIRVCapabilityKind::CapabilityInt64);
136     return CV;
137   }
138 
139 protected:
setHasNoType()140   void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;}
setHasType()141   void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;}
142 
143   SPIRVType *Type;                 // Value Type
144 };
145 
146 template<Op OC>
147 class SPIRVConstantBase: public SPIRVValue {
148 public:
149   // Complete constructor for integer constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,uint64_t TheValue)150   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
151       uint64_t TheValue)
152     :SPIRVValue(M, 0, OC, TheType, TheId){
153     Union.UInt64Val = TheValue;
154     recalculateWordCount();
155     validate();
156   }
157   // Complete constructor for float constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,float TheValue)158   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue)
159     :SPIRVValue(M, 0, OC, TheType, TheId){
160     Union.FloatVal = TheValue;
161     recalculateWordCount();
162     validate();
163   }
164   // Complete constructor for double constant
SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,double TheValue)165   SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue)
166     :SPIRVValue(M, 0, OC, TheType, TheId){
167     Union.DoubleVal = TheValue;
168     recalculateWordCount();
169     validate();
170   }
171   // Incomplete constructor
SPIRVConstantBase()172   SPIRVConstantBase():SPIRVValue(OC), NumWords(0){}
getZExtIntValue()173   uint64_t getZExtIntValue() const { return Union.UInt64Val;}
getFloatValue()174   float getFloatValue() const { return Union.FloatVal;}
getDoubleValue()175   double getDoubleValue() const { return Union.DoubleVal;}
isConstant()176   bool isConstant() { return true; }
177 protected:
recalculateWordCount()178   void recalculateWordCount() {
179     NumWords = (Type->getBitWidth() + 31) / 32;
180     WordCount = 3 + NumWords;
181   }
validate()182   void validate() const {
183     SPIRVValue::validate();
184     IGC_ASSERT_EXIT_MESSAGE(1 <= NumWords, "Invalid constant size");
185     IGC_ASSERT_EXIT_MESSAGE(NumWords <= 32, "Invalid constant size");
186   }
setWordCount(SPIRVWord WordCount)187   void setWordCount(SPIRVWord WordCount) {
188     SPIRVValue::setWordCount(WordCount);
189     NumWords = WordCount - 3;
190   }
decode(std::istream & I)191   void decode(std::istream &I) {
192     getDecoder(I) >> Type >> Id;
193     validate();
194     for (unsigned i = 0; i < NumWords; ++i)
195       getDecoder(I) >> Union.Words[i];
196   }
197 
198   unsigned NumWords;
199   union UnionType{
200     uint64_t UInt64Val;
201     float FloatVal;
202     double DoubleVal;
203     SPIRVWord Words[32];
UnionType()204     UnionType() {
205       UInt64Val = 0;
206     }
207   } Union;
208 };
209 
210 typedef SPIRVConstantBase<OpConstant> SPIRVConstant;
211 typedef SPIRVConstantBase<OpSpecConstant> SPIRVSpecConstant;
212 
213 template<Op OC>
214 class SPIRVConstantEmpty: public SPIRVValue {
215 public:
216   // Complete constructor
SPIRVConstantEmpty(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)217   SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
218     :SPIRVValue(M, 3, OC, TheType, TheId){
219     validate();
220   }
221   // Incomplete constructor
SPIRVConstantEmpty()222   SPIRVConstantEmpty():SPIRVValue(OC){}
223 protected:
validate()224   void validate() const override {
225     SPIRVValue::validate();
226   }
227   _SPIRV_DEF_DEC2(Type, Id)
228 };
229 
230 template<Op OC>
231 class SPIRVConstantBool: public SPIRVConstantEmpty<OC> {
232 public:
233   // Complete constructor
SPIRVConstantBool(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)234   SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
235     :SPIRVConstantEmpty<OC>(M, TheType, TheId){}
236   // Incomplete constructor
SPIRVConstantBool()237   SPIRVConstantBool(){}
238 protected:
validate()239   void validate() const {
240     SPIRVConstantEmpty<OC>::validate();
241     IGC_ASSERT_MESSAGE(this->Type->isTypeBool(), "Invalid type");
242   }
243 };
244 
245 typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
246 typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
247 
248 typedef SPIRVConstantBool<OpSpecConstantTrue> SPIRVSpecConstantTrue;
249 typedef SPIRVConstantBool<OpSpecConstantFalse> SPIRVSpecConstantFalse;
250 
251 class SPIRVConstantNull : public SPIRVConstantEmpty<OpConstantNull>
252 {
253 public:
254     // Complete constructor
SPIRVConstantNull(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)255     SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
256         : SPIRVConstantEmpty(M, TheType, TheId) {
257         validate();
258     }
259     // Incomplete constructor
SPIRVConstantNull()260     SPIRVConstantNull() {}
261 protected:
validate()262     void validate() const override {
263         SPIRVConstantEmpty::validate();
264         IGC_ASSERT_MESSAGE((Type->isTypeInt() || Type->isTypeBool() || Type->isTypeFloat() || Type->isTypeComposite() || Type->isTypeOpaque() || Type->isTypeEvent() || Type->isTypePointer() || Type->isTypeReserveId() || Type->isTypeDeviceEvent() || (Type->isTypeSubgroupAvcINTEL())), "Invalid type");
265     }
266 };
267 
268 class SPIRVUndef : public SPIRVConstantEmpty<OpUndef>
269 {
270 public:
271     // Incomplete constructor
SPIRVUndef()272     SPIRVUndef() {}
273 protected:
validate()274     void validate() const
275     {
276         SPIRVConstantEmpty::validate();
277     }
278 };
279 
280 template<Op OC>
281 class SPIRVConstantCompositeBase: public SPIRVValue {
282 public:
283     // There are always 3 words in this instruction except constituents:
284     // 1) WordCount + OpCode
285     // 2) Result type
286     // 3) Result Id
287     constexpr static SPIRVWord FixedWC = 3;
288     using ContinuedInstType = typename InstToContinued<OC>::Type;
289   // Complete constructor for composite constant
SPIRVConstantCompositeBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,const std::vector<SPIRVValue * > TheElements)290   SPIRVConstantCompositeBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
291       const std::vector<SPIRVValue *> TheElements)
292     :SPIRVValue(M, TheElements.size()+ FixedWC, OC, TheType, TheId){
293     Elements = getIds(TheElements);
294     validate();
295   }
296   // Incomplete constructor
SPIRVConstantCompositeBase()297   SPIRVConstantCompositeBase():SPIRVValue(OC){}
getElements()298   std::vector<SPIRVValue*> getElements()const {
299     return getValues(Elements);
300   }
301 
getContinuedInstructions()302   std::vector<ContinuedInstType> getContinuedInstructions() {
303       return ContinuedInstructions;
304   }
305 
addContinuedInstruction(ContinuedInstType Inst)306   void addContinuedInstruction(ContinuedInstType Inst) {
307       ContinuedInstructions.push_back(Inst);
308   }
309 
310 protected:
validate()311   void validate() const override {
312     SPIRVValue::validate();
313     for (auto &I:Elements)
314       getValue(I)->validate();
315   }
setWordCount(SPIRVWord WordCount)316   void setWordCount(SPIRVWord WordCount) override
317   {
318     Elements.resize(WordCount - FixedWC);
319   }
320 
decode(std::istream & I)321   void decode(std::istream& I) override
322   {
323       SPIRVDecoder Decoder = getDecoder(I);
324       Decoder >> Type >> Id >> Elements;
325 
326       for (SPIRVEntry* E : Decoder.getContinuedInstructions(ContinuedOpCode))
327       {
328           addContinuedInstruction(static_cast<ContinuedInstType>(E));
329       }
330   }
331 
332   std::vector<SPIRVId> Elements;
333   std::vector<ContinuedInstType> ContinuedInstructions;
334   const igc_spv::Op ContinuedOpCode = InstToContinued<OC>::OpCode;
335 };
336 
337 typedef SPIRVConstantCompositeBase<OpConstantComposite> SPIRVConstantComposite;
338 typedef SPIRVConstantCompositeBase<OpSpecConstantComposite> SPIRVSpecConstantComposite;
339 
340 class SPIRVConstantSampler: public SPIRVValue {
341 public:
342   const static Op OC = OpConstantSampler;
343   const static SPIRVWord WC = 6;
344   // Complete constructor
SPIRVConstantSampler(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord TheAddrMode,SPIRVWord TheNormalized,SPIRVWord TheFilterMode)345   SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
346       SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode)
347     :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
348      Normalized(TheNormalized), FilterMode(TheFilterMode){
349     validate();
350   }
351   // Incomplete constructor
SPIRVConstantSampler()352   SPIRVConstantSampler() :SPIRVValue(OC), AddrMode(SPIRVSamplerAddressingModeKind::SamplerAddressingModeNone),
353      Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSamplerFilterModeKind::SamplerFilterModeNearest){}
354 
getAddrMode()355   SPIRVWord getAddrMode() const {
356     return AddrMode;
357   }
358 
getFilterMode()359   SPIRVWord getFilterMode() const {
360     return FilterMode;
361   }
362 
getNormalized()363   SPIRVWord getNormalized() const {
364     return Normalized;
365   }
getRequiredCapability()366   CapVec getRequiredCapability() const {
367      return getVec(SPIRVCapabilityKind::CapabilityLiteralSampler);
368   }
369 protected:
370   SPIRVWord AddrMode;
371   SPIRVWord Normalized;
372   SPIRVWord FilterMode;
validate()373   void validate() const {
374     SPIRVValue::validate();
375     IGC_ASSERT(OpCode == OC);
376     IGC_ASSERT(WordCount == WC);
377     IGC_ASSERT(Type->isTypeSampler());
378   }
379   _SPIRV_DEF_DEC5(Type, Id, AddrMode, Normalized, FilterMode)
380 };
381 
382 class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes {
383 public:
384   const static Op OC = OpForward;
385   // Complete constructor
SPIRVForward(SPIRVModule * TheModule,SPIRVType * TheTy,SPIRVId TheId)386   SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId):
387     SPIRVValue(TheModule, 0, OC, TheId){
388     if (TheTy)
389       setType(TheTy);
390   }
SPIRVForward()391   SPIRVForward():SPIRVValue(OC) {
392     IGC_ASSERT_EXIT_MESSAGE(0, "should never be called");
393   }
_SPIRV_DEF_DEC1(Id)394   _SPIRV_DEF_DEC1(Id)
395   friend class SPIRVFunction;
396 protected:
397   void validate() const {}
398 };
399 
400 class SPIRVConstantPipeStorage : public SPIRVValue
401 {
402 public:
403     static const Op OC = OpConstantPipeStorage;
SPIRVConstantPipeStorage()404     SPIRVConstantPipeStorage() : SPIRVValue(OC) {}
GetPacketSize()405     uint32_t GetPacketSize() { return PacketSize; }
GetPacketAlignment()406     uint32_t GetPacketAlignment() { return PacketAlignment; }
GetCapacity()407     uint32_t GetCapacity() { return Capacity; }
408 private:
409     _SPIRV_DEF_DEC5(Type, Id, PacketSize, PacketAlignment, Capacity)
410     uint32_t PacketSize;
411     uint32_t PacketAlignment;
412     uint32_t Capacity;
413 };
414 
415 }
416 
417 
418 #endif /* SPIRVVALUE_HPP_ */
419