Changeset 246121 in webkit
- Timestamp:
- Jun 5, 2019 11:36:29 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 18 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r246118 r246121 1 2019-06-05 Saam Barati <sbarati@apple.com> 2 3 [WHLSL] Implement loop expressions 4 https://bugs.webkit.org/show_bug.cgi?id=195808 5 <rdar://problem/50746309> 6 7 Reviewed by Myles Maxfield. 8 9 * webgpu/whlsl-do-while-loop-break-expected.html: Added. 10 * webgpu/whlsl-do-while-loop-break.html: Added. 11 * webgpu/whlsl-do-while-loop-continue-expected.html: Added. 12 * webgpu/whlsl-do-while-loop-continue.html: Added. 13 * webgpu/whlsl-do-while-loop-expected.html: Added. 14 * webgpu/whlsl-do-while-loop.html: Added. 15 * webgpu/whlsl-loops-break-expected.html: Added. 16 * webgpu/whlsl-loops-break.html: Added. 17 * webgpu/whlsl-loops-continue-expected.html: Added. 18 * webgpu/whlsl-loops-continue.html: Added. 19 * webgpu/whlsl-loops-expected.html: Added. 20 * webgpu/whlsl-loops.html: Added. 21 * webgpu/whlsl-nested-loop-expected.html: Added. 22 * webgpu/whlsl-nested-loop.html: Added. 23 * webgpu/whlsl-while-loop-break-expected.html: Added. 24 * webgpu/whlsl-while-loop-break.html: Added. 25 * webgpu/whlsl-while-loop-continue-expected.html: Added. 26 * webgpu/whlsl-while-loop-continue.html: Added. 27 1 28 2019-06-05 Wenson Hsieh <wenson_hsieh@apple.com> 2 29 -
trunk/Source/WebCore/ChangeLog
r246118 r246121 1 2019-06-05 Saam Barati <sbarati@apple.com> 2 3 [WHLSL] Implement loop expressions 4 https://bugs.webkit.org/show_bug.cgi?id=195808 5 <rdar://problem/50746309> 6 7 Reviewed by Myles Maxfield. 8 9 This patch makes continue/break break for "do/while/for" loops 10 in WHLSL. Because of the way we emit code where every expression 11 turns into a Metal statement, it's not convenient to emit native 12 Metal loop constructs. Instead, we model break/continue as if 13 we had goto. 14 15 For example, this WHLSL program: 16 ``` 17 for (INIT; COND; INC) { 18 if (b) 19 continue; 20 if (b2) 21 break; 22 } 23 ``` 24 would become something like: 25 ``` 26 INIT; 27 while (1) { 28 if (!COND) 29 break; 30 if (b) 31 goto increment; 32 if (b2) 33 goto exit; 34 increment: 35 INC; 36 } 37 exit: 38 ``` 39 40 However, Metal doesn't have goto, so we model goto using a run-once 41 loop and a variable indicating if we should break out early. This 42 "break out early" variable is initially set to false. We "should 43 break out early" when executing a WHLSL "break" statement. "continue" 44 is modeled as breaking out of the run-once loop, but not touching the 45 "break out early" variable. "break" is modeled as setting the "break 46 out early" variable to true, followed by breaking out of the run-once loop. 47 The above WHLSL will turn into this Metal: 48 ``` 49 bool breakOutOfCurrentLoop = false; 50 INIT; 51 while (1) { 52 if (!COND) 53 break; 54 do { 55 if (b) { 56 // WHLSL 'continue' 57 break; 58 } 59 if (b2) { 60 // WHLSL 'break' 61 breakOutOfCurrentLoop = true; 62 break; 63 } 64 } while (0); 65 if (breakOutOfCurrentLoop) 66 break; 67 INC; 68 } 69 ``` 70 71 This patch also found a bug with ForLoop where it held a Variant<VariableDeclarationsStatement, Expression>. 72 This is invalid to do since we mutate the AST in place. This means some phase 73 could replace VariableDeclarationsStatement with some other Statement, and 74 we'd be breaking the C++ type system. So this patch migrates ForLoop to hold 75 a statement instead. In general, AST nodes that point to other AST nodes 76 should use broad types unless we know apriori that a certain type will 77 never be replaced. 78 79 Tests: webgpu/whlsl-do-while-loop-break.html 80 webgpu/whlsl-do-while-loop-continue.html 81 webgpu/whlsl-do-while-loop.html 82 webgpu/whlsl-loops-break.html 83 webgpu/whlsl-loops-continue.html 84 webgpu/whlsl-loops.html 85 webgpu/whlsl-nested-loop.html 86 webgpu/whlsl-while-loop-break.html 87 webgpu/whlsl-while-loop-continue.html 88 89 * Modules/webgpu/WHLSL/AST/WHLSLForLoop.h: 90 (WebCore::WHLSL::AST::ForLoop::ForLoop): 91 (WebCore::WHLSL::AST::ForLoop::initialization): 92 * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp: 93 (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit): 94 (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop): 95 * Modules/webgpu/WHLSL/WHLSLASTDumper.cpp: 96 (WebCore::WHLSL::ASTDumper::visit): 97 * Modules/webgpu/WHLSL/WHLSLChecker.cpp: 98 (WebCore::WHLSL::Checker::visit): 99 * Modules/webgpu/WHLSL/WHLSLParser.cpp: 100 (WebCore::WHLSL::Parser::parseForLoop): 101 * Modules/webgpu/WHLSL/WHLSLPrepare.cpp: 102 * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt: 103 * Modules/webgpu/WHLSL/WHLSLVisitor.cpp: 104 (WebCore::WHLSL::Visitor::visit): 105 1 106 2019-06-05 Wenson Hsieh <wenson_hsieh@apple.com> 2 107 -
trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLForLoop.h
r239930 r246121 45 45 class ForLoop : public Statement { 46 46 public: 47 ForLoop(Lexer::Token&& origin, Variant< VariableDeclarationsStatement, UniqueRef<Expression>>&& initialization, Optional<UniqueRef<Expression>>&& condition, Optional<UniqueRef<Expression>>&& increment, UniqueRef<Statement>&& body)47 ForLoop(Lexer::Token&& origin, Variant<UniqueRef<Statement>, UniqueRef<Expression>>&& initialization, Optional<UniqueRef<Expression>>&& condition, Optional<UniqueRef<Expression>>&& increment, UniqueRef<Statement>&& body) 48 48 : Statement(WTFMove(origin)) 49 49 , m_initialization(WTFMove(initialization)) … … 63 63 bool isForLoop() const override { return true; } 64 64 65 Variant< VariableDeclarationsStatement, UniqueRef<Expression>>& initialization() { return m_initialization; }65 Variant<UniqueRef<Statement>, UniqueRef<Expression>>& initialization() { return m_initialization; } 66 66 Expression* condition() { return m_condition ? &*m_condition : nullptr; } 67 67 Expression* increment() { return m_increment ? &*m_increment : nullptr; } … … 69 69 70 70 private: 71 Variant< VariableDeclarationsStatement, UniqueRef<Expression>> m_initialization;71 Variant<UniqueRef<Statement>, UniqueRef<Expression>> m_initialization; 72 72 Optional<UniqueRef<Expression>> m_condition; 73 73 Optional<UniqueRef<Expression>> m_increment; -
trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp
r245973 r246121 36 36 #include "WHLSLVisitor.h" 37 37 #include <wtf/HashMap.h> 38 #include <wtf/SetForScope.h> 38 39 #include <wtf/text/StringBuilder.h> 39 40 … … 140 141 void visit(AST::VariableReference&) override; 141 142 143 enum class LoopConditionLocation { 144 BeforeBody, 145 AfterBody 146 }; 147 void emitLoop(LoopConditionLocation, AST::Expression* conditionExpression, AST::Expression* increment, AST::Statement& body); 148 142 149 String constantExpressionString(AST::ConstantExpression&); 143 150 … … 156 163 Layout& m_layout; 157 164 unsigned m_variableCount { 0 }; 165 String m_breakOutOfCurrentLoopEarlyVariable; 158 166 }; 159 167 … … 225 233 void FunctionDefinitionWriter::visit(AST::Break&) 226 234 { 235 ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length()); 236 m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n")); 227 237 m_stringBuilder.append("break;\n"); 228 238 } … … 230 240 void FunctionDefinitionWriter::visit(AST::Continue&) 231 241 { 232 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195808 Figure out which loop we're in, and run the increment code 233 notImplemented(); 234 } 235 236 void FunctionDefinitionWriter::visit(AST::DoWhileLoop& doWhileLoop) 237 { 238 m_stringBuilder.append("do {\n"); 239 checkErrorAndVisit(doWhileLoop.body()); 240 checkErrorAndVisit(doWhileLoop.conditional()); 241 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); 242 m_stringBuilder.append(makeString("} while(true);\n")); 242 ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length()); 243 m_stringBuilder.append("break;\n"); 243 244 } 244 245 … … 254 255 } 255 256 257 void FunctionDefinitionWriter::emitLoop(LoopConditionLocation loopConditionLocation, AST::Expression* conditionExpression, AST::Expression* increment, AST::Statement& body) 258 { 259 SetForScope<String> loopVariableScope(m_breakOutOfCurrentLoopEarlyVariable, generateNextVariableName()); 260 261 m_stringBuilder.append(makeString("bool ", m_breakOutOfCurrentLoopEarlyVariable, " = false;\n")); 262 263 m_stringBuilder.append("while (true) {\n"); 264 265 if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) { 266 checkErrorAndVisit(*conditionExpression); 267 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); 268 } 269 270 m_stringBuilder.append("do {\n"); 271 checkErrorAndVisit(body); 272 m_stringBuilder.append("} while(false); \n"); 273 m_stringBuilder.append(makeString("if (", m_breakOutOfCurrentLoopEarlyVariable, ") break;\n")); 274 275 if (increment) { 276 checkErrorAndVisit(*increment); 277 // Expression results get pushed to m_stack. We don't use the result 278 // of increment, so we dispense of that now. 279 m_stack.takeLast(); 280 } 281 282 if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) { 283 checkErrorAndVisit(*conditionExpression); 284 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); 285 } 286 287 m_stringBuilder.append("} \n"); 288 } 289 290 void FunctionDefinitionWriter::visit(AST::DoWhileLoop& doWhileLoop) 291 { 292 emitLoop(LoopConditionLocation::AfterBody, &doWhileLoop.conditional(), nullptr, doWhileLoop.body()); 293 } 294 295 void FunctionDefinitionWriter::visit(AST::WhileLoop& whileLoop) 296 { 297 emitLoop(LoopConditionLocation::BeforeBody, &whileLoop.conditional(), nullptr, whileLoop.body()); 298 } 299 256 300 void FunctionDefinitionWriter::visit(AST::ForLoop& forLoop) 257 301 { 258 WTF::visit(WTF::makeVisitor([&](AST::VariableDeclarationsStatement& variableDeclarationsStatement) { 259 checkErrorAndVisit(variableDeclarationsStatement); 302 m_stringBuilder.append("{\n"); 303 304 WTF::visit(WTF::makeVisitor([&](AST::Statement& statement) { 305 checkErrorAndVisit(statement); 260 306 }, [&](UniqueRef<AST::Expression>& expression) { 261 307 checkErrorAndVisit(expression); … … 263 309 }), forLoop.initialization()); 264 310 265 m_stringBuilder.append("for ( ; ; ) {\n"); 266 if (forLoop.condition()) { 267 checkErrorAndVisit(*forLoop.condition()); 268 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); 269 } 270 checkErrorAndVisit(forLoop.body()); 271 if (forLoop.increment()) { 272 checkErrorAndVisit(*forLoop.increment()); 273 m_stack.takeLast(); 274 } 311 emitLoop(LoopConditionLocation::BeforeBody, forLoop.condition(), forLoop.increment(), forLoop.body()); 275 312 m_stringBuilder.append("}\n"); 276 313 } … … 332 369 { 333 370 Visitor::visit(variableDeclarationsStatement); 334 }335 336 void FunctionDefinitionWriter::visit(AST::WhileLoop& whileLoop)337 {338 m_stringBuilder.append(makeString("while (true) {\n"));339 checkErrorAndVisit(whileLoop.conditional());340 m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));341 checkErrorAndVisit(whileLoop.body());342 m_stringBuilder.append("}\n");343 371 } 344 372 -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp
r245945 r246121 414 414 { 415 415 m_out.print("for ("); 416 WTF::visit(WTF::makeVisitor([&]( AST::VariableDeclarationsStatement& variableDeclarationsStatement) {417 visit( variableDeclarationsStatement);416 WTF::visit(WTF::makeVisitor([&](UniqueRef<AST::Statement>& statement) { 417 visit(statement); 418 418 }, [&](UniqueRef<AST::Expression>& expression) { 419 419 visit(expression); -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp
r245844 r246121 1190 1190 void Checker::visit(AST::ForLoop& forLoop) 1191 1191 { 1192 WTF::visit(WTF::makeVisitor([&]( AST::VariableDeclarationsStatement& variableDeclarationsStatement) {1193 checkErrorAndVisit( variableDeclarationsStatement);1192 WTF::visit(WTF::makeVisitor([&](UniqueRef<AST::Statement>& statement) { 1193 checkErrorAndVisit(statement); 1194 1194 }, [&](UniqueRef<AST::Expression>& expression) { 1195 1195 checkErrorAndVisit(expression); -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp
r246108 r246121 1415 1415 return Unexpected<Error>(origin.error()); 1416 1416 1417 auto parseRemainder = [&](Variant< AST::VariableDeclarationsStatement, UniqueRef<AST::Expression>>&& initialization) -> Expected<AST::ForLoop, Error> {1417 auto parseRemainder = [&](Variant<UniqueRef<AST::Statement>, UniqueRef<AST::Expression>>&& initialization) -> Expected<AST::ForLoop, Error> { 1418 1418 auto semicolon = consumeType(Lexer::Token::Type::Semicolon); 1419 1419 if (!semicolon) … … 1454 1454 return parseVariableDeclarations(); 1455 1455 }); 1456 if (variableDeclarations) 1457 return parseRemainder(WTFMove(*variableDeclarations)); 1456 if (variableDeclarations) { 1457 UniqueRef<AST::Statement> declarationStatement = makeUniqueRef<AST::VariableDeclarationsStatement>(WTFMove(*variableDeclarations)); 1458 return parseRemainder(WTFMove(declarationStatement)); 1459 } 1458 1460 1459 1461 auto effectfulExpression = parseEffectfulExpression(); -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp
r245945 r246121 58 58 static constexpr bool dumpASTBeforeEachPass = false; 59 59 static constexpr bool dumpASTAfterParsing = false; 60 static constexpr bool dumpASTAtEnd = true;60 static constexpr bool dumpASTAtEnd = false; 61 61 static constexpr bool alwaysDumpPassFailures = false; 62 62 static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures; -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt
r245680 r246121 385 385 native float4 operator.w=(float4, float); 386 386 387 native float operator+(float, float); 388 native float operator-(float, float); 389 native int operator+(int, int); 390 native uint operator+(uint, uint); 391 native bool operator<(int, int); 392 native bool operator<(uint, uint); 393 native bool operator<(float, float); 394 387 395 native float ddx(float); 388 396 native float ddy(float); -
trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp
r245945 r246121 435 435 void Visitor::visit(AST::ForLoop& forLoop) 436 436 { 437 WTF::visit(WTF::makeVisitor([&]( AST::VariableDeclarationsStatement& variableDeclarationsStatement) {438 checkErrorAndVisit( variableDeclarationsStatement);437 WTF::visit(WTF::makeVisitor([&](UniqueRef<AST::Statement>& statement) { 438 checkErrorAndVisit(statement); 439 439 }, [&](UniqueRef<AST::Expression>& expression) { 440 440 checkErrorAndVisit(expression);
Note: See TracChangeset
for help on using the changeset viewer.