blob: fda3ff060574a3af1fb852862e261c286ebb48ba [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.
43//
44// Most fields are initialized statically by including an automatically
45// generated file.
46// The operandTypes fields are initialized during spvOpcodeInitialize().
47//
48// TODO(dneto): Some of the macros are quite unreadable. We could make
49// good use of constexpr functions, but some compilers don't support that yet.
Lei Zhang972788b2015-11-12 13:48:30 -050050const spv_opcode_desc_t opcodeTableEntries[] = {
David Neto78c3b432015-08-27 13:03:52 -040051#include "opcode.inc"
David Neto78c3b432015-08-27 13:03:52 -040052};
53
Lei Zhanga94701d2015-09-14 10:05:37 -040054} // anonymous namespace
David Neto78c3b432015-08-27 13:03:52 -040055
Lei Zhang1a0334e2015-11-02 09:41:20 -050056const char* spvGeneratorStr(uint32_t generator) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010057 switch (generator) {
58 case SPV_GENERATOR_KHRONOS:
59 return "Khronos";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010060 case SPV_GENERATOR_LUNARG:
61 return "LunarG";
David Neto1780fc42015-10-26 15:43:12 -040062 case SPV_GENERATOR_VALVE:
63 return "Valve";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010064 case SPV_GENERATOR_CODEPLAY:
65 return "Codeplay Software Ltd.";
David Neto1780fc42015-10-26 15:43:12 -040066 case SPV_GENERATOR_NVIDIA:
67 return "NVIDIA";
68 case SPV_GENERATOR_ARM:
69 return "ARM";
David Neto14b93e42015-11-12 18:33:47 -050070 case SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR:
71 return "Khronos LLVM/SPIR-V Translator";
72 case SPV_GENERATOR_KHRONOS_ASSEMBLER:
73 return "Khronos SPIR-V Tools Assembler";
David Neto2266ba12015-11-13 12:03:28 -060074 case SPV_GENERATOR_KHRONOS_GLSLANG:
75 return "Khronos Glslang Reference Front End";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010076 default:
77 return "Unknown";
78 }
79}
80
Lei Zhangb36e7042015-10-28 13:40:52 -040081uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010082 return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
83}
84
Lei Zhang1a0334e2015-11-02 09:41:20 -050085void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, SpvOp* pOpcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010086 if (pWordCount) {
87 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
88 }
89 if (pOpcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -040090 *pOpcode = (SpvOp)(0x0000ffff & word);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010091 }
92}
93
Lei Zhang4f293b72016-03-21 16:36:14 -040094// Evaluates to the number of elements of array A.
95// If we could use constexpr, then we could make this a template function.
96// If the source arrays were std::array, then we could have used
97// std::array::size.
98#define ARRAY_SIZE(A) (static_cast<uint32_t>(sizeof(A) / sizeof(A[0])))
99
Lei Zhang1a0334e2015-11-02 09:41:20 -0500100spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable) {
Lei Zhang40056702015-09-11 14:31:27 -0400101 if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100102
Lei Zhang4f293b72016-03-21 16:36:14 -0400103 static const spv_opcode_table_t table = {ARRAY_SIZE(opcodeTableEntries),
104 opcodeTableEntries};
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100105
Lei Zhang4f293b72016-03-21 16:36:14 -0400106 *pInstTable = &table;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100107
108 return SPV_SUCCESS;
109}
110
111spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500112 const char* name,
113 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400114 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
115 if (!table) return SPV_ERROR_INVALID_TABLE;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100116
117 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
118 // preferable but the table requires sorting on the Opcode name, but it's
119 // static
120 // const initialized and matches the order of the spec.
121 const size_t nameLength = strlen(name);
122 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
123 if (nameLength == strlen(table->entries[opcodeIndex].name) &&
124 !strncmp(name, table->entries[opcodeIndex].name, nameLength)) {
125 // NOTE: Found out Opcode!
126 *pEntry = &table->entries[opcodeIndex];
127 return SPV_SUCCESS;
128 }
129 }
130
131 return SPV_ERROR_INVALID_LOOKUP;
132}
133
134spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
Lei Zhangb36e7042015-10-28 13:40:52 -0400135 const SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500136 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400137 if (!table) return SPV_ERROR_INVALID_TABLE;
138 if (!pEntry) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100139
140 // TODO: As above this lookup is not optimal.
141 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
142 if (opcode == table->entries[opcodeIndex].opcode) {
143 // NOTE: Found the Opcode!
144 *pEntry = &table->entries[opcodeIndex];
145 return SPV_SUCCESS;
146 }
147 }
148
149 return SPV_ERROR_INVALID_LOOKUP;
150}
151
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100152int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry) {
David Neto9db3a532015-10-07 16:58:38 -0400153 return entry->capabilities != 0;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100154}
155
Lei Zhang1a0334e2015-11-02 09:41:20 -0500156void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100157 const uint16_t wordCount, const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500158 spv_instruction_t* pInst) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100159 pInst->opcode = opcode;
David Netob5dc8fc2015-10-06 16:22:00 -0400160 pInst->words.resize(wordCount);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100161 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
162 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
163 if (!wordIndex) {
164 uint16_t thisWordCount;
Lei Zhangb36e7042015-10-28 13:40:52 -0400165 SpvOp thisOpcode;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100166 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
167 assert(opcode == thisOpcode && wordCount == thisWordCount &&
168 "Endianness failed!");
169 }
170 }
171}
172
Lei Zhang1a0334e2015-11-02 09:41:20 -0500173const char* spvOpcodeString(const SpvOp opcode) {
Lei Zhang4f293b72016-03-21 16:36:14 -0400174 for (uint32_t i = 0;
175 i < sizeof(opcodeTableEntries) / sizeof(spv_opcode_desc_t); ++i) {
176 if (opcodeTableEntries[i].opcode == opcode)
177 return opcodeTableEntries[i].name;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100178 }
Lei Zhang4f293b72016-03-21 16:36:14 -0400179 assert(0 && "Unreachable!");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100180 return "unknown";
181}
182
Lei Zhangb36e7042015-10-28 13:40:52 -0400183int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100184 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400185 case SpvOpTypeInt:
186 case SpvOpTypeFloat:
Dejan Mircevski276a7242016-01-21 15:55:43 -0500187 case SpvOpTypeBool:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100188 return true;
189 default:
190 return false;
191 }
192}
193
Lei Zhangb36e7042015-10-28 13:40:52 -0400194int32_t spvOpcodeIsConstant(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100195 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400196 case SpvOpConstantTrue:
197 case SpvOpConstantFalse:
198 case SpvOpConstant:
199 case SpvOpConstantComposite:
200 case SpvOpConstantSampler:
201 // case SpvOpConstantNull:
202 case SpvOpConstantNull:
203 case SpvOpSpecConstantTrue:
204 case SpvOpSpecConstantFalse:
205 case SpvOpSpecConstant:
206 case SpvOpSpecConstantComposite:
207 // case SpvOpSpecConstantOp:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100208 return true;
209 default:
210 return false;
211 }
212}
213
Lei Zhangb36e7042015-10-28 13:40:52 -0400214int32_t spvOpcodeIsComposite(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100215 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400216 case SpvOpTypeVector:
217 case SpvOpTypeMatrix:
218 case SpvOpTypeArray:
219 case SpvOpTypeStruct:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100220 return true;
221 default:
222 return false;
223 }
224}
225
Lei Zhangb36e7042015-10-28 13:40:52 -0400226int32_t spvOpcodeIsPointer(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100227 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400228 case SpvOpVariable:
229 case SpvOpAccessChain:
Florian Ziesche680f9b72016-03-01 19:56:14 +0100230 case SpvOpPtrAccessChain:
Lei Zhangb36e7042015-10-28 13:40:52 -0400231 case SpvOpInBoundsAccessChain:
Florian Ziesche680f9b72016-03-01 19:56:14 +0100232 case SpvOpInBoundsPtrAccessChain:
Lei Zhangb36e7042015-10-28 13:40:52 -0400233 case SpvOpFunctionParameter:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100234 return true;
235 default:
236 return false;
237 }
238}
239
Lei Zhangb36e7042015-10-28 13:40:52 -0400240int32_t spvOpcodeGeneratesType(SpvOp op) {
Lei Zhang1a0334e2015-11-02 09:41:20 -0500241 switch (op) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400242 case SpvOpTypeVoid:
243 case SpvOpTypeBool:
244 case SpvOpTypeInt:
245 case SpvOpTypeFloat:
246 case SpvOpTypeVector:
247 case SpvOpTypeMatrix:
248 case SpvOpTypeImage:
249 case SpvOpTypeSampler:
250 case SpvOpTypeSampledImage:
251 case SpvOpTypeArray:
252 case SpvOpTypeRuntimeArray:
253 case SpvOpTypeStruct:
254 case SpvOpTypeOpaque:
255 case SpvOpTypePointer:
256 case SpvOpTypeFunction:
257 case SpvOpTypeEvent:
258 case SpvOpTypeDeviceEvent:
259 case SpvOpTypeReserveId:
260 case SpvOpTypeQueue:
261 case SpvOpTypePipe:
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400262 return true;
David Netoaef608c2015-11-02 14:59:02 -0500263 default:
264 // In particular, OpTypeForwardPointer does not generate a type,
265 // but declares a storage class for a pointer type generated
266 // by a different instruction.
267 break;
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400268 }
269 return 0;
270}