1 //===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - 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 implements SPIR-V instructions.
37 ///
38 //===----------------------------------------------------------------------===//
39 
40 #include "SPIRVInstruction.h"
41 #include "SPIRVBasicBlock.h"
42 #include "SPIRVFunction.h"
43 
44 #include <unordered_set>
45 
46 namespace SPIRV {
47 
48 // Complete constructor for instruction with type and id
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVType * TheType,SPIRVId TheId,SPIRVBasicBlock * TheBB)49 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
50                                    SPIRVType *TheType, SPIRVId TheId,
51                                    SPIRVBasicBlock *TheBB)
52     : SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId),
53       BB(TheBB), DebugScope(nullptr) {
54   SPIRVInstruction::validate();
55 }
56 
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVType * TheType,SPIRVId TheId,SPIRVBasicBlock * TheBB,SPIRVModule * TheBM)57 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
58                                    SPIRVType *TheType, SPIRVId TheId,
59                                    SPIRVBasicBlock *TheBB, SPIRVModule *TheBM)
60     : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB),
61       DebugScope(nullptr) {
62   SPIRVInstruction::validate();
63 }
64 
65 // Complete constructor for instruction with id but no type
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVId TheId,SPIRVBasicBlock * TheBB)66 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
67                                    SPIRVId TheId, SPIRVBasicBlock *TheBB)
68     : SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB),
69       DebugScope(nullptr) {
70   SPIRVInstruction::validate();
71 }
72 // Complete constructor for instruction without type and id
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVBasicBlock * TheBB)73 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
74                                    SPIRVBasicBlock *TheBB)
75     : SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB),
76       DebugScope(nullptr) {
77   SPIRVInstruction::validate();
78 }
79 // Complete constructor for instruction with type but no id
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVType * TheType,SPIRVBasicBlock * TheBB)80 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
81                                    SPIRVType *TheType, SPIRVBasicBlock *TheBB)
82     : SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB),
83       DebugScope(nullptr) {
84   SPIRVInstruction::validate();
85 }
86 
87 // Special constructor for debug instruction
SPIRVInstruction(unsigned TheWordCount,Op TheOC,SPIRVType * TheType,SPIRVId TheId,SPIRVModule * TheBM,SPIRVBasicBlock * TheBB)88 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
89                                    SPIRVType *TheType, SPIRVId TheId,
90                                    SPIRVModule *TheBM, SPIRVBasicBlock *TheBB)
91     : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB),
92       DebugScope(nullptr) {
93   SPIRVInstruction::validate();
94 }
95 
setParent(SPIRVBasicBlock * TheBB)96 void SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) {
97   assert(TheBB && "Invalid BB");
98   if (BB == TheBB)
99     return;
100   assert(BB == NULL && "BB cannot change parent");
101   BB = TheBB;
102 }
103 
setScope(SPIRVEntry * Scope)104 void SPIRVInstruction::setScope(SPIRVEntry *Scope) {
105   assert(Scope && Scope->getOpCode() == OpLabel && "Invalid scope");
106   setParent(static_cast<SPIRVBasicBlock *>(Scope));
107 }
108 
SPIRVFunctionCall(SPIRVId TheId,SPIRVFunction * TheFunction,const std::vector<SPIRVWord> & TheArgs,SPIRVBasicBlock * BB)109 SPIRVFunctionCall::SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction,
110                                      const std::vector<SPIRVWord> &TheArgs,
111                                      SPIRVBasicBlock *BB)
112     : SPIRVFunctionCallGeneric(TheFunction->getFunctionType()->getReturnType(),
113                                TheId, TheArgs, BB),
114       FunctionId(TheFunction->getId()) {
115   validate();
116 }
117 
validate() const118 void SPIRVFunctionCall::validate() const {
119   SPIRVFunctionCallGeneric::validate();
120 }
121 
SPIRVFunctionPointerCallINTEL(SPIRVId TheId,SPIRVValue * TheCalledValue,SPIRVType * TheReturnType,const std::vector<SPIRVWord> & TheArgs,SPIRVBasicBlock * BB)122 SPIRVFunctionPointerCallINTEL::SPIRVFunctionPointerCallINTEL(
123     SPIRVId TheId, SPIRVValue *TheCalledValue, SPIRVType *TheReturnType,
124     const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB)
125     : SPIRVFunctionCallGeneric(TheReturnType, TheId, TheArgs, BB),
126       CalledValueId(TheCalledValue->getId()) {
127   validate();
128 }
129 
validate() const130 void SPIRVFunctionPointerCallINTEL::validate() const {
131   SPIRVFunctionCallGeneric::validate();
132 }
133 
134 // ToDo: Each instruction should implement this function
getOperands()135 std::vector<SPIRVValue *> SPIRVInstruction::getOperands() {
136   std::vector<SPIRVValue *> Empty;
137   assert(0 && "not supported");
138   return Empty;
139 }
140 
141 std::vector<SPIRVType *>
getOperandTypes(const std::vector<SPIRVValue * > & Ops)142 SPIRVInstruction::getOperandTypes(const std::vector<SPIRVValue *> &Ops) {
143   std::vector<SPIRVType *> Tys;
144   for (auto &I : Ops) {
145     SPIRVType *Ty = nullptr;
146     if (I->getOpCode() == OpFunction)
147       Ty = reinterpret_cast<SPIRVFunction *>(I)->getFunctionType();
148     else
149       Ty = I->getType();
150 
151     Tys.push_back(Ty);
152   }
153   return Tys;
154 }
155 
getOperandTypes()156 std::vector<SPIRVType *> SPIRVInstruction::getOperandTypes() {
157   return getOperandTypes(getOperands());
158 }
159 
isSpecConstantOpAllowedOp(Op OC)160 bool isSpecConstantOpAllowedOp(Op OC) {
161   static SPIRVWord Table[] = {
162       OpSConvert,
163       OpFConvert,
164       OpConvertFToS,
165       OpConvertSToF,
166       OpConvertFToU,
167       OpConvertUToF,
168       OpUConvert,
169       OpConvertPtrToU,
170       OpConvertUToPtr,
171       OpGenericCastToPtr,
172       OpPtrCastToGeneric,
173       OpCrossWorkgroupCastToPtrINTEL,
174       OpPtrCastToCrossWorkgroupINTEL,
175       OpBitcast,
176       OpQuantizeToF16,
177       OpSNegate,
178       OpNot,
179       OpIAdd,
180       OpISub,
181       OpIMul,
182       OpUDiv,
183       OpSDiv,
184       OpUMod,
185       OpSRem,
186       OpSMod,
187       OpShiftRightLogical,
188       OpShiftRightArithmetic,
189       OpShiftLeftLogical,
190       OpBitwiseOr,
191       OpBitwiseXor,
192       OpBitwiseAnd,
193       OpFNegate,
194       OpFAdd,
195       OpFSub,
196       OpFMul,
197       OpFDiv,
198       OpFRem,
199       OpFMod,
200       OpVectorShuffle,
201       OpCompositeExtract,
202       OpCompositeInsert,
203       OpLogicalOr,
204       OpLogicalAnd,
205       OpLogicalNot,
206       OpLogicalEqual,
207       OpLogicalNotEqual,
208       OpSelect,
209       OpIEqual,
210       OpINotEqual,
211       OpULessThan,
212       OpSLessThan,
213       OpUGreaterThan,
214       OpSGreaterThan,
215       OpULessThanEqual,
216       OpSLessThanEqual,
217       OpUGreaterThanEqual,
218       OpSGreaterThanEqual,
219       OpAccessChain,
220       OpInBoundsAccessChain,
221       OpPtrAccessChain,
222       OpInBoundsPtrAccessChain,
223   };
224   static std::unordered_set<SPIRVWord> Allow(std::begin(Table),
225                                              std::end(Table));
226   return Allow.count(OC);
227 }
228 
createSpecConstantOpInst(SPIRVInstruction * Inst)229 SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst) {
230   auto OC = Inst->getOpCode();
231   assert(isSpecConstantOpAllowedOp(OC) &&
232          "Op code not allowed for OpSpecConstantOp");
233   auto Ops = Inst->getIds(Inst->getOperands());
234   Ops.insert(Ops.begin(), OC);
235   return static_cast<SPIRVSpecConstantOp *>(SPIRVSpecConstantOp::create(
236       OpSpecConstantOp, Inst->getType(), Inst->getId(), Ops, nullptr,
237       Inst->getModule()));
238 }
239 
createInstFromSpecConstantOp(SPIRVSpecConstantOp * Inst)240 SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) {
241   assert(Inst->getOpCode() == OpSpecConstantOp && "Not OpSpecConstantOp");
242   auto Ops = Inst->getOpWords();
243   auto OC = static_cast<Op>(Ops[0]);
244   assert(isSpecConstantOpAllowedOp(OC) &&
245          "Op code not allowed for OpSpecConstantOp");
246   Ops.erase(Ops.begin(), Ops.begin() + 1);
247   return SPIRVInstTemplateBase::create(OC, Inst->getType(), Inst->getId(), Ops,
248                                        nullptr, Inst->getModule());
249 }
250 
251 } // namespace SPIRV
252