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