Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 6 additions & 59 deletions tslang/lib/TypeScript/MLIRGenStatements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,6 @@ namespace mlirgen

auto location = loc(forStatementAST);

auto hasAwait = InternalFlags::ForAwait == (forStatementAST->internalFlags & InternalFlags::ForAwait);

// initializer
// TODO: why do we have ForInitialier
if (isExpression(forStatementAST->initializer))
Expand Down Expand Up @@ -851,63 +849,12 @@ namespace mlirgen

// body
builder.setInsertionPointToStart(&forOp.getBody().front());
if (hasAwait)
{
if (forStatementAST->statement == SyntaxKind::Block)
{
auto firstStatement = forStatementAST->statement.as<ts::Block>()->statements.front();
auto result = mlirGen(firstStatement, loopGenContext);
EXIT_IF_FAILED(result)
}

// TODO: we need to strip metadata to fix issue with debug info
// async body
auto isFailed = false;
auto asyncExecOp = builder.create<mlir::async::ExecuteOp>(
stripMetadata(location), mlir::TypeRange{}, mlir::ValueRange{}, mlir::ValueRange{},
[&](mlir::OpBuilder &builder, mlir::Location location, mlir::ValueRange values) {
GenContext execOpBodyGenContext(loopGenContext);
DITableScopeT debugAsyncCodeScope(debugScope);
MLIRDebugInfoHelper mdi(builder, debugScope);

// TODO: temp hack to break wrong chain on scopes because 'await' create extra function wrap
mdi.clearDebugScope();
mdi.setLexicalBlock(location);

if (forStatementAST->statement == SyntaxKind::Block)
{
if (mlir::failed(mlirGen(forStatementAST->statement.as<ts::Block>(), execOpBodyGenContext, 1)))
{
isFailed = true;
}
}
else
{
if (mlir::failed(mlirGen(forStatementAST->statement, execOpBodyGenContext)))
{
isFailed = true;
}
}

builder.create<mlir::async::YieldOp>(location, mlir::ValueRange{});
});

if (isFailed)
{
return mlir::failure();
}

// One iteration at a time, as `for await` runs its body: the next value is asked for only
// once this body is done. Each body was added to a group awaited after the loop, so the
// bodies ran as concurrent tasks - interleaved, losing each other's writes (#498).
builder.create<mlir::async::AwaitOp>(location, asyncExecOp.getToken());
}
else
{
// default
auto result = mlirGen(forStatementAST->statement, loopGenContext);
EXIT_IF_FAILED(result)
}
// A `for await` body is generated in the loop as any other: an `await` in it makes its own
// async.execute and waits for it, so one iteration runs at a time (#498). Generated inside an
// async.execute of its own, a `break` or `continue` in it had no loop in its region, and a
// nested `for await` crashed the compiler (#502).
auto bodyResult = mlirGen(forStatementAST->statement, loopGenContext);
EXIT_IF_FAILED(bodyResult)

builder.create<mlir_ts::ResultOp>(location);

Expand Down
3 changes: 3 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ tslang_add_test(NAME test-compile-00-record-variable-to-class COMMAND test-runne
tslang_add_test(NAME test-compile-00-array-insert-functions COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_insert_functions.ts")
tslang_add_test(NAME test-compile-00-await-void COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00await_void.ts")
tslang_add_test(NAME test-compile-00-for-await-sequential COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00for_await_sequential.ts")
tslang_add_test(NAME test-compile-00-for-await-control COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00for_await_control.ts")
tslang_add_test(NAME test-compile-00-const-record-owned-fields COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_record_owned_fields.ts")
tslang_add_test(NAME test-compile-00-array-length-valid COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_length_valid.ts")
tslang_add_test(NAME test-compile-00-string-view-copy COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00string_view_copy.ts")
Expand Down Expand Up @@ -865,6 +866,7 @@ tslang_add_test(NAME test-jit-00-record-variable-to-class COMMAND test-runner -j
tslang_add_test(NAME test-jit-00-array-insert-functions COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_insert_functions.ts")
tslang_add_test(NAME test-jit-00-await-void COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00await_void.ts")
tslang_add_test(NAME test-jit-00-for-await-sequential COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00for_await_sequential.ts")
tslang_add_test(NAME test-jit-00-for-await-control COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00for_await_control.ts")
tslang_add_test(NAME test-jit-00-const-record-owned-fields COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_record_owned_fields.ts")
tslang_add_test(NAME test-jit-00-array-length-valid COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_length_valid.ts")
tslang_add_test(NAME test-jit-00-string-view-copy COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00string_view_copy.ts")
Expand Down Expand Up @@ -1705,6 +1707,7 @@ set(TSLANG_CORPUS
00array_insert_functions.ts
00await_void.ts
00for_await_sequential.ts
00for_await_control.ts
00const_record_owned_fields.ts
00array_length_valid.ts
00string_view_copy.ts
Expand Down
50 changes: 50 additions & 0 deletions tslang/test/tester/tests/00for_await_control.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// `break` and `continue` in a `for await` body, and a `for await` nested in another (#502): the
// body was generated in an async.execute region of its own, where a `break` had no loop to leave,
// and the compiler crashed.
let log = "";
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
}
async function* letters() {
yield "a";
yield "b";
}
async function note(s: string) {
log += s;
}
async function main() {
for await (const x of numbers()) {
if (x == 3) break;
log += x;
}
assert(log == "12", "break");

log = "";
for await (const x of numbers()) {
if (x == 2) continue;
log += x;
}
assert(log == "134", "continue");

log = "";
for await (const x of numbers()) {
for await (const y of letters()) {
log += x + y;
}
}
assert(log == "1a1b2a2b3a3b4a4b", "nested");

log = "";
for await (const x of numbers()) {
await note("<" + x);
if (x == 2) continue;
if (x == 4) break;
await note(">");
}
assert(log == "<1><2<3><4", "awaits, continue and break");

print("done.");
}
Loading