Changeset 236452 in webkit
- Timestamp:
- Sep 24, 2018, 9:15:06 PM (8 years ago)
- Location:
- trunk/Tools
- Files:
-
- 1 added
- 8 edited
-
ChangeLog (modified) (1 diff)
-
WebGPUShadingLanguageRI/Evaluator.js (modified) (6 diffs)
-
WebGPUShadingLanguageRI/Metal/MSLBackend.js (modified) (2 diffs)
-
WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js (modified) (1 diff)
-
WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js (modified) (1 diff)
-
WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js (modified) (1 diff)
-
WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js (added)
-
WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js (modified) (3 diffs)
-
WebGPUShadingLanguageRI/Test.js (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r236449 r236452 1 2018-09-24 Thomas Denney <tdenney@apple.com> 2 3 [WHLSL] Implement trap statements in Metal code generation 4 https://bugs.webkit.org/show_bug.cgi?id=189615 5 6 Reviewed by Myles C. Maxfield. 7 8 Each function called by an entry point now receives an additional 9 boolean pointer parameter, which is set to false if the function traps. 10 After each function call (to a non-native function) this trap parameter 11 is checked. The behavior of the interpreter has also been updated so 12 that a function entry point catches the trap and instead returns zero, 13 matching the behavior of compiled code. 14 15 * WebGPUShadingLanguageRI/Evaluator.js: Adds a new flag to allow the 16 test suite to check for traps and also returns zero from entry points 17 whose invocation trapped. 18 * WebGPUShadingLanguageRI/Metal/MSLBackend.js: Pass program to function 19 declarations. 20 * WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js: Update dependencies. 21 * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js: Add program 22 property. 23 * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js: Ditto. 24 * WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js: Added. 25 * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js: Conforms to the 26 new trapping behavior. 27 * WebGPUShadingLanguageRI/Test.js: Update tests that trap. 28 1 29 2018-09-24 Thomas Denney <tdenney@apple.com> 2 30 -
trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js
r235879 r236452 25 25 "use strict"; 26 26 27 let _lastInvocationDidTrap; 28 27 29 // This is a combined LHS/RHS evaluator that passes around EPtr's to everything. 28 30 class Evaluator extends Visitor { … … 31 33 super(); 32 34 this._program = program; 35 _lastInvocationDidTrap = false; 36 } 37 38 static lastInvocationDidTrap() 39 { 40 return lastInvocationDidTrap; 33 41 } 34 42 … … 52 60 { 53 61 return EBuffer.disallowAllocation( 54 () => this._runBody(func.returnType, func.returnEPtr, func.body ));55 } 56 57 _runBody(type, ptr, block )62 () => this._runBody(func.returnType, func.returnEPtr, func.body, func.isEntryPoint)); 63 } 64 65 _runBody(type, ptr, block, isEntryPoint) 58 66 { 59 67 if (!ptr) … … 67 75 if (e == BreakException || e == ContinueException) 68 76 throw new Error("Should not see break/continue at function scope"); 69 if (e instanceof ReturnException) { 70 let result = this._snapshot(type, ptr, e.value); 71 return result; 77 if (e instanceof ReturnException) 78 return this._snapshot(type, ptr, e.value); 79 if (e instanceof WTrapError) { 80 if (isEntryPoint) { 81 _lastInvocationDidTrap = true; 82 type.populateDefaultValue(ptr.buffer, ptr.offset); 83 return ptr; 84 } 72 85 } 73 86 throw e; … … 91 104 } 92 105 93 _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr )106 _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr, isEntryPoint) 94 107 { 95 108 const argumentValues = this._evaluateArguments(argumentList, parameterList); 96 109 for (let i = 0; i < node.argumentList.length; ++i) 97 110 parameterList[i].ePtr.copyFrom(argumentValues[i], parameterList[i].type.size); 98 return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody ));111 return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody, isEntryPoint)); 99 112 } 100 113 101 114 visitFunctionLikeBlock(node) 102 115 { 103 return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr );116 return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr, false); 104 117 } 105 118 … … 335 348 return EBuffer.allowAllocation(() => this._snapshot(node.func.returnType, node.resultEPtr, node.func.implementation(callArguments, node))); 336 349 } else 337 return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr );350 return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr, false); 338 351 } 339 352 } -
trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js
r236299 r236452 80 80 _msl() 81 81 { 82 insertTrapParameter(this.program); 83 82 84 const functionsToCompile = this._findFunctionsToCompile(); 83 85 for (let func of functionsToCompile) … … 157 159 { 158 160 for (let func of unifiedFunctionDefs) { 159 this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this. _funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));160 this._functionDefintions.push(new MSLFunctionDefinition(this. _funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));161 this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes)); 162 this._functionDefintions.push(new MSLFunctionDefinition(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes)); 161 163 } 162 164 } -
trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js
r236299 r236452 30 30 load("MSLFunctionDefinition.js"); 31 31 load("MSLFunctionForwardDeclaration.js"); 32 load("MSLInsertTrapParameter.js"); 32 33 load("MSLNameMangler.js"); 33 34 load("MSLNativeFunctionCall.js"); -
trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js
r236299 r236452 27 27 class MSLFunctionDeclaration { 28 28 29 constructor( funcMangler, funcDef, typeUnifier, typeAttributes)29 constructor(program, funcMangler, funcDef, typeUnifier, typeAttributes) 30 30 { 31 this._program = program; 31 32 this._funcMangler = funcMangler; 32 33 this._func = funcDef; 33 34 this._typeUnifier = typeUnifier; 34 35 this._typeAttributes = typeAttributes; 36 } 37 38 get program() 39 { 40 return this._program; 35 41 } 36 42 -
trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js
r236299 r236452 30 30 let src = this.commentLine() + "\n" + super.toString(); 31 31 src += "\n{\n"; 32 let emitter = new MSLStatementEmitter(this. funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes);32 let emitter = new MSLStatementEmitter(this.program, this.funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes); 33 33 src += emitter.indentedSource(); 34 34 src += "}"; -
trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js
r236299 r236452 26 26 class MSLStatementEmitter extends Visitor { 27 27 28 constructor( funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes)28 constructor(program, funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes) 29 29 { 30 30 super(); 31 this._program = program; 31 32 this._funcMangler = funcMangler; 32 33 this._typeUnifier = typeUnifier; … … 48 49 _emitTrap() 49 50 { 50 this._add('// FIXME: Handle traps.'); 51 // No need to update this if in an entry point, we can just return zero. 52 if (!this._func.isEntryPoint) 53 this._add(`*(${this._func._trapPointerExpression.visit(this)}) = false;`); 54 this._emitTrapReturn(); 55 } 56 57 _emitTrapReturn() 58 { 59 if (this._func.returnType.equals(this._program.intrinsics.void)) 60 this._add('return;'); 61 else { 62 const id = this._fresh(); 63 this._add(`${this._typeUnifier.uniqueTypeId(this._func.returnType)} ${id};`); 64 this._zeroInitialize(this._func.returnType, id); 65 this._add(`return ${id};`); 66 } 51 67 } 52 68 … … 415 431 else 416 432 this._add(`${callString};`); 433 434 this._add(`if (!(*(${this._func._trapPointerExpression.visit(this)}))) {`); 435 this._indent(() => this._emitTrapReturn()); 436 this._add("}"); 417 437 } else 418 438 this._makeNativeFunctionCall(node.func, resultVariable, args); -
trunk/Tools/WebGPUShadingLanguageRI/Test.js
r236449 r236452 315 315 } 316 316 317 function checkTrap(program, callback, checkFunction) 318 { 319 const result = callback(); 320 // FIXME: Rewrite tests so that they return non-zero values in the case that they didn't trap. 321 // The check function is optional in the case of a void return type. 322 checkFunction(program, result, 0); 323 if (!Evaluator.lastInvocationDidTrap) 324 throw new Error("Did not trap"); 325 } 326 317 327 let tests; 318 328 let okToTest = false; … … 929 939 } 930 940 `); 931 checkFail( 932 () => callFunction(program, "foo", []), 933 (e) => e instanceof WTrapError); 941 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 934 942 } 935 943 … … 943 951 } 944 952 `); 945 checkFail( 946 () => callFunction(program, "foo", []), 947 (e) => e instanceof WTrapError); 953 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 948 954 } 949 955 … … 960 966 } 961 967 `); 962 checkFail( 963 () => callFunction(program, "bar", []), 964 (e) => e instanceof WTrapError); 968 checkTrap(program, () => callFunction(program, "bar", []), checkInt); 965 969 } 966 970 … … 1007 1011 } 1008 1012 `); 1009 checkFail( 1010 () => callFunction(program, "foo", []), 1011 (e) => e instanceof WTrapError); 1013 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 1012 1014 } 1013 1015 … … 1021 1023 } 1022 1024 `); 1023 checkFail( 1024 () => callFunction(program, "foo", []), 1025 (e) => e instanceof WTrapError); 1025 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 1026 1026 } 1027 1027 … … 1035 1035 } 1036 1036 `); 1037 checkFail( 1038 () => callFunction(program, "foo", []), 1039 (e) => e instanceof WTrapError); 1037 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 1040 1038 } 1041 1039 … … 1052 1050 } 1053 1051 `); 1054 checkFail( 1055 () => callFunction(program, "bar", []), 1056 (e) => e instanceof WTrapError); 1052 checkTrap(program, () => callFunction(program, "bar", []), checkInt); 1057 1053 } 1058 1054 … … 2502 2498 src += " int i = 0;\n"; 2503 2499 let target = 0; 2504 const numVars = 1024;2500 const numVars = 50; 2505 2501 for (let i = 0; i < numVars; i++) { 2506 2502 const value = i * 3; … … 3881 3877 } 3882 3878 `); 3883 checkFail( 3884 () => callFunction(program, "foo", []), 3885 e => e instanceof WTrapError); 3879 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 3886 3880 checkInt(program, callFunction(program, "foo2", [makeInt(program, 1)]), 4); 3887 checkFail( 3888 () => callFunction(program, "foo2", [makeInt(program, 3)]), 3889 e => e instanceof WTrapError); 3890 checkFail( 3891 () => callFunction(program, "foo3", []), 3892 e => e instanceof WTrapError); 3881 checkTrap(program, () => callFunction(program, "foo2", [makeInt(program, 3)]), checkInt); 3882 checkTrap(program, () => callFunction(program, "foo3", []), (progam, result, expected) => { 3883 for (let i = 0; i < 4; i++) { 3884 if (result.ePtr.get(i) != expected) 3885 throw new Error(`Non-zero return value at offset ${i}`); 3886 } 3887 }); 3893 3888 } 3894 3889 … … 4652 4647 } 4653 4648 `); 4654 checkFail( 4655 () => checkInt(program, callFunction(program, "foo", []), -511), 4656 e => e instanceof WTrapError); 4649 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 4657 4650 } 4658 4651 … … 6347 6340 6348 6341 program = doPrep(` 6349 test voidfoo() {6342 test int foo() { 6350 6343 thread atomic_int* x = null; 6351 6344 InterlockedAdd(x, 1, null); 6352 } 6353 `); 6354 checkFail( 6355 () => callFunction(program, "foo", []), 6356 (e) => e instanceof WTrapError); 6345 return 1; 6346 } 6347 `); 6348 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6357 6349 6358 6350 program = doPrep(` 6359 test voidfoo() {6351 test int foo() { 6360 6352 thread atomic_uint* x = null; 6361 6353 InterlockedAdd(x, 1, null); 6362 } 6363 `); 6364 checkFail( 6365 () => callFunction(program, "foo", []), 6366 (e) => e instanceof WTrapError); 6354 return 1; 6355 } 6356 `); 6357 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6367 6358 6368 6359 program = doPrep(` 6369 test voidfoo() {6360 test int foo() { 6370 6361 thread atomic_int* x = null; 6371 6362 InterlockedAnd(x, 1, null); 6372 } 6373 `); 6374 checkFail( 6375 () => callFunction(program, "foo", []), 6376 (e) => e instanceof WTrapError); 6363 return 1; 6364 } 6365 `); 6366 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6377 6367 6378 6368 program = doPrep(` 6379 test voidfoo() {6369 test int foo() { 6380 6370 thread atomic_uint* x = null; 6381 6371 InterlockedAnd(x, 1, null); 6382 } 6383 `); 6384 checkFail( 6385 () => callFunction(program, "foo", []), 6386 (e) => e instanceof WTrapError); 6372 return 1; 6373 } 6374 `); 6375 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6387 6376 6388 6377 program = doPrep(` 6389 test voidfoo() {6378 test int foo() { 6390 6379 thread atomic_int* x = null; 6391 6380 InterlockedExchange(x, 1, null); 6392 } 6393 `); 6394 checkFail( 6395 () => callFunction(program, "foo", []), 6396 (e) => e instanceof WTrapError); 6381 return 1; 6382 } 6383 `); 6384 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6397 6385 6398 6386 program = doPrep(` 6399 test voidfoo() {6387 test int foo() { 6400 6388 thread atomic_uint* x = null; 6401 6389 InterlockedExchange(x, 1, null); 6402 } 6403 `); 6404 checkFail( 6405 () => callFunction(program, "foo", []), 6406 (e) => e instanceof WTrapError); 6390 return 1; 6391 } 6392 `); 6393 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6407 6394 6408 6395 program = doPrep(` 6409 test voidfoo() {6396 test int foo() { 6410 6397 thread atomic_int* x = null; 6411 6398 InterlockedMax(x, 1, null); 6412 } 6413 `); 6414 checkFail( 6415 () => callFunction(program, "foo", []), 6416 (e) => e instanceof WTrapError); 6399 return 1; 6400 } 6401 `); 6402 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6417 6403 6418 6404 program = doPrep(` 6419 test voidfoo() {6405 test int foo() { 6420 6406 thread atomic_uint* x = null; 6421 6407 InterlockedMax(x, 1, null); 6422 } 6423 `); 6424 checkFail( 6425 () => callFunction(program, "foo", []), 6426 (e) => e instanceof WTrapError); 6408 return 1; 6409 } 6410 `); 6411 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6427 6412 6428 6413 program = doPrep(` 6429 test voidfoo() {6414 test int foo() { 6430 6415 thread atomic_int* x = null; 6431 6416 InterlockedMin(x, 1, null); 6432 } 6433 `); 6434 checkFail( 6435 () => callFunction(program, "foo", []), 6436 (e) => e instanceof WTrapError); 6417 return 1; 6418 } 6419 `); 6420 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6437 6421 6438 6422 program = doPrep(` 6439 test voidfoo() {6423 test int foo() { 6440 6424 thread atomic_uint* x = null; 6441 6425 InterlockedMin(x, 1, null); 6442 } 6443 `); 6444 checkFail( 6445 () => callFunction(program, "foo", []), 6446 (e) => e instanceof WTrapError); 6426 return 1; 6427 } 6428 `); 6429 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6447 6430 6448 6431 program = doPrep(` 6449 test voidfoo() {6432 test int foo() { 6450 6433 thread atomic_int* x = null; 6451 6434 InterlockedOr(x, 1, null); 6452 } 6453 `); 6454 checkFail( 6455 () => callFunction(program, "foo", []), 6456 (e) => e instanceof WTrapError); 6435 return 1; 6436 } 6437 `); 6438 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6457 6439 6458 6440 program = doPrep(` 6459 test voidfoo() {6441 test int foo() { 6460 6442 thread atomic_uint* x = null; 6461 6443 InterlockedOr(x, 1, null); 6462 } 6463 `); 6464 checkFail( 6465 () => callFunction(program, "foo", []), 6466 (e) => e instanceof WTrapError); 6444 return 1; 6445 } 6446 `); 6447 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6467 6448 6468 6449 program = doPrep(` 6469 test voidfoo() {6450 test int foo() { 6470 6451 thread atomic_int* x = null; 6471 6452 InterlockedXor(x, 1, null); 6472 } 6473 `); 6474 checkFail( 6475 () => callFunction(program, "foo", []), 6476 (e) => e instanceof WTrapError); 6453 return 1; 6454 } 6455 `); 6456 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6477 6457 6478 6458 program = doPrep(` 6479 test voidfoo() {6459 test int foo() { 6480 6460 thread atomic_uint* x = null; 6481 6461 InterlockedXor(x, 1, null); 6482 } 6483 `); 6484 checkFail( 6485 () => callFunction(program, "foo", []), 6486 (e) => e instanceof WTrapError); 6462 return 1; 6463 } 6464 `); 6465 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6487 6466 6488 6467 program = doPrep(` 6489 test voidfoo() {6468 test int foo() { 6490 6469 thread atomic_int* x = null; 6491 6470 InterlockedCompareExchange(x, 1, 2, null); 6492 } 6493 `); 6494 checkFail( 6495 () => callFunction(program, "foo", []), 6496 (e) => e instanceof WTrapError); 6471 return 1; 6472 } 6473 `); 6474 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6497 6475 6498 6476 program = doPrep(` 6499 test voidfoo() {6477 test int foo() { 6500 6478 thread atomic_uint* x = null; 6501 6479 InterlockedCompareExchange(x, 1, 2, null); 6502 } 6503 `); 6504 checkFail( 6505 () => callFunction(program, "foo", []), 6506 (e) => e instanceof WTrapError); 6480 return 1; 6481 } 6482 `); 6483 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 6507 6484 } 6508 6485 … … 9156 9133 }; 9157 9134 9135 tests.passingArrayToFunction = function() 9136 { 9137 let program = doPrep(` 9138 test int foo() 9139 { 9140 int[10] arr; 9141 for (uint i = 0; i < arr.length; i++) 9142 arr[i] = int(i) + 1; 9143 return sum(arr); 9144 } 9145 9146 int sum(int[10] xs) 9147 { 9148 int t = 0; 9149 for (uint i = 0; i < xs.length; i++) 9150 t = t + xs[i]; 9151 return t; 9152 } 9153 `); 9154 checkInt(program, callFunction(program, "foo", []), 55); 9155 } 9156 9157 tests.returnAnArrayFromAFunction = function() 9158 { 9159 let program = doPrep(` 9160 test int foo() 9161 { 9162 int[5] ys = bar(); 9163 return ys[0] + ys[1] + ys[2] + ys[3] + ys[4]; 9164 } 9165 9166 int[5] bar() 9167 { 9168 int[5] xs; 9169 xs[0] = 1; 9170 xs[1] = 2; 9171 xs[2] = 3; 9172 xs[3] = 4; 9173 xs[4] = 5; 9174 return xs; 9175 } 9176 `); 9177 } 9178 9179 tests.copyArray = function() 9180 { 9181 let program = doPrep(` 9182 test int foo() 9183 { 9184 int[10] xs; 9185 for (uint i = 0; i < xs.length; i++) 9186 xs[i] = int(i) + 1; 9187 int[10] ys = xs; 9188 for (uint i = 0; i < xs.length; i++) 9189 xs[i] = 0; 9190 int sum = 0; 9191 for (uint i = 0; i < ys.length; i++) 9192 sum = sum + ys[i]; 9193 return sum; 9194 } 9195 `); 9196 checkInt(program, callFunction(program, "foo", []), 55); 9197 } 9198 9199 tests.settingAnArrayInsideAStruct = function() 9200 { 9201 let program = doPrep(` 9202 struct Foo { 9203 int[1] array; 9204 } 9205 test int foo() 9206 { 9207 Foo foo; 9208 thread Foo* bar = &foo; 9209 bar->array[0] = 21; 9210 return foo.array[0]; 9211 } 9212 `); 9213 checkInt(program, callFunction(program, "foo", []), 21); 9214 } 9215 9216 tests.trapBecauseOfIndexAcesss = () => { 9217 const program = doPrep(` 9218 test int foo() 9219 { 9220 int[5] array; 9221 array[6] = 42; 9222 return array[6]; 9223 } 9224 `); 9225 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 9226 } 9227 9228 tests.trapTransitively = () => { 9229 const program = doPrep(` 9230 test int foo() 9231 { 9232 willTrapTransitively(); 9233 return 42; 9234 } 9235 9236 void willTrapTransitively() 9237 { 9238 doTrap(); 9239 } 9240 9241 void doTrap() 9242 { 9243 trap; 9244 } 9245 `); 9246 checkTrap(program, () => callFunction(program, "foo", []), checkInt); 9247 }; 9248 9158 9249 okToTest = true; 9159 9250
Note:
See TracChangeset
for help on using the changeset viewer.