blob: 4d98e3dab828a4e9d15b84f538a64781ffbdd57e [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
David Netofcc7d582015-10-27 15:31:10 -04002//
David Neto9fc86582016-09-01 15:33:59 -04003// 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
David Netofcc7d582015-10-27 15:31:10 -04006//
David Neto9fc86582016-09-01 15:33:59 -04007// http://www.apache.org/licenses/LICENSE-2.0
David Netofcc7d582015-10-27 15:31:10 -04008//
David Neto9fc86582016-09-01 15:33:59 -04009// 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.
David Netofcc7d582015-10-27 15:31:10 -040014
dan sinclaireda2cfb2018-08-03 15:06:09 -040015#include "source/assembly_grammar.h"
David Netofcc7d582015-10-27 15:31:10 -040016
17#include <algorithm>
David Neto0ca6b592015-10-30 16:06:15 -040018#include <cassert>
David Netofcc7d582015-10-27 15:31:10 -040019#include <cstring>
20
dan sinclaireda2cfb2018-08-03 15:06:09 -040021#include "source/ext_inst.h"
22#include "source/opcode.h"
23#include "source/operand.h"
24#include "source/table.h"
David Netofcc7d582015-10-27 15:31:10 -040025
dan sinclair3dad1cd2018-07-07 09:38:00 -040026namespace spvtools {
David Netofcc7d582015-10-27 15:31:10 -040027namespace {
28
29/// @brief Parses a mask expression string for the given operand type.
30///
31/// A mask expression is a sequence of one or more terms separated by '|',
32/// where each term a named enum value for the given type. No whitespace
33/// is permitted.
34///
35/// On success, the value is written to pValue.
36///
37/// @param[in] operandTable operand lookup table
38/// @param[in] type of the operand
39/// @param[in] textValue word of text to be parsed
40/// @param[out] pValue where the resulting value is written
41///
42/// @return result code
Lei Zhang1ef6b192018-03-14 13:06:18 -040043spv_result_t spvTextParseMaskOperand(spv_target_env env,
44 const spv_operand_table operandTable,
David Netofcc7d582015-10-27 15:31:10 -040045 const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -050046 const char* textValue, uint32_t* pValue) {
David Netofcc7d582015-10-27 15:31:10 -040047 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
48 size_t text_length = strlen(textValue);
49 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
Lei Zhang1a0334e2015-11-02 09:41:20 -050050 const char* text_end = textValue + text_length;
David Netofcc7d582015-10-27 15:31:10 -040051
52 // We only support mask expressions in ASCII, so the separator value is a
53 // char.
54 const char separator = '|';
55
56 // Accumulate the result by interpreting one word at a time, scanning
57 // from left to right.
58 uint32_t value = 0;
Lei Zhang1a0334e2015-11-02 09:41:20 -050059 const char* begin = textValue; // The left end of the current word.
60 const char* end = nullptr; // One character past the end of the current word.
David Netofcc7d582015-10-27 15:31:10 -040061 do {
62 end = std::find(begin, text_end, separator);
63
64 spv_operand_desc entry = nullptr;
Lei Zhang1ef6b192018-03-14 13:06:18 -040065 if (spvOperandTableNameLookup(env, operandTable, type, begin, end - begin,
David Netofcc7d582015-10-27 15:31:10 -040066 &entry)) {
67 return SPV_ERROR_INVALID_TEXT;
68 }
69 value |= entry->value;
70
71 // Advance to the next word by skipping over the separator.
72 begin = end + 1;
73 } while (end != text_end);
74
75 *pValue = value;
76 return SPV_SUCCESS;
77}
David Neto0ca6b592015-10-30 16:06:15 -040078
David Neto0f166be2015-11-11 01:56:49 -050079// Associates an opcode with its name.
80struct SpecConstantOpcodeEntry {
81 SpvOp opcode;
82 const char* name;
83};
84
85// All the opcodes allowed as the operation for OpSpecConstantOp.
86// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
87// is associated with the name "IAdd".
88//
89// clang-format off
90#define CASE(NAME) { SpvOp##NAME, #NAME }
91const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
92 // Conversion
93 CASE(SConvert),
94 CASE(FConvert),
95 CASE(ConvertFToS),
96 CASE(ConvertSToF),
97 CASE(ConvertFToU),
98 CASE(ConvertUToF),
99 CASE(UConvert),
100 CASE(ConvertPtrToU),
101 CASE(ConvertUToPtr),
David Neto969ce4b2016-01-05 18:22:22 -0500102 CASE(GenericCastToPtr),
David Neto0f166be2015-11-11 01:56:49 -0500103 CASE(PtrCastToGeneric),
104 CASE(Bitcast),
105 CASE(QuantizeToF16),
106 // Arithmetic
107 CASE(SNegate),
108 CASE(Not),
109 CASE(IAdd),
110 CASE(ISub),
111 CASE(IMul),
112 CASE(UDiv),
113 CASE(SDiv),
114 CASE(UMod),
115 CASE(SRem),
116 CASE(SMod),
117 CASE(ShiftRightLogical),
118 CASE(ShiftRightArithmetic),
119 CASE(ShiftLeftLogical),
120 CASE(BitwiseOr),
121 CASE(BitwiseAnd),
David Neto969ce4b2016-01-05 18:22:22 -0500122 CASE(BitwiseXor),
David Neto0f166be2015-11-11 01:56:49 -0500123 CASE(FNegate),
124 CASE(FAdd),
125 CASE(FSub),
126 CASE(FMul),
127 CASE(FDiv),
128 CASE(FRem),
129 CASE(FMod),
130 // Composite
131 CASE(VectorShuffle),
132 CASE(CompositeExtract),
133 CASE(CompositeInsert),
134 // Logical
135 CASE(LogicalOr),
136 CASE(LogicalAnd),
137 CASE(LogicalNot),
138 CASE(LogicalEqual),
139 CASE(LogicalNotEqual),
140 CASE(Select),
141 // Comparison
142 CASE(IEqual),
qining256c56d2016-07-26 17:52:06 -0400143 CASE(INotEqual),
David Neto0f166be2015-11-11 01:56:49 -0500144 CASE(ULessThan),
145 CASE(SLessThan),
146 CASE(UGreaterThan),
147 CASE(SGreaterThan),
148 CASE(ULessThanEqual),
149 CASE(SLessThanEqual),
David Neto0f166be2015-11-11 01:56:49 -0500150 CASE(UGreaterThanEqual),
151 CASE(SGreaterThanEqual),
152 // Memory
153 CASE(AccessChain),
154 CASE(InBoundsAccessChain),
155 CASE(PtrAccessChain),
156 CASE(InBoundsPtrAccessChain),
157};
David Neto969ce4b2016-01-05 18:22:22 -0500158
qining256c56d2016-07-26 17:52:06 -0400159// The 59 is determined by counting the opcodes listed in the spec.
160static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
David Neto969ce4b2016-01-05 18:22:22 -0500161 "OpSpecConstantOp opcode table is incomplete");
David Neto0f166be2015-11-11 01:56:49 -0500162#undef CASE
163// clang-format on
164
165const size_t kNumOpSpecConstantOpcodes =
166 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
167
dan sinclair3dad1cd2018-07-07 09:38:00 -0400168} // namespace
David Netofcc7d582015-10-27 15:31:10 -0400169
170bool AssemblyGrammar::isValid() const {
171 return operandTable_ && opcodeTable_ && extInstTable_;
172}
173
Lei Zhang1ef6b192018-03-14 13:06:18 -0400174CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
175 const SpvCapability* cap_array, uint32_t count) const {
176 CapabilitySet cap_set;
177 for (uint32_t i = 0; i < count; ++i) {
178 spv_operand_desc cap_desc = {};
179 if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
180 static_cast<uint32_t>(cap_array[i]),
181 &cap_desc)) {
182 // spvOperandTableValueLookup() filters capabilities internally
183 // according to the current target environment by itself. So we
184 // should be safe to add this capability if the lookup succeeds.
185 cap_set.Add(cap_array[i]);
186 }
187 }
188 return cap_set;
189}
190
Lei Zhang1a0334e2015-11-02 09:41:20 -0500191spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
192 spv_opcode_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400193 return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
David Netofcc7d582015-10-27 15:31:10 -0400194}
195
Lei Zhangb36e7042015-10-28 13:40:52 -0400196spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500197 spv_opcode_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400198 return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
David Netofcc7d582015-10-27 15:31:10 -0400199}
200
201spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500202 const char* name, size_t name_len,
203 spv_operand_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400204 return spvOperandTableNameLookup(target_env_, operandTable_, type, name,
205 name_len, desc);
David Netofcc7d582015-10-27 15:31:10 -0400206}
207
208spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
209 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500210 spv_operand_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400211 return spvOperandTableValueLookup(target_env_, operandTable_, type, operand,
212 desc);
David Netofcc7d582015-10-27 15:31:10 -0400213}
214
David Neto0f166be2015-11-11 01:56:49 -0500215spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
216 SpvOp* opcode) const {
217 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
218 const auto* found =
219 std::find_if(kOpSpecConstantOpcodes, last,
220 [name](const SpecConstantOpcodeEntry& entry) {
221 return 0 == strcmp(name, entry.name);
222 });
223 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
224 *opcode = found->opcode;
225 return SPV_SUCCESS;
226}
227
David Neto21196942015-11-11 02:45:45 -0500228spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
229 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
230 const auto* found =
231 std::find_if(kOpSpecConstantOpcodes, last,
232 [opcode](const SpecConstantOpcodeEntry& entry) {
233 return opcode == entry.opcode;
234 });
235 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
236 return SPV_SUCCESS;
237}
238
David Netofcc7d582015-10-27 15:31:10 -0400239spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500240 const char* textValue,
241 uint32_t* pValue) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400242 return spvTextParseMaskOperand(target_env_, operandTable_, type, textValue,
243 pValue);
David Netofcc7d582015-10-27 15:31:10 -0400244}
245spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500246 const char* textValue,
247 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400248 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
249}
250
251spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
252 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500253 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400254 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
255}
256
Chris Forbes78338d52017-06-27 16:28:22 -0700257void AssemblyGrammar::pushOperandTypesForMask(
David Netofcc7d582015-10-27 15:31:10 -0400258 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500259 spv_operand_pattern_t* pattern) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400260 spvPushOperandTypesForMask(target_env_, operandTable_, type, mask, pattern);
David Netofcc7d582015-10-27 15:31:10 -0400261}
dan sinclair3dad1cd2018-07-07 09:38:00 -0400262
263} // namespace spvtools