• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "opcode.h"
16 
17 #include <assert.h>
18 #include <string.h>
19 
20 #include <algorithm>
21 #include <cstdlib>
22 
23 #include "instruction.h"
24 #include "macro.h"
25 #include "spirv-tools/libspirv.h"
26 #include "spirv_constant.h"
27 #include "spirv_endian.h"
28 
29 namespace {
30 
31 // Descriptions of each opcode.  Each entry describes the format of the
32 // instruction that follows a particular opcode.
33 const spv_opcode_desc_t opcodeTableEntries_1_0[] = {
34 #include "core.insts-1.0.inc"
35 };
36 const spv_opcode_desc_t opcodeTableEntries_1_1[] = {
37 #include "core.insts-1.1.inc"
38 };
39 const spv_opcode_desc_t opcodeTableEntries_1_2[] = {
40 #include "core.insts-1.2.inc"
41 };
42 
43 // Represents a vendor tool entry in the SPIR-V XML Regsitry.
44 struct VendorTool {
45   uint32_t value;
46   const char* vendor;
47   const char* tool; // Might be empty string.
48   const char* vendor_tool; // Combiantion of vendor and tool.
49 };
50 
51 const VendorTool vendor_tools[] = {
52 #include "generators.inc"
53 };
54 
55 }  // anonymous namespace
56 
57 // TODO(dneto): Move this to another file.  It doesn't belong with opcode
58 // processing.
spvGeneratorStr(uint32_t generator)59 const char* spvGeneratorStr(uint32_t generator) {
60   auto where = std::find_if(
61       std::begin(vendor_tools), std::end(vendor_tools),
62       [generator](const VendorTool& vt) { return generator == vt.value; });
63   if (where != std::end(vendor_tools)) return where->vendor_tool;
64   return "Unknown";
65 }
66 
spvOpcodeMake(uint16_t wordCount,SpvOp opcode)67 uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
68   return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
69 }
70 
spvOpcodeSplit(const uint32_t word,uint16_t * pWordCount,uint16_t * pOpcode)71 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
72                     uint16_t* pOpcode) {
73   if (pWordCount) {
74     *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
75   }
76   if (pOpcode) {
77     *pOpcode = 0x0000ffff & word;
78   }
79 }
80 
spvOpcodeTableGet(spv_opcode_table * pInstTable,spv_target_env env)81 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable,
82                                spv_target_env env) {
83   if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
84 
85   static const spv_opcode_table_t table_1_0 = {
86       ARRAY_SIZE(opcodeTableEntries_1_0), opcodeTableEntries_1_0};
87   static const spv_opcode_table_t table_1_1 = {
88       ARRAY_SIZE(opcodeTableEntries_1_1), opcodeTableEntries_1_1};
89   static const spv_opcode_table_t table_1_2 = {
90       ARRAY_SIZE(opcodeTableEntries_1_2), opcodeTableEntries_1_2};
91 
92   switch (env) {
93     case SPV_ENV_UNIVERSAL_1_0:
94     case SPV_ENV_VULKAN_1_0:
95     case SPV_ENV_OPENCL_2_1:
96     case SPV_ENV_OPENGL_4_0:
97     case SPV_ENV_OPENGL_4_1:
98     case SPV_ENV_OPENGL_4_2:
99     case SPV_ENV_OPENGL_4_3:
100     case SPV_ENV_OPENGL_4_5:
101       *pInstTable = &table_1_0;
102       return SPV_SUCCESS;
103     case SPV_ENV_UNIVERSAL_1_1:
104       *pInstTable = &table_1_1;
105       return SPV_SUCCESS;
106     case SPV_ENV_UNIVERSAL_1_2:
107     case SPV_ENV_OPENCL_2_2:
108       *pInstTable = &table_1_2;
109       return SPV_SUCCESS;
110   }
111   assert(0 && "Unknown spv_target_env in spvOpcodeTableGet()");
112   return SPV_ERROR_INVALID_TABLE;
113 }
114 
spvOpcodeTableNameLookup(const spv_opcode_table table,const char * name,spv_opcode_desc * pEntry)115 spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
116                                       const char* name,
117                                       spv_opcode_desc* pEntry) {
118   if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
119   if (!table) return SPV_ERROR_INVALID_TABLE;
120 
121   // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
122   // preferable but the table requires sorting on the Opcode name, but it's
123   // static
124   // const initialized and matches the order of the spec.
125   const size_t nameLength = strlen(name);
126   for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
127     if (nameLength == strlen(table->entries[opcodeIndex].name) &&
128         !strncmp(name, table->entries[opcodeIndex].name, nameLength)) {
129       // NOTE: Found out Opcode!
130       *pEntry = &table->entries[opcodeIndex];
131       return SPV_SUCCESS;
132     }
133   }
134 
135   return SPV_ERROR_INVALID_LOOKUP;
136 }
137 
spvOpcodeTableValueLookup(const spv_opcode_table table,const SpvOp opcode,spv_opcode_desc * pEntry)138 spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
139                                        const SpvOp opcode,
140                                        spv_opcode_desc* pEntry) {
141   if (!table) return SPV_ERROR_INVALID_TABLE;
142   if (!pEntry) return SPV_ERROR_INVALID_POINTER;
143 
144   // TODO: As above this lookup is not optimal.
145   for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
146     if (opcode == table->entries[opcodeIndex].opcode) {
147       // NOTE: Found the Opcode!
148       *pEntry = &table->entries[opcodeIndex];
149       return SPV_SUCCESS;
150     }
151   }
152 
153   return SPV_ERROR_INVALID_LOOKUP;
154 }
155 
spvInstructionCopy(const uint32_t * words,const SpvOp opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)156 void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
157                         const uint16_t wordCount, const spv_endianness_t endian,
158                         spv_instruction_t* pInst) {
159   pInst->opcode = opcode;
160   pInst->words.resize(wordCount);
161   for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
162     pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
163     if (!wordIndex) {
164       uint16_t thisWordCount;
165       uint16_t thisOpcode;
166       spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
167       assert(opcode == static_cast<SpvOp>(thisOpcode) &&
168              wordCount == thisWordCount && "Endianness failed!");
169     }
170   }
171 }
172 
spvOpcodeString(const SpvOp opcode)173 const char* spvOpcodeString(const SpvOp opcode) {
174   // Use the latest SPIR-V version, which should be backward-compatible with all
175   // previous ones.
176   for (uint32_t i = 0; i < ARRAY_SIZE(opcodeTableEntries_1_2); ++i) {
177     if (opcodeTableEntries_1_2[i].opcode == opcode)
178       return opcodeTableEntries_1_2[i].name;
179   }
180   assert(0 && "Unreachable!");
181   return "unknown";
182 }
183 
spvOpcodeIsScalarType(const SpvOp opcode)184 int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
185   switch (opcode) {
186     case SpvOpTypeInt:
187     case SpvOpTypeFloat:
188     case SpvOpTypeBool:
189       return true;
190     default:
191       return false;
192   }
193 }
194 
spvOpcodeIsConstant(const SpvOp opcode)195 int32_t spvOpcodeIsConstant(const SpvOp opcode) {
196   switch (opcode) {
197     case SpvOpConstantTrue:
198     case SpvOpConstantFalse:
199     case SpvOpConstant:
200     case SpvOpConstantComposite:
201     case SpvOpConstantSampler:
202     case SpvOpConstantNull:
203     case SpvOpSpecConstantTrue:
204     case SpvOpSpecConstantFalse:
205     case SpvOpSpecConstant:
206     case SpvOpSpecConstantComposite:
207     case SpvOpSpecConstantOp:
208       return true;
209     default:
210       return false;
211   }
212 }
213 
spvOpcodeIsConstantOrUndef(const SpvOp opcode)214 bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) {
215   return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode);
216 }
217 
spvOpcodeIsScalarSpecConstant(const SpvOp opcode)218 bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) {
219   switch (opcode) {
220     case SpvOpSpecConstantTrue:
221     case SpvOpSpecConstantFalse:
222     case SpvOpSpecConstant:
223       return true;
224     default:
225       return false;
226   }
227 }
228 
spvOpcodeIsComposite(const SpvOp opcode)229 int32_t spvOpcodeIsComposite(const SpvOp opcode) {
230   switch (opcode) {
231     case SpvOpTypeVector:
232     case SpvOpTypeMatrix:
233     case SpvOpTypeArray:
234     case SpvOpTypeStruct:
235       return true;
236     default:
237       return false;
238   }
239 }
240 
spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode)241 bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode) {
242   switch (opcode) {
243     case SpvOpVariable:
244     case SpvOpAccessChain:
245     case SpvOpInBoundsAccessChain:
246     case SpvOpFunctionParameter:
247     case SpvOpImageTexelPointer:
248     case SpvOpCopyObject:
249     case SpvOpSelect:
250     case SpvOpPhi:
251     case SpvOpFunctionCall:
252     case SpvOpPtrAccessChain:
253     case SpvOpLoad:
254     case SpvOpConstantNull:
255       return true;
256     default:
257       return false;
258   }
259 }
260 
spvOpcodeReturnsLogicalPointer(const SpvOp opcode)261 int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) {
262   switch (opcode) {
263     case SpvOpVariable:
264     case SpvOpAccessChain:
265     case SpvOpInBoundsAccessChain:
266     case SpvOpFunctionParameter:
267     case SpvOpImageTexelPointer:
268     case SpvOpCopyObject:
269       return true;
270     default:
271       return false;
272   }
273 }
274 
spvOpcodeGeneratesType(SpvOp op)275 int32_t spvOpcodeGeneratesType(SpvOp op) {
276   switch (op) {
277     case SpvOpTypeVoid:
278     case SpvOpTypeBool:
279     case SpvOpTypeInt:
280     case SpvOpTypeFloat:
281     case SpvOpTypeVector:
282     case SpvOpTypeMatrix:
283     case SpvOpTypeImage:
284     case SpvOpTypeSampler:
285     case SpvOpTypeSampledImage:
286     case SpvOpTypeArray:
287     case SpvOpTypeRuntimeArray:
288     case SpvOpTypeStruct:
289     case SpvOpTypeOpaque:
290     case SpvOpTypePointer:
291     case SpvOpTypeFunction:
292     case SpvOpTypeEvent:
293     case SpvOpTypeDeviceEvent:
294     case SpvOpTypeReserveId:
295     case SpvOpTypeQueue:
296     case SpvOpTypePipe:
297     case SpvOpTypePipeStorage:
298     case SpvOpTypeNamedBarrier:
299       return true;
300     default:
301       // In particular, OpTypeForwardPointer does not generate a type,
302       // but declares a storage class for a pointer type generated
303       // by a different instruction.
304       break;
305   }
306   return 0;
307 }
308