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 SPIRVVALUE_HPP_
44#define SPIRVVALUE_HPP_
45
46#include "SPIRVEntry.h"
47#include "SPIRVType.h"
48#include "SPIRVDecorate.h"
49
50#include <iostream>
51#include <map>
52#include <memory>
53
54namespace SPIRV{
55
56class SPIRVValue: public SPIRVEntry {
57public:
58  // Complete constructor for value with id and type
59  SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
60      SPIRVType *TheType, SPIRVId TheId)
61    :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
62    validate();
63  }
64  // Complete constructor for value with type but without id
65  SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
66      SPIRVType *TheType)
67    :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
68    setHasNoId();
69    validate();
70  }
71  // Complete constructor for value with id but without type
72  SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
73      SPIRVId TheId)
74    :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
75    setHasNoType();
76    validate();
77  }
78  // Complete constructor for value without id and type
79  SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
80    :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
81    setHasNoId();
82    setHasNoType();
83    validate();
84  }
85  // Incomplete constructor
86  SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {}
87
88  bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);}
89  SPIRVType *getType()const {
90    assert(hasType() && "value has no type");
91    return Type;
92  }
93  bool isVolatile()const;
94  bool hasAlignment(SPIRVWord *Result=0)const;
95
96  void setAlignment(SPIRVWord);
97  void setVolatile(bool IsVolatile);
98
99  void validate()const {
100    SPIRVEntry::validate();
101    assert((!hasType() || Type) && "Invalid type");
102  }
103
104  void setType(SPIRVType *Ty) {
105    Type = Ty;
106    assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction);
107    if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction))
108      setHasType();
109    else
110      setHasNoType();
111  }
112
113  SPIRVCapVec getRequiredCapability() const {
114    SPIRVCapVec CV;
115    if (!hasType())
116      return CV;
117    return Type->getRequiredCapability();
118  }
119
120protected:
121  void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;}
122  void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;}
123
124  SPIRVType *Type;                 // Value Type
125};
126
127class SPIRVConstant: public SPIRVValue {
128public:
129  // Complete constructor for integer constant
130  SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
131      uint64_t TheValue)
132    :SPIRVValue(M, 0, OpConstant, TheType, TheId){
133    Union.UInt64Val = TheValue;
134    recalculateWordCount();
135    validate();
136  }
137  // Complete constructor for float constant
138  SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue)
139    :SPIRVValue(M, 0, OpConstant, TheType, TheId){
140    Union.FloatVal = TheValue;
141    recalculateWordCount();
142    validate();
143  }
144  // Complete constructor for double constant
145  SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue)
146    :SPIRVValue(M, 0, OpConstant, TheType, TheId){
147    Union.DoubleVal = TheValue;
148    recalculateWordCount();
149    validate();
150  }
151  // Incomplete constructor
152  SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){}
153  uint64_t getZExtIntValue() const { return Union.UInt64Val;}
154  float getFloatValue() const { return Union.FloatVal;}
155  double getDoubleValue() const { return Union.DoubleVal;}
156protected:
157  void recalculateWordCount() {
158    NumWords = Type->getBitWidth()/32;
159    if (NumWords < 1)
160      NumWords = 1;
161    WordCount = 3 + NumWords;
162  }
163  void validate() const {
164    SPIRVValue::validate();
165    assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size");
166  }
167  void encode(spv_ostream &O) const {
168    getEncoder(O) << Type << Id;
169    for (unsigned i = 0; i < NumWords; ++i)
170      getEncoder(O) << Union.Words[i];
171  }
172  void setWordCount(SPIRVWord WordCount) {
173    SPIRVValue::setWordCount(WordCount);
174    NumWords = WordCount - 3;
175  }
176  void decode(std::istream &I) {
177    getDecoder(I) >> Type >> Id;
178    for (unsigned i = 0; i < NumWords; ++i)
179      getDecoder(I) >> Union.Words[i];
180  }
181
182  unsigned NumWords;
183  union UnionType{
184    uint64_t UInt64Val;
185    float FloatVal;
186    double DoubleVal;
187    SPIRVWord Words[2];
188    UnionType() {
189      UInt64Val = 0;
190    }
191  } Union;
192};
193
194template<Op OC>
195class SPIRVConstantEmpty: public SPIRVValue {
196public:
197  // Complete constructor
198  SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
199    :SPIRVValue(M, 3, OC, TheType, TheId){
200    validate();
201  }
202  // Incomplete constructor
203  SPIRVConstantEmpty():SPIRVValue(OC){}
204protected:
205  void validate() const {
206    SPIRVValue::validate();
207  }
208  _SPIRV_DEF_ENCDEC2(Type, Id)
209};
210
211template<Op OC>
212class SPIRVConstantBool: public SPIRVConstantEmpty<OC> {
213public:
214  // Complete constructor
215  SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
216    :SPIRVConstantEmpty<OC>(M, TheType, TheId){}
217  // Incomplete constructor
218  SPIRVConstantBool(){}
219protected:
220  void validate() const {
221    SPIRVConstantEmpty<OC>::validate();
222    assert(this->Type->isTypeBool() && "Invalid type");
223  }
224};
225
226typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
227typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
228
229class SPIRVConstantNull:
230    public SPIRVConstantEmpty<OpConstantNull> {
231public:
232  // Complete constructor
233  SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
234    :SPIRVConstantEmpty(M, TheType, TheId){
235    validate();
236  }
237  // Incomplete constructor
238  SPIRVConstantNull(){}
239protected:
240  void validate() const {
241    SPIRVConstantEmpty::validate();
242    assert((Type->isTypeComposite() ||
243            Type->isTypeOpaque() ||
244            Type->isTypeEvent() ||
245            Type->isTypePointer() ||
246            Type->isTypeReserveId() ||
247            Type->isTypeDeviceEvent()) &&
248            "Invalid type");
249  }
250};
251
252class SPIRVUndef:
253    public SPIRVConstantEmpty<OpUndef> {
254public:
255  // Complete constructor
256  SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
257    :SPIRVConstantEmpty(M, TheType, TheId){
258    validate();
259  }
260  // Incomplete constructor
261  SPIRVUndef(){}
262protected:
263  void validate() const {
264    SPIRVConstantEmpty::validate();
265  }
266};
267
268class SPIRVConstantComposite: public SPIRVValue {
269public:
270  // Complete constructor for composite constant
271  SPIRVConstantComposite(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
272      const std::vector<SPIRVValue *> TheElements)
273    :SPIRVValue(M, TheElements.size()+3, OpConstantComposite, TheType,
274        TheId){
275    Elements = getIds(TheElements);
276    validate();
277  }
278  // Incomplete constructor
279  SPIRVConstantComposite():SPIRVValue(OpConstantComposite){}
280  std::vector<SPIRVValue*> getElements()const {
281    return getValues(Elements);
282  }
283  std::vector<SPIRVEntry*> getNonLiteralOperands() const {
284    std::vector<SPIRVValue*> Elements = getElements();
285    return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end());
286  }
287protected:
288  void validate() const {
289    SPIRVValue::validate();
290    for (auto &I:Elements)
291      getValue(I)->validate();
292  }
293  void setWordCount(SPIRVWord WordCount) {
294    Elements.resize(WordCount - 3);
295  }
296  _SPIRV_DEF_ENCDEC3(Type, Id, Elements)
297
298  std::vector<SPIRVId> Elements;
299};
300
301class SPIRVConstantSampler: public SPIRVValue {
302public:
303  const static Op OC = OpConstantSampler;
304  const static SPIRVWord WC = 6;
305  // Complete constructor
306  SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
307      SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode)
308    :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
309     Normalized(TheNormalized), FilterMode(TheFilterMode){
310    validate();
311  }
312  // Incomplete constructor
313  SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid),
314      Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){}
315
316  SPIRVWord getAddrMode() const {
317    return AddrMode;
318  }
319
320  SPIRVWord getFilterMode() const {
321    return FilterMode;
322  }
323
324  SPIRVWord getNormalized() const {
325    return Normalized;
326  }
327  SPIRVCapVec getRequiredCapability() const {
328    return getVec(CapabilityLiteralSampler);
329  }
330protected:
331  SPIRVWord AddrMode;
332  SPIRVWord Normalized;
333  SPIRVWord FilterMode;
334  void validate() const {
335    SPIRVValue::validate();
336    assert(OpCode == OC);
337    assert(WordCount == WC);
338    assert(Type->isTypeSampler());
339  }
340  _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode)
341};
342
343class SPIRVConstantPipeStorage : public SPIRVValue {
344public:
345  const static Op OC = OpConstantPipeStorage;
346  const static SPIRVWord WC = 6;
347  // Complete constructor
348  SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
349    SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, SPIRVWord TheCapacity)
350    :SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize),
351    PacketAlign(ThePacketAlign), Capacity(TheCapacity){
352    validate();
353  }
354  // Incomplete constructor
355  SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0),
356    PacketAlign(0), Capacity(0){}
357
358  SPIRVWord getPacketSize() const {
359    return PacketSize;
360  }
361
362  SPIRVWord getPacketAlign() const {
363    return PacketAlign;
364  }
365
366  SPIRVWord getCapacity() const {
367    return Capacity;
368  }
369  SPIRVCapVec getRequiredCapability() const {
370    return getVec(CapabilityPipes, CapabilityPipeStorage);
371  }
372protected:
373  SPIRVWord PacketSize;
374  SPIRVWord PacketAlign;
375  SPIRVWord Capacity;
376  void validate() const {
377    SPIRVValue::validate();
378    assert(OpCode == OC);
379    assert(WordCount == WC);
380    assert(Type->isTypePipeStorage());
381  }
382  _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity)
383};
384
385class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes {
386public:
387  const static Op OC = OpForward;
388  // Complete constructor
389  SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId):
390    SPIRVValue(TheModule, 0, OC, TheId){
391    if (TheTy)
392      setType(TheTy);
393  }
394  SPIRVForward():SPIRVValue(OC) {
395    assert(0 && "should never be called");
396  }
397  _SPIRV_DEF_ENCDEC1(Id)
398  friend class SPIRVFunction;
399protected:
400  void validate() const {}
401};
402
403}
404
405
406#endif /* SPIRVVALUE_HPP_ */
407