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