WSL needs float and double support
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / Intrinsics.js
1 /*
2  * Copyright (C) 2017 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 class Intrinsics {
28     constructor(nameContext)
29     {
30         this.primitive = new ProtocolDecl(null, "primitive");
31         this.primitive.isPrimitive = true;
32         nameContext.add(this.primitive);
33         
34         this._map = new Map();
35
36         // NOTE: Intrinsic resolution happens before type name resolution, so the strings we use here
37         // to catch the intrinsics must be based on the type names that StandardLibraryPrologue.js uses.
38         // For example, if a native function is declared using "int" rather than "int32", then we must
39         // use "int" here, since we don't yet know that they are the same type.
40         
41         this._map.set(
42             "native primitive type void<>",
43             type => {
44                 this.void = type;
45                 type.size = 0;
46                 type.populateDefaultValue = () => { };
47             });
48         
49         function isBitwiseEquivalent(left, right)
50         {
51             let doubleArray = new Float64Array(1);
52             let intArray = new Int32Array(doubleArray.buffer);
53             doubleArray[0] = left;
54             let leftInts = Int32Array.from(intArray);
55             doubleArray[0] = right;
56             for (let i = 0; i < 2; ++i) {
57                 if (leftInts[i] != intArray[i])
58                     return false;
59             }
60             return true;
61         }
62
63         this._map.set(
64             "native primitive type int32<>",
65             type => {
66                 this.int32 = type;
67                 type.isInt = true;
68                 type.isNumber = true;
69                 type.isSigned = true;
70                 type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
71                 type.size = 1;
72                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
73             });
74
75         this._map.set(
76             "native primitive type uint32<>",
77             type => {
78                 this.uint32 = type;
79                 type.isInt = true;
80                 type.isNumber = true;
81                 type.isSigned = false;
82                 type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
83                 type.size = 1;
84                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
85             });
86
87         this._map.set(
88             "native primitive type float<>",
89             type => {
90                 this.float = type;
91                 type.size = 1;
92                 type.isFloating = true;
93                 type.isNumber = true;
94                 type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
95                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
96             });
97
98         this._map.set(
99             "native primitive type double<>",
100             type => {
101                 this.double = type;
102                 type.size = 1;
103                 type.isFloating = true;
104                 type.isNumber = true;
105                 type.canRepresent = value => true;
106                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
107             });
108
109         this._map.set(
110             "native primitive type bool<>",
111             type => {
112                 this.bool = type;
113                 type.size = 1;
114                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
115             });
116         
117         this._map.set(
118             "native operator int32<>(uint32)",
119             func => {
120                 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
121             });
122         
123         this._map.set(
124             "native operator uint32<>(int32)",
125             func => {
126                 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
127             });
128         
129         this._map.set(
130             "native operator float<>(double)",
131             func => {
132                 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
133             });
134         
135         this._map.set(
136             "native operator double<>(float)",
137             func => {
138                 func.implementation = ([value]) => EPtr.box(value.loadValue());
139             });
140         
141         this._map.set(
142             "native int operator+<>(int,int)",
143             func => {
144                 func.implementation = ([left, right]) =>
145                     EPtr.box((left.loadValue() + right.loadValue()) | 0);
146             });
147         
148         this._map.set(
149             "native uint operator+<>(uint,uint)",
150             func => {
151                 func.implementation = ([left, right]) =>
152                     EPtr.box((left.loadValue() + right.loadValue()) >>> 0);
153             });
154         
155         this._map.set(
156             "native float operator+<>(float,float)",
157             func => {
158                 func.implementation = ([left, right]) =>
159                     EPtr.box(Math.fround(left.loadValue() + right.loadValue()));
160             });
161         
162         this._map.set(
163             "native double operator+<>(double,double)",
164             func => {
165                 func.implementation = ([left, right]) =>
166                     EPtr.box(left.loadValue() + right.loadValue());
167             });
168         
169         this._map.set(
170             "native int operator-<>(int,int)",
171             func => {
172                 func.implementation = ([left, right]) =>
173                     EPtr.box((left.loadValue() - right.loadValue()) | 0);
174             });
175         
176         this._map.set(
177             "native uint operator-<>(uint,uint)",
178             func => {
179                 func.implementation = ([left, right]) =>
180                     EPtr.box((left.loadValue() - right.loadValue()) >>> 0);
181             });
182         
183         this._map.set(
184             "native float operator-<>(float,float)",
185             func => {
186                 func.implementation = ([left, right]) =>
187                     EPtr.box(Math.fround(left.loadValue() - right.loadValue()));
188             });
189         
190         this._map.set(
191             "native double operator-<>(double,double)",
192             func => {
193                 func.implementation = ([left, right]) =>
194                     EPtr.box(left.loadValue() - right.loadValue());
195             });
196         
197         this._map.set(
198             "native int operator*<>(int,int)",
199             func => {
200                 func.implementation = ([left, right]) =>
201                     EPtr.box((left.loadValue() * right.loadValue()) | 0);
202             });
203         
204         this._map.set(
205             "native uint operator*<>(uint,uint)",
206             func => {
207                 func.implementation = ([left, right]) =>
208                     EPtr.box((left.loadValue() * right.loadValue()) >>> 0);
209             });
210         
211         this._map.set(
212             "native float operator*<>(float,float)",
213             func => {
214                 func.implementation = ([left, right]) =>
215                     EPtr.box(Math.fround(left.loadValue() * right.loadValue()));
216             });
217         
218         this._map.set(
219             "native double operator*<>(double,double)",
220             func => {
221                 func.implementation = ([left, right]) =>
222                     EPtr.box(left.loadValue() * right.loadValue());
223             });
224         
225         this._map.set(
226             "native int operator/<>(int,int)",
227             func => {
228                 func.implementation = ([left, right]) =>
229                     EPtr.box((left.loadValue() / right.loadValue()) | 0);
230             });
231         
232         this._map.set(
233             "native uint operator/<>(uint,uint)",
234             func => {
235                 func.implementation = ([left, right]) =>
236                     EPtr.box((left.loadValue() / right.loadValue()) >>> 0);
237             });
238         
239         this._map.set(
240             "native float operator/<>(float,float)",
241             func => {
242                 func.implementation = ([left, right]) =>
243                     EPtr.box(Math.fround(left.loadValue() / right.loadValue()));
244             });
245         
246         this._map.set(
247             "native double operator/<>(double,double)",
248             func => {
249                 func.implementation = ([left, right]) =>
250                     EPtr.box(left.loadValue() / right.loadValue());
251             });
252         
253         this._map.set(
254             "native bool operator==<>(int,int)",
255             func => {
256                 func.implementation = ([left, right]) =>
257                     EPtr.box(left.loadValue() == right.loadValue());
258             });
259         
260         this._map.set(
261             "native bool operator==<>(uint,uint)",
262             func => {
263                 func.implementation = ([left, right]) =>
264                     EPtr.box(left.loadValue() == right.loadValue());
265             });
266         
267         this._map.set(
268             "native bool operator==<>(bool,bool)",
269             func => {
270                 func.implementation = ([left, right]) =>
271                     EPtr.box(left.loadValue() == right.loadValue());
272             });
273         
274         this._map.set(
275             "native bool operator==<>(float,float)",
276             func => {
277                 func.implementation = ([left, right]) =>
278                     EPtr.box(left.loadValue() == right.loadValue());
279             });
280         
281         this._map.set(
282             "native bool operator==<>(double,double)",
283             func => {
284                 func.implementation = ([left, right]) =>
285                     EPtr.box(left.loadValue() == right.loadValue());
286             });
287         
288         this._map.set(
289             "native bool operator<<>(int,int)",
290             func => {
291                 func.implementation = ([left, right]) =>
292                     EPtr.box(left.loadValue() < right.loadValue());
293             });
294         
295         this._map.set(
296             "native bool operator<<>(uint,uint)",
297             func => {
298                 func.implementation = ([left, right]) =>
299                     EPtr.box(left.loadValue() < right.loadValue());
300             });
301         
302         this._map.set(
303             "native bool operator<<>(float,float)",
304             func => {
305                 func.implementation = ([left, right]) =>
306                     EPtr.box(left.loadValue() < right.loadValue());
307             });
308         
309         this._map.set(
310             "native bool operator<<>(double,double)",
311             func => {
312                 func.implementation = ([left, right]) =>
313                     EPtr.box(left.loadValue() < right.loadValue());
314             });
315         
316         this._map.set(
317             "native bool operator<=<>(int,int)",
318             func => {
319                 func.implementation = ([left, right]) =>
320                     EPtr.box(left.loadValue() <= right.loadValue());
321             });
322         
323         this._map.set(
324             "native bool operator<=<>(uint,uint)",
325             func => {
326                 func.implementation = ([left, right]) =>
327                     EPtr.box(left.loadValue() <= right.loadValue());
328             });
329         
330         this._map.set(
331             "native bool operator<=<>(float,float)",
332             func => {
333                 func.implementation = ([left, right]) =>
334                     EPtr.box(left.loadValue() <= right.loadValue());
335             });
336         
337         this._map.set(
338             "native bool operator<=<>(double,double)",
339             func => {
340                 func.implementation = ([left, right]) =>
341                     EPtr.box(left.loadValue() <= right.loadValue());
342             });
343         
344         this._map.set(
345             "native bool operator><>(int,int)",
346             func => {
347                 func.implementation = ([left, right]) =>
348                     EPtr.box(left.loadValue() > right.loadValue());
349             });
350         
351         this._map.set(
352             "native bool operator><>(uint,uint)",
353             func => {
354                 func.implementation = ([left, right]) =>
355                     EPtr.box(left.loadValue() > right.loadValue());
356             });
357         
358         this._map.set(
359             "native bool operator><>(float,float)",
360             func => {
361                 func.implementation = ([left, right]) =>
362                     EPtr.box(left.loadValue() > right.loadValue());
363             });
364         
365         this._map.set(
366             "native bool operator><>(double,double)",
367             func => {
368                 func.implementation = ([left, right]) =>
369                     EPtr.box(left.loadValue() > right.loadValue());
370             });
371         
372         this._map.set(
373             "native bool operator>=<>(int,int)",
374             func => {
375                 func.implementation = ([left, right]) =>
376                     EPtr.box(left.loadValue() >= right.loadValue());
377             });
378         
379         this._map.set(
380             "native bool operator>=<>(uint,uint)",
381             func => {
382                 func.implementation = ([left, right]) =>
383                     EPtr.box(left.loadValue() >= right.loadValue());
384             });
385         
386         this._map.set(
387             "native bool operator>=<>(float,float)",
388             func => {
389                 func.implementation = ([left, right]) =>
390                     EPtr.box(left.loadValue() >= right.loadValue());
391             });
392         
393         this._map.set(
394             "native bool operator>=<>(double,double)",
395             func => {
396                 func.implementation = ([left, right]) =>
397                     EPtr.box(left.loadValue() >= right.loadValue());
398             });
399         
400         let arrayElementPtr = func => {
401             func.implementation = ([ref, index], node) => {
402                 ref = ref.loadValue();
403                 if (!ref)
404                     throw new WTrapError(node.origin.originString, "Null dereference");
405                 index = index.loadValue();
406                 if (index > ref.length)
407                     throw new WTrapError(node.origin.originString, "Array index " + index + " is out of bounds of " + ref);
408                 return EPtr.box(ref.ptr.plus(index * node.actualTypeArguments[0].size));
409             };
410         };
411         
412         this._map.set(
413             "native T^ thread operator&[]<T>(T[] thread,uint)",
414             arrayElementPtr);
415         this._map.set(
416             "native T^ threadgroup operator&[]<T:primitive>(T[] threadgroup,uint)",
417             arrayElementPtr);
418         this._map.set(
419             "native T^ device operator&[]<T:primitive>(T[] device,uint)",
420             arrayElementPtr);
421         this._map.set(
422             "native T^ constant operator&[]<T:primitive>(T[] constant,uint)",
423             arrayElementPtr);
424     }
425     
426     add(thing)
427     {
428         let intrinsic = this._map.get(thing.toString());
429         if (!intrinsic)
430             throw new WTypeError(thing.origin.originString, "Unrecognized intrinsic: " + thing);
431         intrinsic(thing);
432     }
433 }
434