Changeset 223246 in webkit
- Timestamp:
- Oct 12, 2017 11:45:04 AM (7 years ago)
- Location:
- trunk/Tools
- Files:
-
- 3 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r223239 r223246 1 2017-10-12 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Emit SPIR-V from WSL compiler (Part 1) 4 https://bugs.webkit.org/show_bug.cgi?id=177998 5 6 Reviewed by Filip Pizlo. 7 8 This patch implements the first half of a SPIR-V codegen phase for WSL. 9 This includes all the operations which aren't actually emitting the contents 10 of functions themselves. For example, this includes things like representing 11 WSL types with SPIR-V types, and declaring shaders' inputs and outputs. A 12 future patch will actually emit the contents of functions. 13 14 There are two helper visitors here: SPIRVTypeAnalyzer which generates SPIR-V 15 types from WSL types, and SPIRVPrimitiveVariableAnalyzer which identifies 16 input and output variables from a shader (and assigns location values to 17 each one). 18 19 This patch is currently pursuing the "logical mode" detailed in 20 https://bugs.webkit.org/show_bug.cgi?id=176967. In this mode, each pointer and 21 array reference operation can be statically traced to the variable or array it 22 is operating on. 23 24 This has the interesting property where accessing a pointer inside an array is 25 forbidden, because the array index may be computed at runtime, so the compiler 26 can't know at compile time which variable the pointer operation will be 27 accessing. However, this isn't true for structs; the program must statically 28 state which struct member it is accessing. Therefore, pointers or array 29 references must not transitively appear within an array, but they may appear 30 within a struct. The same logic applies to array references; those get lowered 31 to just two indexes in SPIR-V (a lower bound and an upper bound). 32 33 So, outside of an array, SPIR-V types don't need to include any pointers because 34 any operation with the pointer doesn't need access to the runtime value of the 35 pointer. Inside of an array, pointers are forbidden. Therefore, SPIR-V types 36 will never include any pointers. 37 38 This means that, for example, WSL can represent a linked list in logical mode. 39 However, a WSL program cannot iterate across the list, because that would require 40 assigning to a pointer. So instead, a program using a linked list could only say 41 something like "list.ptr->ptr->ptr->value". 42 43 * WebGPUShadingLanguageRI/LateChecker.js: 44 (LateChecker.prototype._checkShaderType): 45 * WebGPUShadingLanguageRI/SPIR-V.js: 46 (SPIRV.OperandChecker.prototype._isStar): 47 (SPIRV.OperandChecker.prototype.nextComparisonType): 48 (SPIRV.OperandChecker.prototype.finalize): 49 (SPIRV.OperandChecker): 50 * WebGPUShadingLanguageRI/SPIRV.html: 51 * WebGPUShadingLanguageRI/SPIRVCodegen.js: Added. 52 (findEntryPoints): 53 (emitTypes.doEmitTypes): 54 (emitTypes): 55 (ConstantFinder.prototype.visitGenericLiteralType): 56 (ConstantFinder): 57 (generateSPIRV): 58 * WebGPUShadingLanguageRI/SPIRVTypeAnalyzer.js: Added. 59 (SPIRVTypeAnalyzer): 60 (SPIRVTypeAnalyzer.prototype.get program): 61 (SPIRVTypeAnalyzer.prototype.get typeMap): 62 (SPIRVTypeAnalyzer.prototype.get currentId): 63 (SPIRVTypeAnalyzer.prototype.get stack): 64 (SPIRVTypeAnalyzer.prototype.visitTypeRef): 65 (SPIRVTypeAnalyzer.prototype._encounterType): 66 (SPIRVTypeAnalyzer.prototype.visitNullType): 67 (SPIRVTypeAnalyzer.prototype.visitGenericLiteralType): 68 (SPIRVTypeAnalyzer.prototype.visitNativeType): 69 (SPIRVTypeAnalyzer.prototype.visitEnumType): 70 (SPIRVTypeAnalyzer.prototype.visitPtrType): 71 (SPIRVTypeAnalyzer.prototype.visitArrayRefType): 72 (SPIRVTypeAnalyzer.prototype.visitArrayType): 73 (SPIRVTypeAnalyzer.prototype.visitStructType): 74 * WebGPUShadingLanguageRI/SPIRVVariableAnalyzer.js: Added. 75 (SPIRVPrimitiveVariableAnalyzer): 76 (SPIRVPrimitiveVariableAnalyzer.prototype.get program): 77 (SPIRVPrimitiveVariableAnalyzer.prototype.get typeMap): 78 (SPIRVPrimitiveVariableAnalyzer.prototype.get currentId): 79 (SPIRVPrimitiveVariableAnalyzer.prototype.get currentLocation): 80 (SPIRVPrimitiveVariableAnalyzer.prototype.get nameComponents): 81 (SPIRVPrimitiveVariableAnalyzer.prototype.get result): 82 (SPIRVPrimitiveVariableAnalyzer.prototype.visitTypeRef): 83 (SPIRVPrimitiveVariableAnalyzer.prototype.visitNullType): 84 (SPIRVPrimitiveVariableAnalyzer.prototype.visitGenericLiteralType): 85 (SPIRVPrimitiveVariableAnalyzer.prototype.visitNativeType): 86 (SPIRVPrimitiveVariableAnalyzer.prototype.visitEnumType): 87 (SPIRVPrimitiveVariableAnalyzer.prototype.visitPtrType): 88 (SPIRVPrimitiveVariableAnalyzer.prototype.visitArrayRefType): 89 (SPIRVPrimitiveVariableAnalyzer.prototype.visitArrayType): 90 (SPIRVPrimitiveVariableAnalyzer.prototype.visitStructType): 91 * WebGPUShadingLanguageRI/WSL.md: 92 * WebGPUShadingLanguageRI/index.html: 93 1 94 2017-09-29 Filip Pizlo <fpizlo@apple.com> 2 95 -
trunk/Tools/WebGPUShadingLanguageRI/LateChecker.js
r222413 r223246 37 37 _checkShaderType(node) 38 38 { 39 // FIXME: Tighten these checks. For now, we should only accept int32, uint32, float32, and float64. 39 40 let assertPrimitive = type => { 40 41 if (!type.isPrimitive) -
trunk/Tools/WebGPUShadingLanguageRI/SPIR-V.js
r222825 r223246 39 39 case "BitEnum": 40 40 case "ValueEnum": 41 let enumerants = { };41 let enumerants = { category: kind.category }; 42 42 for (let enumerant of kind.enumerants) { 43 43 enumerants[enumerant.enumerant] = enumerant; … … 113 113 } 114 114 115 nextComparisonType(operand) 116 { 117 if (this._operandInfoIndex >= this._operandInfos.length) 118 throw new Error("Specified operand does not correspond to any that the instruction expects."); 119 let operandInfo = this._operandInfos[this._operandInfoIndex]; 120 121 let isStar = operandInfo.quantifier && operandInfo.quantifier == "*"; 115 _isStar(operandInfo) 116 { 122 117 switch (operandInfo.kind) { 123 118 case "LiteralContextDependentNumber": 124 119 case "LiteralSpecConstantOpInteger": 125 120 // These types can be any width. 126 isStar = true; 127 break; 128 } 121 return true; 122 } 123 return operandInfo.quantifier && operandInfo.quantifier == "*"; 124 } 125 126 nextComparisonType(operand) 127 { 128 if (this._operandInfoIndex >= this._operandInfos.length) 129 throw new Error("Specified operand does not correspond to any that the instruction expects."); 130 let operandInfo = this._operandInfos[this._operandInfoIndex]; 131 132 let isStar = this._isStar(operandInfo); 129 133 130 134 if (this._parameters.length != 0) { … … 177 181 throw new Error("Operand not specified for parameter."); 178 182 for (let i = this._operandInfoIndex; i < this._operandInfos.length; ++i) { 179 let quantifier = this._operandInfos[i].quantifier; 180 if (quantifier != "?" && quantifier != "*") 183 let operandInfo = this._operandInfos[i]; 184 let quantifier = operandInfo.quantifier; 185 if (quantifier != "?" && !this._isStar(operandInfo)) 181 186 throw new Error("Did not specify operand " + i + " to instruction."); 182 187 } … … 191 196 constructor(...operands) 192 197 { 193 // FIXME: Handle OpConstant, OpSpecConstant, OpSpecConstantOp specially.194 198 let operandChecker = new OperandChecker(instruction.operands); 195 199 for (let operand of operands) -
trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html
r222825 r223246 2 2 <html> 3 3 <head> 4 <script src="SPIR-V.js"></script> 4 <style> 5 td { 6 border: solid black 1px; 7 } 8 </style> 9 <!-- FIXME: Migrate to ES6 modules --> 10 <script src="Node.js"></script> 11 <script src="Type.js"></script> 12 <script src="ReferenceType.js"></script> 13 <script src="Value.js"></script> 14 <script src="Expression.js"></script> 15 <script src="Rewriter.js"></script> 16 <script src="Visitor.js"></script> 17 <script src="CreateLiteral.js"></script> 18 <script src="CreateLiteralType.js"></script> 19 <script src="PropertyAccessExpression.js"></script> 20 21 <script src="AddressSpace.js"></script> 22 <script src="AnonymousVariable.js"></script> 23 <script src="ArrayRefType.js"></script> 24 <script src="ArrayType.js"></script> 25 <script src="Assignment.js"></script> 26 <script src="AutoWrapper.js"></script> 27 <script src="Block.js"></script> 28 <script src="BoolLiteral.js"></script> 29 <script src="Break.js"></script> 30 <script src="CallExpression.js"></script> 31 <script src="CallFunction.js"></script> 32 <script src="Check.js"></script> 33 <script src="CheckLiteralTypes.js"></script> 34 <script src="CheckLoops.js"></script> 35 <script src="CheckRecursion.js"></script> 36 <script src="CheckRecursiveTypes.js"></script> 37 <script src="CheckReturns.js"></script> 38 <script src="CheckUnreachableCode.js"></script> 39 <script src="CheckWrapped.js"></script> 40 <script src="Checker.js"></script> 41 <script src="CloneProgram.js"></script> 42 <script src="CommaExpression.js"></script> 43 <script src="ConstexprFolder.js"></script> 44 <script src="ConstexprTypeParameter.js"></script> 45 <script src="Continue.js"></script> 46 <script src="ConvertPtrToArrayRefExpression.js"></script> 47 <script src="DoWhileLoop.js"></script> 48 <script src="DotExpression.js"></script> 49 <script src="DoubleLiteral.js"></script> 50 <script src="DoubleLiteralType.js"></script> 51 <script src="DereferenceExpression.js"></script> 52 <script src="EArrayRef.js"></script> 53 <script src="EBuffer.js"></script> 54 <script src="EBufferBuilder.js"></script> 55 <script src="EPtr.js"></script> 56 <script src="EnumLiteral.js"></script> 57 <script src="EnumMember.js"></script> 58 <script src="EnumType.js"></script> 59 <script src="EvaluationCommon.js"></script> 60 <script src="Evaluator.js"></script> 61 <script src="ExpressionFinder.js"></script> 62 <script src="ExternalOrigin.js"></script> 63 <script src="Field.js"></script> 64 <script src="FindHighZombies.js"></script> 65 <script src="FlattenProtocolExtends.js"></script> 66 <script src="FlattenedStructOffsetGatherer.js"></script> 67 <script src="FloatLiteral.js"></script> 68 <script src="FloatLiteralType.js"></script> 69 <script src="FoldConstexprs.js"></script> 70 <script src="ForLoop.js"></script> 71 <script src="Func.js"></script> 72 <script src="FuncDef.js"></script> 73 <script src="FuncInstantiator.js"></script> 74 <script src="FuncParameter.js"></script> 75 <script src="FunctionLikeBlock.js"></script> 76 <script src="HighZombieFinder.js"></script> 77 <script src="IdentityExpression.js"></script> 78 <script src="IfStatement.js"></script> 79 <script src="IndexExpression.js"></script> 80 <script src="InferTypesForCall.js"></script> 81 <script src="Inline.js"></script> 82 <script src="Inliner.js"></script> 83 <script src="InstantiateImmediates.js"></script> 84 <script src="IntLiteral.js"></script> 85 <script src="IntLiteralType.js"></script> 86 <script src="Intrinsics.js"></script> 87 <script src="LateChecker.js"></script> 88 <script src="Lexer.js"></script> 89 <script src="LexerToken.js"></script> 90 <script src="LiteralTypeChecker.js"></script> 91 <script src="LogicalExpression.js"></script> 92 <script src="LogicalNot.js"></script> 93 <script src="LoopChecker.js"></script> 94 <script src="MakeArrayRefExpression.js"></script> 95 <script src="MakePtrExpression.js"></script> 96 <script src="NameContext.js"></script> 97 <script src="NameFinder.js"></script> 98 <script src="NameResolver.js"></script> 99 <script src="NativeFunc.js"></script> 100 <script src="NativeFuncInstance.js"></script> 101 <script src="NativeType.js"></script> 102 <script src="NativeTypeInstance.js"></script> 103 <script src="NormalUsePropertyResolver.js"></script> 104 <script src="NullLiteral.js"></script> 105 <script src="NullType.js"></script> 106 <script src="OriginKind.js"></script> 107 <script src="OverloadResolutionFailure.js"></script> 108 <script src="Parse.js"></script> 109 <script src="Prepare.js"></script> 110 <script src="PropertyResolver.js"></script> 111 <script src="Program.js"></script> 112 <script src="ProgramWithUnnecessaryThingsRemoved.js"></script> 113 <script src="Protocol.js"></script> 114 <script src="ProtocolDecl.js"></script> 115 <script src="ProtocolFuncDecl.js"></script> 116 <script src="ProtocolRef.js"></script> 117 <script src="PtrType.js"></script> 118 <script src="ReadModifyWriteExpression.js"></script> 119 <script src="RecursionChecker.js"></script> 120 <script src="RecursiveTypeChecker.js"></script> 121 <script src="ResolveNames.js"></script> 122 <script src="ResolveOverloadImpl.js"></script> 123 <script src="ResolveProperties.js"></script> 124 <script src="ResolveTypeDefs.js"></script> 125 <script src="Return.js"></script> 126 <script src="ReturnChecker.js"></script> 127 <script src="ReturnException.js"></script> 128 <script src="SPIR-V.js"></script> 129 <script src="SPIRVCodegen.js"></script> 130 <script src="SPIRVTypeAnalyzer.js"></script> 131 <script src="SPIRVVariableAnalyzer.js"></script> 132 <script src="StandardLibrary.js"></script> 133 <script src="StatementCloner.js"></script> 134 <script src="StructLayoutBuilder.js"></script> 135 <script src="StructType.js"></script> 136 <script src="Substitution.js"></script> 137 <script src="SwitchCase.js"></script> 138 <script src="SwitchStatement.js"></script> 139 <script src="SynthesizeEnumFunctions.js"></script> 140 <script src="SynthesizeStructAccessors.js"></script> 141 <script src="TrapStatement.js"></script> 142 <script src="TypeDef.js"></script> 143 <script src="TypeDefResolver.js"></script> 144 <script src="TypeOrVariableRef.js"></script> 145 <script src="TypeParameterRewriter.js"></script> 146 <script src="TypeRef.js"></script> 147 <script src="TypeVariable.js"></script> 148 <script src="TypeVariableTracker.js"></script> 149 <script src="TypedValue.js"></script> 150 <script src="UintLiteral.js"></script> 151 <script src="UintLiteralType.js"></script> 152 <script src="UnificationContext.js"></script> 153 <script src="UnreachableCodeChecker.js"></script> 154 <script src="VariableDecl.js"></script> 155 <script src="VariableRef.js"></script> 156 <script src="VisitingSet.js"></script> 157 <script src="WSyntaxError.js"></script> 158 <script src="WTrapError.js"></script> 159 <script src="WTypeError.js"></script> 160 <script src="WhileLoop.js"></script> 161 <script src="WrapChecker.js"></script> 5 162 <script> 163 let code = ` 164 struct VertexInput { 165 float2 position; 166 float3 color; 167 } 168 169 struct VertexOutput { 170 float4 wsl_Position; 171 float4 color; 172 } 173 174 struct FragmentOutput { 175 float4 wsl_Color; 176 } 177 178 vertex VertexOutput vertexShader(VertexInput vertexInput) { 179 VertexOutput result; 180 result.wsl_Position = float4(vertexInput.position, 0., 1.); 181 result.color = float4(vertexInput.color, 1); 182 183 int[10] a; 184 int[10u] b; 185 return result; 186 } 187 188 fragment FragmentOutput fragmentShader(VertexOutput stageIn) { 189 FragmentOutput result; 190 result.wsl_Color = stageIn.color; 191 return result; 192 }`; 6 193 7 194 window.addEventListener("load", function () { 8 195 fetch("spirv.core.grammar.json").then(response => response.json()).then(function (json) { 9 196 let spirv = SPIRV(json); 10 let assembler = new SPIRVAssembler(); 11 assembler.append(new spirv.ops.Capability(spirv.kinds.Capability.Shader)); 12 assembler.append(new spirv.ops.MemoryModel(spirv.kinds.AddressingModel.Logical, spirv.kinds.MemoryModel.GLSL450)); 13 assembler.append(new spirv.ops.EntryPoint(spirv.kinds.ExecutionModel.Fragment, 5, "main", 10, 17)); 14 assembler.append(new spirv.ops.ExecutionMode(5, spirv.kinds.ExecutionMode.OriginLowerLeft)); 15 assembler.append(new spirv.ops.Decorate(10, spirv.kinds.Decoration.Location, 0)); 16 assembler.append(new spirv.ops.Decorate(14, spirv.kinds.Decoration.DescriptorSet, 0)); 17 assembler.append(new spirv.ops.Decorate(14, spirv.kinds.Decoration.Binding, 1)); 18 assembler.append(new spirv.ops.Decorate(17, spirv.kinds.Decoration.Location, 0)); 19 assembler.append(new spirv.ops.TypeVoid(3)); 20 assembler.append(new spirv.ops.TypeFunction(4, 3)); 21 assembler.append(new spirv.ops.TypeFloat(7, 32)); 22 assembler.append(new spirv.ops.TypeVector(8, 7, 4)); 23 assembler.append(new spirv.ops.TypePointer(9, spirv.kinds.StorageClass.Output, 8)); 24 assembler.append(new spirv.ops.Variable(9, 10, spirv.kinds.StorageClass.Output)); 25 assembler.append(new spirv.ops.TypeImage(11, 7, spirv.kinds.Dim["2D"], 0, 0, 0, 1, spirv.kinds.ImageFormat.Unknown)); 26 assembler.append(new spirv.ops.TypeSampledImage(12, 11)); 27 assembler.append(new spirv.ops.TypePointer(13, spirv.kinds.StorageClass.UniformConstant, 12)); 28 assembler.append(new spirv.ops.Variable(13, 14, spirv.kinds.StorageClass.UniformConstant)); 29 assembler.append(new spirv.ops.TypePointer(16, spirv.kinds.StorageClass.Input, 8)); 30 assembler.append(new spirv.ops.Variable(16, 17, spirv.kinds.StorageClass.Input)); 31 assembler.append(new spirv.ops.TypeVector(18, 7, 2)); 32 assembler.append(new spirv.ops.Function(3, 5, spirv.kinds.FunctionControl.None, 4)); 33 assembler.append(new spirv.ops.Label(6)); 34 assembler.append(new spirv.ops.Load(12, 15, 14)); 35 assembler.append(new spirv.ops.Load(8, 19, 17)); 36 assembler.append(new spirv.ops.VectorShuffle(18, 20, 19, 19, 0, 1)); 37 assembler.append(new spirv.ops.ImageSampleImplicitLod(8, 21, 15, 20)); 38 assembler.append(new spirv.ops.Store(10, 21)); 39 assembler.append(new spirv.ops.Return()); 40 assembler.append(new spirv.ops.FunctionEnd()); 41 let result = assembler.result; 42 197 let program = prepare("/internal/test", 0, code); 198 let result = generateSPIRV(spirv, program); 199 return result; 200 }).then(function(result) { 43 201 let resultElement = document.getElementById("Result"); 44 202 while (resultElement.childNodes.length != 0) 45 203 resultElement.removeChild(resultElement.childNodes[0]); 46 204 let anchor = document.createElement("a"); 47 let blob = new Blob([result ], { type: "application/octet-binary" });205 let blob = new Blob([result.file], { type: "application/octet-binary" }); 48 206 anchor.href = URL.createObjectURL(blob); 49 207 anchor.download = "result.spv"; 50 208 anchor.textContent = "Download generated SPIR-V"; 51 209 resultElement.appendChild(anchor); 210 211 let table = document.createElement("table"); 212 let tableHeader = document.createElement("thead"); 213 let headerRow = document.createElement("tr"); 214 let nameHeader = document.createElement("th"); 215 nameHeader.textContent = "Attribute name"; 216 let locationHeader = document.createElement("th"); 217 locationHeader.textContent = "Location"; 218 headerRow.appendChild(nameHeader); 219 headerRow.appendChild(locationHeader); 220 tableHeader.appendChild(headerRow); 221 table.appendChild(tableHeader); 222 for (let location of result.locations) { 223 let tableRow = document.createElement("tr"); 224 let nameElement = document.createElement("td"); 225 nameElement.textContent = location.name; 226 let locationElement = document.createElement("td"); 227 locationElement.textContent = location.location; 228 tableRow.appendChild(nameElement); 229 tableRow.appendChild(locationElement); 230 table.appendChild(tableRow); 231 } 232 resultElement.appendChild(table); 52 233 }).then(undefined, function () { 53 234 let resultElement = document.getElementById("Result"); -
trunk/Tools/WebGPUShadingLanguageRI/WSL.md
r222179 r223246 474 474 475 475 - `device`, `constant`, and `threadgroup` pointers cannot point to data that may have pointers in it. This safety check is not done as part of the normal type system checks. It's performed only after instantiation. 476 - Pointers and array references (collectively, *references*) may be restricted to support compiling to SPIR-V *logical mode*. In this mode, references may never point to data structures that have references in them. References must be initialized upon declaration and never reassigned. Functions that return references must have one return point. Ternary expressions may not return references.476 - Pointers and array references (collectively, *references*) may be restricted to support compiling to SPIR-V *logical mode*. In this mode, arrays must not transitively hold references. References must be initialized upon declaration and never reassigned. Functions that return references must have one return point. Ternary expressions may not return references. 477 477 - Graphics entry points must transitively never refer to the `threadgroup` memory space. 478 478 -
trunk/Tools/WebGPUShadingLanguageRI/index.html
r222770 r223246 301 301 availableVertexShaders = []; 302 302 availableFragmentShaders = []; 303 for ( functionNames of program.functions.values()) {304 for ( func of functionNames) {303 for (let functionNames of program.functions.values()) { 304 for (let func of functionNames) { 305 305 if (func.shaderType == "vertex") 306 306 availableVertexShaders.push(func);
Note: See TracChangeset
for help on using the changeset viewer.