blob: 7e459c6117e251bbf1c11f5d49d7f41a8393c08f [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01002//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010027#include "opcode.h"
28
29#include <assert.h>
30#include <string.h>
31
Lei Zhang972788b2015-11-12 13:48:30 -050032#include <cstdlib>
33
Lei Zhang923f6c12015-11-11 12:45:23 -050034#include "instruction.h"
David Neto5a703352016-02-17 14:44:00 -050035#include "spirv-tools/libspirv.h"
Lei Zhangaa056cd2015-11-11 14:24:04 -050036#include "spirv_constant.h"
David Neto4c215712015-12-22 15:08:41 -050037#include "spirv_endian.h"
Lei Zhang923f6c12015-11-11 12:45:23 -050038
David Neto78c3b432015-08-27 13:03:52 -040039namespace {
40
41// Descriptions of each opcode. Each entry describes the format of the
42// instruction that follows a particular opcode.
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -040043const spv_opcode_desc_t opcodeTableEntries_1_0[] = {
Dejan Mircevskie26fdc62016-04-07 14:09:48 -040044#include "core.insts-1-0.inc"
David Neto78c3b432015-08-27 13:03:52 -040045};
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -040046const spv_opcode_desc_t opcodeTableEntries_1_1[] = {
47#include "core.insts-1-1.inc"
48};
David Neto78c3b432015-08-27 13:03:52 -040049
Lei Zhanga94701d2015-09-14 10:05:37 -040050} // anonymous namespace
David Neto78c3b432015-08-27 13:03:52 -040051
Lei Zhang1a0334e2015-11-02 09:41:20 -050052const char* spvGeneratorStr(uint32_t generator) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010053 switch (generator) {
54 case SPV_GENERATOR_KHRONOS:
55 return "Khronos";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010056 case SPV_GENERATOR_LUNARG:
57 return "LunarG";
David Neto1780fc42015-10-26 15:43:12 -040058 case SPV_GENERATOR_VALVE:
59 return "Valve";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010060 case SPV_GENERATOR_CODEPLAY:
61 return "Codeplay Software Ltd.";
David Neto1780fc42015-10-26 15:43:12 -040062 case SPV_GENERATOR_NVIDIA:
63 return "NVIDIA";
64 case SPV_GENERATOR_ARM:
65 return "ARM";
David Neto14b93e42015-11-12 18:33:47 -050066 case SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR:
67 return "Khronos LLVM/SPIR-V Translator";
68 case SPV_GENERATOR_KHRONOS_ASSEMBLER:
69 return "Khronos SPIR-V Tools Assembler";
David Neto2266ba12015-11-13 12:03:28 -060070 case SPV_GENERATOR_KHRONOS_GLSLANG:
71 return "Khronos Glslang Reference Front End";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010072 default:
73 return "Unknown";
74 }
75}
76
Lei Zhangb36e7042015-10-28 13:40:52 -040077uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010078 return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
79}
80
Lei Zhang6fa3f8a2016-03-31 17:26:31 -040081void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
82 uint16_t* pOpcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010083 if (pWordCount) {
84 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
85 }
86 if (pOpcode) {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -040087 *pOpcode = 0x0000ffff & word;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010088 }
89}
90
Lei Zhang4f293b72016-03-21 16:36:14 -040091// Evaluates to the number of elements of array A.
92// If we could use constexpr, then we could make this a template function.
93// If the source arrays were std::array, then we could have used
94// std::array::size.
95#define ARRAY_SIZE(A) (static_cast<uint32_t>(sizeof(A) / sizeof(A[0])))
96
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -040097spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable,
98 spv_target_env env) {
Lei Zhang40056702015-09-11 14:31:27 -040099 if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100100
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -0400101 static const spv_opcode_table_t table_1_0 = {
102 ARRAY_SIZE(opcodeTableEntries_1_0), opcodeTableEntries_1_0};
103 static const spv_opcode_table_t table_1_1 = {
104 ARRAY_SIZE(opcodeTableEntries_1_1), opcodeTableEntries_1_1};
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100105
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -0400106 switch (env) {
107 case SPV_ENV_UNIVERSAL_1_0:
108 case SPV_ENV_VULKAN_1_0:
109 *pInstTable = &table_1_0;
110 return SPV_SUCCESS;
111 case SPV_ENV_UNIVERSAL_1_1:
112 *pInstTable = &table_1_1;
113 return SPV_SUCCESS;
114 }
115 assert(0 && "Unknown spv_target_env in spvOpcodeTableGet()");
116 return SPV_ERROR_INVALID_TABLE;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100117}
118
119spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500120 const char* name,
121 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400122 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
123 if (!table) return SPV_ERROR_INVALID_TABLE;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100124
125 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
126 // preferable but the table requires sorting on the Opcode name, but it's
127 // static
128 // const initialized and matches the order of the spec.
129 const size_t nameLength = strlen(name);
130 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
131 if (nameLength == strlen(table->entries[opcodeIndex].name) &&
132 !strncmp(name, table->entries[opcodeIndex].name, nameLength)) {
133 // NOTE: Found out Opcode!
134 *pEntry = &table->entries[opcodeIndex];
135 return SPV_SUCCESS;
136 }
137 }
138
139 return SPV_ERROR_INVALID_LOOKUP;
140}
141
142spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
Lei Zhangb36e7042015-10-28 13:40:52 -0400143 const SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500144 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400145 if (!table) return SPV_ERROR_INVALID_TABLE;
146 if (!pEntry) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100147
148 // TODO: As above this lookup is not optimal.
149 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
150 if (opcode == table->entries[opcodeIndex].opcode) {
151 // NOTE: Found the Opcode!
152 *pEntry = &table->entries[opcodeIndex];
153 return SPV_SUCCESS;
154 }
155 }
156
157 return SPV_ERROR_INVALID_LOOKUP;
158}
159
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100160int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry) {
David Neto9db3a532015-10-07 16:58:38 -0400161 return entry->capabilities != 0;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100162}
163
Lei Zhang1a0334e2015-11-02 09:41:20 -0500164void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100165 const uint16_t wordCount, const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500166 spv_instruction_t* pInst) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100167 pInst->opcode = opcode;
David Netob5dc8fc2015-10-06 16:22:00 -0400168 pInst->words.resize(wordCount);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100169 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
170 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
171 if (!wordIndex) {
172 uint16_t thisWordCount;
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400173 uint16_t thisOpcode;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100174 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400175 assert(opcode == static_cast<SpvOp>(thisOpcode) &&
176 wordCount == thisWordCount && "Endianness failed!");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100177 }
178 }
179}
180
Lei Zhang1a0334e2015-11-02 09:41:20 -0500181const char* spvOpcodeString(const SpvOp opcode) {
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -0400182 // Use the latest SPIR-V version, which should be backward-compatible with all
183 // previous ones.
Lei Zhang4f293b72016-03-21 16:36:14 -0400184 for (uint32_t i = 0;
Dejan Mircevskicb3c49e2016-04-07 14:41:34 -0400185 i < sizeof(opcodeTableEntries_1_1) / sizeof(spv_opcode_desc_t); ++i) {
186 if (opcodeTableEntries_1_1[i].opcode == opcode)
187 return opcodeTableEntries_1_1[i].name;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100188 }
Lei Zhang4f293b72016-03-21 16:36:14 -0400189 assert(0 && "Unreachable!");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100190 return "unknown";
191}
192
Lei Zhangb36e7042015-10-28 13:40:52 -0400193int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100194 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400195 case SpvOpTypeInt:
196 case SpvOpTypeFloat:
Dejan Mircevski276a7242016-01-21 15:55:43 -0500197 case SpvOpTypeBool:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100198 return true;
199 default:
200 return false;
201 }
202}
203
Lei Zhangb36e7042015-10-28 13:40:52 -0400204int32_t spvOpcodeIsConstant(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100205 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400206 case SpvOpConstantTrue:
207 case SpvOpConstantFalse:
208 case SpvOpConstant:
209 case SpvOpConstantComposite:
210 case SpvOpConstantSampler:
Lei Zhangb36e7042015-10-28 13:40:52 -0400211 case SpvOpConstantNull:
212 case SpvOpSpecConstantTrue:
213 case SpvOpSpecConstantFalse:
214 case SpvOpSpecConstant:
215 case SpvOpSpecConstantComposite:
Dejan Mircevski3fb26762016-04-04 15:55:05 -0400216 case SpvOpSpecConstantOp:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100217 return true;
218 default:
219 return false;
220 }
221}
222
Lei Zhangb36e7042015-10-28 13:40:52 -0400223int32_t spvOpcodeIsComposite(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100224 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400225 case SpvOpTypeVector:
226 case SpvOpTypeMatrix:
227 case SpvOpTypeArray:
228 case SpvOpTypeStruct:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100229 return true;
230 default:
231 return false;
232 }
233}
234
Lei Zhangb36e7042015-10-28 13:40:52 -0400235int32_t spvOpcodeIsPointer(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100236 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400237 case SpvOpVariable:
238 case SpvOpAccessChain:
Florian Ziesche680f9b72016-03-01 19:56:14 +0100239 case SpvOpPtrAccessChain:
Lei Zhangb36e7042015-10-28 13:40:52 -0400240 case SpvOpInBoundsAccessChain:
Florian Ziesche680f9b72016-03-01 19:56:14 +0100241 case SpvOpInBoundsPtrAccessChain:
Lei Zhangb36e7042015-10-28 13:40:52 -0400242 case SpvOpFunctionParameter:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100243 return true;
244 default:
245 return false;
246 }
247}
248
Lei Zhangb36e7042015-10-28 13:40:52 -0400249int32_t spvOpcodeGeneratesType(SpvOp op) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500250 switch (op) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400251 case SpvOpTypeVoid:
252 case SpvOpTypeBool:
253 case SpvOpTypeInt:
254 case SpvOpTypeFloat:
255 case SpvOpTypeVector:
256 case SpvOpTypeMatrix:
257 case SpvOpTypeImage:
258 case SpvOpTypeSampler:
259 case SpvOpTypeSampledImage:
260 case SpvOpTypeArray:
261 case SpvOpTypeRuntimeArray:
262 case SpvOpTypeStruct:
263 case SpvOpTypeOpaque:
264 case SpvOpTypePointer:
265 case SpvOpTypeFunction:
266 case SpvOpTypeEvent:
267 case SpvOpTypeDeviceEvent:
268 case SpvOpTypeReserveId:
269 case SpvOpTypeQueue:
270 case SpvOpTypePipe:
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400271 return true;
David Netoaef608c2015-11-02 14:59:02 -0500272 default:
273 // In particular, OpTypeForwardPointer does not generate a type,
274 // but declares a storage class for a pointer type generated
275 // by a different instruction.
276 break;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400277 }
278 return 0;
279}