1/*
2 * Copyright (C) 2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WHLSLIntrinsics.h"
28
29#if ENABLE(WEBGPU)
30
31#include "WHLSLConstantExpression.h"
32#include "WHLSLTypeArgument.h"
33#include "WHLSLTypeReference.h"
34#include <algorithm>
35#include <cstring>
36
37namespace WebCore {
38
39namespace WHLSL {
40
41constexpr const char* Intrinsics::m_textureTypeNames[];
42constexpr const char* Intrinsics::m_textureInnerTypeNames[];
43constexpr const char* Intrinsics::m_depthTextureInnerTypes[];
44
45Intrinsics::Intrinsics()
46{
47}
48
49void Intrinsics::add(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
50{
51 if (nativeFunctionDeclaration.name() == "ddx")
52 m_ddx = &nativeFunctionDeclaration;
53 else if (nativeFunctionDeclaration.name() == "ddy")
54 m_ddy = &nativeFunctionDeclaration;
55 else if (nativeFunctionDeclaration.name() == "AllMemoryBarrierWithGroupSync")
56 m_allMemoryBarrier = &nativeFunctionDeclaration;
57 else if (nativeFunctionDeclaration.name() == "DeviceMemoryBarrierWithGroupSync")
58 m_deviceMemoryBarrier = &nativeFunctionDeclaration;
59 else if (nativeFunctionDeclaration.name() == "GroupMemoryBarrierWithGroupSync")
60 m_groupMemoryBarrier = &nativeFunctionDeclaration;
61}
62
63bool Intrinsics::addPrimitive(AST::NativeTypeDeclaration& nativeTypeDeclaration)
64{
65 if (nativeTypeDeclaration.typeArguments().size())
66 return false;
67
68 if (nativeTypeDeclaration.name() == "void")
69 m_voidType = &nativeTypeDeclaration;
70 else if (nativeTypeDeclaration.name() == "bool")
71 m_boolType = &nativeTypeDeclaration;
72 else if (nativeTypeDeclaration.name() == "uchar") {
73 nativeTypeDeclaration.setIsInt();
74 nativeTypeDeclaration.setIsNumber();
75 nativeTypeDeclaration.setCanRepresentInteger([](int x) {
76 return x >= 0 && x <= 0xFF;
77 });
78 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
79 return x <= 0xFF;
80 });
81 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
82 return static_cast<float>(static_cast<uint8_t>(x)) == x;
83 });
84 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
85 return static_cast<uint8_t>(x + 1);
86 });
87 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
88 return static_cast<uint8_t>(x);
89 });
90 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
91 return static_cast<uint8_t>(x);
92 });
93 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
94 for (int64_t i = 0; i < 0x100; ++i) {
95 if (callback(i))
96 break;
97 }
98 });
99 m_ucharType = &nativeTypeDeclaration;
100 } else if (nativeTypeDeclaration.name() == "ushort") {
101 nativeTypeDeclaration.setIsInt();
102 nativeTypeDeclaration.setIsNumber();
103 nativeTypeDeclaration.setCanRepresentInteger([](int x) {
104 return x >= 0 && x <= 0xFFFF;
105 });
106 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
107 return x <= 0xFFFF;
108 });
109 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
110 return static_cast<float>(static_cast<uint16_t>(x)) == x;
111 });
112 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
113 return static_cast<uint16_t>(x + 1);
114 });
115 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
116 return static_cast<uint16_t>(x);
117 });
118 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
119 return static_cast<uint16_t>(x);
120 });
121 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
122 for (int64_t i = 0; i < 0x10000; ++i) {
123 if (callback(i))
124 break;
125 }
126 });
127 m_ushortType = &nativeTypeDeclaration;
128 } else if (nativeTypeDeclaration.name() == "uint") {
129 nativeTypeDeclaration.setIsInt();
130 nativeTypeDeclaration.setIsNumber();
131 nativeTypeDeclaration.setCanRepresentInteger([](int x) {
132 return x >= 0;
133 });
134 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned) {
135 return true;
136 });
137 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
138 return static_cast<float>(static_cast<uint32_t>(x)) == x;
139 });
140 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
141 return static_cast<uint32_t>(x + 1);
142 });
143 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
144 return static_cast<uint32_t>(x);
145 });
146 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
147 return static_cast<uint32_t>(x);
148 });
149 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
150 for (int64_t i = 0; i < 0x100000000; ++i) {
151 if (callback(i))
152 break;
153 }
154 });
155 m_uintType = &nativeTypeDeclaration;
156 } else if (nativeTypeDeclaration.name() == "char") {
157 nativeTypeDeclaration.setIsInt();
158 nativeTypeDeclaration.setIsNumber();
159 nativeTypeDeclaration.setIsSigned();
160 nativeTypeDeclaration.setCanRepresentInteger([](int x) {
161 return x >= -128 && x <= 127;
162 });
163 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
164 return x <= 127;
165 });
166 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
167 return static_cast<float>(static_cast<int8_t>(x)) == x;
168 });
169 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
170 return static_cast<int8_t>(x + 1);
171 });
172 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
173 return static_cast<int8_t>(x);
174 });
175 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
176 return static_cast<int8_t>(x);
177 });
178 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
179 for (int64_t i = -128; i < 128; ++i) {
180 if (callback(i))
181 break;
182 }
183 });
184 m_charType = &nativeTypeDeclaration;
185 } else if (nativeTypeDeclaration.name() == "short") {
186 nativeTypeDeclaration.setIsInt();
187 nativeTypeDeclaration.setIsNumber();
188 nativeTypeDeclaration.setIsSigned();
189 nativeTypeDeclaration.setCanRepresentInteger([](int x) {
190 return x >= -32768 && x <= 32767;
191 });
192 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
193 return x <= 32767;
194 });
195 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
196 return static_cast<float>(static_cast<int16_t>(x)) == x;
197 });
198 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
199 return static_cast<int16_t>(x + 1);
200 });
201 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
202 return static_cast<int16_t>(x);
203 });
204 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
205 return static_cast<int16_t>(x);
206 });
207 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
208 for (int64_t i = -32768; i < 32768; ++i) {
209 if (callback(i))
210 break;
211 }
212 });
213 m_shortType = &nativeTypeDeclaration;
214 } else if (nativeTypeDeclaration.name() == "int") {
215 nativeTypeDeclaration.setIsInt();
216 nativeTypeDeclaration.setIsNumber();
217 nativeTypeDeclaration.setIsSigned();
218 nativeTypeDeclaration.setCanRepresentInteger([](int) {
219 return true;
220 });
221 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
222 return x <= 2147483647;
223 });
224 nativeTypeDeclaration.setCanRepresentFloat([](float x) {
225 return static_cast<float>(static_cast<int32_t>(x)) == x;
226 });
227 nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
228 return static_cast<int32_t>(x + 1);
229 });
230 nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
231 return static_cast<int32_t>(x);
232 });
233 nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
234 return static_cast<int32_t>(x);
235 });
236 nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
237 for (int64_t i = -2147483647; i < 2147483648; ++i) {
238 if (callback(i))
239 break;
240 }
241 });
242 m_intType = &nativeTypeDeclaration;
243 } else if (nativeTypeDeclaration.name() == "half") {
244 nativeTypeDeclaration.setIsNumber();
245 nativeTypeDeclaration.setIsFloating();
246 nativeTypeDeclaration.setCanRepresentInteger([](int) {
247 return true;
248 });
249 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned) {
250 return true;
251 });
252 nativeTypeDeclaration.setCanRepresentFloat([](float) {
253 return true;
254 });
255 m_halfType = &nativeTypeDeclaration;
256 } else if (nativeTypeDeclaration.name() == "float") {
257 nativeTypeDeclaration.setIsNumber();
258 nativeTypeDeclaration.setIsFloating();
259 nativeTypeDeclaration.setCanRepresentInteger([](int) {
260 return true;
261 });
262 nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned) {
263 return true;
264 });
265 nativeTypeDeclaration.setCanRepresentFloat([](float) {
266 return true;
267 });
268 m_floatType = &nativeTypeDeclaration;
269 } else if (nativeTypeDeclaration.name() == "atomic_int") {
270 nativeTypeDeclaration.setIsAtomic();
271 m_atomicIntType = &nativeTypeDeclaration;
272 } else if (nativeTypeDeclaration.name() == "atomic_uint") {
273 nativeTypeDeclaration.setIsAtomic();
274 m_atomicUintType = &nativeTypeDeclaration;
275 } else if (nativeTypeDeclaration.name() == "sampler")
276 m_samplerType = &nativeTypeDeclaration;
277 else
278 ASSERT_NOT_REACHED();
279 return true;
280}
281
282bool Intrinsics::addVector(AST::NativeTypeDeclaration& nativeTypeDeclaration)
283{
284 if (nativeTypeDeclaration.name() != "vector")
285 return false;
286
287 ASSERT(nativeTypeDeclaration.typeArguments().size() == 2);
288 ASSERT(WTF::holds_alternative<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
289 ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]));
290 auto& innerType = static_cast<AST::TypeReference&>(WTF::get<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
291 auto& lengthExpression = WTF::get<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]);
292 ASSERT(!innerType.typeArguments().size());
293 AST::NativeTypeDeclaration** array;
294 if (innerType.name() == "bool")
295 array = m_vectorBool;
296 else if (innerType.name() == "uchar")
297 array = m_vectorUchar;
298 else if (innerType.name() == "ushort")
299 array = m_vectorUshort;
300 else if (innerType.name() == "uint")
301 array = m_vectorUint;
302 else if (innerType.name() == "char")
303 array = m_vectorChar;
304 else if (innerType.name() == "short")
305 array = m_vectorShort;
306 else if (innerType.name() == "int")
307 array = m_vectorInt;
308 else if (innerType.name() == "half")
309 array = m_vectorHalf;
310 else {
311 ASSERT(innerType.name() == "float");
312 array = m_vectorFloat;
313 }
314 int length = lengthExpression.integerLiteral().value();
315 ASSERT(length >= 2 && length <= 4);
316 nativeTypeDeclaration.setIsVector();
317 array[length - 2] = &nativeTypeDeclaration;
318 return true;
319}
320
321bool Intrinsics::addMatrix(AST::NativeTypeDeclaration& nativeTypeDeclaration)
322{
323 if (nativeTypeDeclaration.name() != "matrix")
324 return false;
325
326 ASSERT(nativeTypeDeclaration.typeArguments().size() == 3);
327 ASSERT(WTF::holds_alternative<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
328 ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]));
329 ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[2]));
330 auto& innerType = static_cast<AST::TypeReference&>(WTF::get<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
331 auto& rowExpression = WTF::get<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]);
332 auto& columnExpression = WTF::get<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[2]);
333 ASSERT(!innerType.typeArguments().size());
334 AST::NativeTypeDeclaration* (*array)[3];
335 if (innerType.name() == "half")
336 array = m_matrixHalf;
337 if (innerType.name() == "float")
338 array = m_matrixFloat;
339 int row = rowExpression.integerLiteral().value();
340 ASSERT(row >= 2 && row <= 4);
341 int column = columnExpression.integerLiteral().value();
342 ASSERT(column >= 2 && column <= 4);
343 nativeTypeDeclaration.setIsMatrix();
344 array[row - 2][column - 2] = &nativeTypeDeclaration;
345 return true;
346}
347
348bool Intrinsics::addFullTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration, AST::TypeReference& innerType)
349{
350 unsigned textureTypeIndex = WTF_ARRAY_LENGTH(m_textureTypeNames);
351 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_textureTypeNames); ++i) {
352 if (nativeTypeDeclaration.name() == m_textureTypeNames[i])
353 textureTypeIndex = i;
354 }
355 if (textureTypeIndex == WTF_ARRAY_LENGTH(m_textureTypeNames))
356 return false;
357
358 unsigned innerTypeIndex = WTF_ARRAY_LENGTH(m_textureInnerTypeNames);
359 unsigned vectorLength;
360 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_textureInnerTypeNames); ++i) {
361 if (innerType.name().startsWith(m_textureInnerTypeNames[i])) {
362 innerTypeIndex = i;
363 if (innerType.name() == m_textureInnerTypeNames[i])
364 vectorLength = 1;
365 else {
366 ASSERT(innerType.name().length() == strlen(m_textureInnerTypeNames[i]) + 1);
367 ASSERT(innerType.name()[innerType.name().length() - 1] == '2'
368 || innerType.name()[innerType.name().length() - 1] == '3'
369 || innerType.name()[innerType.name().length() - 1] == '4');
370 vectorLength = innerType.name()[innerType.name().length() - 1] - '0';
371 }
372 }
373 }
374 ASSERT(innerTypeIndex != WTF_ARRAY_LENGTH(m_textureInnerTypeNames));
375 nativeTypeDeclaration.setIsTexture();
376 m_fullTextures[textureTypeIndex][innerTypeIndex][vectorLength - 1] = &nativeTypeDeclaration;
377 return true;
378}
379
380bool Intrinsics::addDepthTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration, AST::TypeReference& innerType)
381{
382 AST::NativeTypeDeclaration** texture;
383 if (nativeTypeDeclaration.name() == "TextureDepth2D")
384 texture = m_textureDepth2D;
385 else if (nativeTypeDeclaration.name() == "RWTextureDepth2D")
386 texture = m_rwTextureDepth2D;
387 else if (nativeTypeDeclaration.name() == "TextureDepth2DArray")
388 texture = m_textureDepth2DArray;
389 else if (nativeTypeDeclaration.name() == "RWTextureDepth2DArray")
390 texture = m_rwTextureDepth2DArray;
391 else if (nativeTypeDeclaration.name() == "TextureDepthCube")
392 texture = m_textureDepthCube;
393 else
394 ASSERT_NOT_REACHED();
395 unsigned innerTypeIndex = WTF_ARRAY_LENGTH(m_depthTextureInnerTypes);
396 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_depthTextureInnerTypes); ++i) {
397 if (innerType.name() == m_depthTextureInnerTypes[i])
398 innerTypeIndex = i;
399 }
400 ASSERT(innerTypeIndex != WTF_ARRAY_LENGTH(m_depthTextureInnerTypes));
401 nativeTypeDeclaration.setIsTexture();
402 texture[innerTypeIndex] = &nativeTypeDeclaration;
403 return true;
404}
405
406void Intrinsics::addTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration)
407{
408 ASSERT(nativeTypeDeclaration.typeArguments().size() == 1);
409 ASSERT(WTF::holds_alternative<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
410 auto& innerType = static_cast<AST::TypeReference&>(WTF::get<UniqueRef<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
411 ASSERT(!innerType.typeArguments().size());
412 if (addFullTexture(nativeTypeDeclaration, innerType)) {
413 m_textureSet.add(&nativeTypeDeclaration);
414 return;
415 }
416 if (addDepthTexture(nativeTypeDeclaration, innerType))
417 m_textureSet.add(&nativeTypeDeclaration);
418}
419
420void Intrinsics::add(AST::NativeTypeDeclaration& nativeTypeDeclaration)
421{
422 if (addPrimitive(nativeTypeDeclaration))
423 return;
424 if (addVector(nativeTypeDeclaration))
425 return;
426 if (addMatrix(nativeTypeDeclaration))
427 return;
428 addTexture(nativeTypeDeclaration);
429}
430
431} // namespace WHLSL
432
433} // namespace WebCore
434
435#endif // ENABLE(WEBGPU)
436