blob: 518da26f7db73159c13d9780a3ff6a6844f434c4 [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[] = {
Lei Zhang80e416c2016-04-04 14:30:56 -040051#include "core.insts.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 Zhang6fa3f8a2016-03-31 17:26:31 -040085void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
86 uint16_t* pOpcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010087 if (pWordCount) {
88 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
89 }
90 if (pOpcode) {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -040091 *pOpcode = 0x0000ffff & word;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010092 }
93}
94
Lei Zhang4f293b72016-03-21 16:36:14 -040095// Evaluates to the number of elements of array A.
96// If we could use constexpr, then we could make this a template function.
97// If the source arrays were std::array, then we could have used
98// std::array::size.
99#define ARRAY_SIZE(A) (static_cast<uint32_t>(sizeof(A) / sizeof(A[0])))
100
Lei Zhang1a0334e2015-11-02 09:41:20 -0500101spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable) {
Lei Zhang40056702015-09-11 14:31:27 -0400102 if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100103
Lei Zhang4f293b72016-03-21 16:36:14 -0400104 static const spv_opcode_table_t table = {ARRAY_SIZE(opcodeTableEntries),
105 opcodeTableEntries};
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100106
Lei Zhang4f293b72016-03-21 16:36:14 -0400107 *pInstTable = &table;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100108
109 return SPV_SUCCESS;
110}
111
112spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500113 const char* name,
114 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400115 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
116 if (!table) return SPV_ERROR_INVALID_TABLE;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100117
118 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
119 // preferable but the table requires sorting on the Opcode name, but it's
120 // static
121 // const initialized and matches the order of the spec.
122 const size_t nameLength = strlen(name);
123 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
124 if (nameLength == strlen(table->entries[opcodeIndex].name) &&
125 !strncmp(name, table->entries[opcodeIndex].name, nameLength)) {
126 // NOTE: Found out Opcode!
127 *pEntry = &table->entries[opcodeIndex];
128 return SPV_SUCCESS;
129 }
130 }
131
132 return SPV_ERROR_INVALID_LOOKUP;
133}
134
135spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
Lei Zhangb36e7042015-10-28 13:40:52 -0400136 const SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500137 spv_opcode_desc* pEntry) {
Lei Zhang40056702015-09-11 14:31:27 -0400138 if (!table) return SPV_ERROR_INVALID_TABLE;
139 if (!pEntry) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100140
141 // TODO: As above this lookup is not optimal.
142 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
143 if (opcode == table->entries[opcodeIndex].opcode) {
144 // NOTE: Found the Opcode!
145 *pEntry = &table->entries[opcodeIndex];
146 return SPV_SUCCESS;
147 }
148 }
149
150 return SPV_ERROR_INVALID_LOOKUP;
151}
152
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100153int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry) {
David Neto9db3a532015-10-07 16:58:38 -0400154 return entry->capabilities != 0;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100155}
156
Lei Zhang1a0334e2015-11-02 09:41:20 -0500157void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100158 const uint16_t wordCount, const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500159 spv_instruction_t* pInst) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100160 pInst->opcode = opcode;
David Netob5dc8fc2015-10-06 16:22:00 -0400161 pInst->words.resize(wordCount);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100162 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
163 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
164 if (!wordIndex) {
165 uint16_t thisWordCount;
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400166 uint16_t thisOpcode;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100167 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400168 assert(opcode == static_cast<SpvOp>(thisOpcode) &&
169 wordCount == thisWordCount && "Endianness failed!");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100170 }
171 }
172}
173
Lei Zhang1a0334e2015-11-02 09:41:20 -0500174const char* spvOpcodeString(const SpvOp opcode) {
Lei Zhang4f293b72016-03-21 16:36:14 -0400175 for (uint32_t i = 0;
176 i < sizeof(opcodeTableEntries) / sizeof(spv_opcode_desc_t); ++i) {
177 if (opcodeTableEntries[i].opcode == opcode)
178 return opcodeTableEntries[i].name;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100179 }
Lei Zhang4f293b72016-03-21 16:36:14 -0400180 assert(0 && "Unreachable!");
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100181 return "unknown";
182}
183
Lei Zhangb36e7042015-10-28 13:40:52 -0400184int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100185 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400186 case SpvOpTypeInt:
187 case SpvOpTypeFloat:
Dejan Mircevski276a7242016-01-21 15:55:43 -0500188 case SpvOpTypeBool:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100189 return true;
190 default:
191 return false;
192 }
193}
194
Lei Zhangb36e7042015-10-28 13:40:52 -0400195int32_t spvOpcodeIsConstant(const SpvOp opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100196 switch (opcode) {
Lei Zhangb36e7042015-10-28 13:40:52 -0400197 case SpvOpConstantTrue:
198 case SpvOpConstantFalse:
199 case SpvOpConstant:
200 case SpvOpConstantComposite:
201 case SpvOpConstantSampler:
Lei Zhangb36e7042015-10-28 13:40:52 -0400202 case SpvOpConstantNull:
203 case SpvOpSpecConstantTrue:
204 case SpvOpSpecConstantFalse:
205 case SpvOpSpecConstant:
206 case SpvOpSpecConstantComposite:
Dejan Mircevski3fb26762016-04-04 15:55:05 -0400207 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}