From 66ccc8643852cb022bf3e4946311a8a8bc55e858 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isuckatcs@users.noreply.github.com> Date: Sat, 29 Jun 2024 19:08:12 +0200 Subject: [PATCH] [CFG] handle conditional operator in while condition --- src/cfg.cpp | 15 +- test/cfg/while.al | 371 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+), 3 deletions(-) create mode 100644 test/cfg/while.al diff --git a/src/cfg.cpp b/src/cfg.cpp index 5d11407..7fb98de 100644 --- a/src/cfg.cpp +++ b/src/cfg.cpp @@ -82,9 +82,18 @@ void CFGBuilder::visit(const ResolvedWhileStmt &stmt) { successorBlock = bodyBlock; currentBlock = -1; - // FIXME: Handle conditional - visit(*stmt.condition); - currentCFG.insertEdge(currentBlock, exitBlock, true); + const auto *binaryOperator = + dynamic_cast(stmt.condition.get()); + if (binaryOperator && (binaryOperator->op == TokenKind::PipePipe || + binaryOperator->op == TokenKind::AmpAmp)) { + visitCondition( + *binaryOperator, &stmt, + binaryOperator->op == TokenKind::PipePipe ? exitBlock : bodyBlock, + binaryOperator->op == TokenKind::PipePipe ? bodyBlock : exitBlock); + } else { + visit(*stmt.condition); + currentCFG.insertEdge(currentBlock, exitBlock, true); + } currentCFG.insertEdge(transitionBlock, currentBlock, true); successorBlock = currentBlock; diff --git a/test/cfg/while.al b/test/cfg/while.al new file mode 100644 index 0000000..69a7869 --- /dev/null +++ b/test/cfg/while.al @@ -0,0 +1,371 @@ +// RUN: compiler %s -cfg-dump 2>&1 | filecheck %s +fn main(): void { + 5.0; + while 4.0 { + 3.0; + } + + 1.0; +} +// CHECK: main +// CHECK-NEXT: ---------- +// CHECK-NEXT: [6 (entry)] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 5 +// CHECK-NEXT: +// CHECK-NEXT: [5] +// CHECK-NEXT: preds: 6 +// CHECK-NEXT: succs: 4 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: +// CHECK-NEXT: [4] +// CHECK-NEXT: preds: 2 5 +// CHECK-NEXT: succs: 1 3 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [3] +// CHECK-NEXT: preds: 4 +// CHECK-NEXT: succs: 2 +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [2] +// CHECK-NEXT: preds: 3 +// CHECK-NEXT: succs: 4 +// CHECK-NEXT: +// CHECK-NEXT: [1] +// CHECK-NEXT: preds: 4 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '1' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: +// CHECK-NEXT: [0 (exit)] +// CHECK-NEXT: preds: 1 +// CHECK-NEXT: succs: + +fn orCondition(): void { + 7.0; + while 6.0 || 5.0 || 4.0 { + 3.0; + } + + 1.0; +} +// CHECK: orCondition +// CHECK-NEXT: ---------- +// CHECK-NEXT: [8 (entry)] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: +// CHECK-NEXT: [7] +// CHECK-NEXT: preds: 8 +// CHECK-NEXT: succs: 6 +// CHECK-NEXT: NumberLiteral: '7' +// CHECK-NEXT: | value: 7 +// CHECK-NEXT: +// CHECK-NEXT: [6] +// CHECK-NEXT: preds: 2 7 +// CHECK-NEXT: succs: 3 5 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: ResolvedBinaryOperator: '||' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: +// CHECK-NEXT: [5] +// CHECK-NEXT: preds: 6 +// CHECK-NEXT: succs: 3 4 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: ResolvedBinaryOperator: '||' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: ResolvedBinaryOperator: '||' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [4] +// CHECK-NEXT: preds: 5 +// CHECK-NEXT: succs: 1 3 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: ResolvedWhileStmt +// CHECK-NEXT: ResolvedBinaryOperator: '||' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: ResolvedBinaryOperator: '||' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: ResolvedBlock +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [3] +// CHECK-NEXT: preds: 4 5 6 +// CHECK-NEXT: succs: 2 +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [2] +// CHECK-NEXT: preds: 3 +// CHECK-NEXT: succs: 6 +// CHECK-NEXT: +// CHECK-NEXT: [1] +// CHECK-NEXT: preds: 4 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '1' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: +// CHECK-NEXT: [0 (exit)] +// CHECK-NEXT: preds: 1 +// CHECK-NEXT: succs: + +fn andCondition(): void { + 7.0; + while 6.0 && 5.0 && 4.0 { + 3.0; + } + + 1.0; +} +// CHECK: andCondition +// CHECK-NEXT: ---------- +// CHECK-NEXT: [8 (entry)] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: +// CHECK-NEXT: [7] +// CHECK-NEXT: preds: 8 +// CHECK-NEXT: succs: 6 +// CHECK-NEXT: NumberLiteral: '7' +// CHECK-NEXT: | value: 7 +// CHECK-NEXT: +// CHECK-NEXT: [6] +// CHECK-NEXT: preds: 2 7 +// CHECK-NEXT: succs: 1 5 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: ResolvedBinaryOperator: '&&' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: +// CHECK-NEXT: [5] +// CHECK-NEXT: preds: 6 +// CHECK-NEXT: succs: 1 4 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: ResolvedBinaryOperator: '&&' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: ResolvedBinaryOperator: '&&' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [4] +// CHECK-NEXT: preds: 5 +// CHECK-NEXT: succs: 1 3 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: ResolvedWhileStmt +// CHECK-NEXT: ResolvedBinaryOperator: '&&' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: ResolvedBinaryOperator: '&&' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: ResolvedBlock +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [3] +// CHECK-NEXT: preds: 4 +// CHECK-NEXT: succs: 2 +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [2] +// CHECK-NEXT: preds: 3 +// CHECK-NEXT: succs: 6 +// CHECK-NEXT: +// CHECK-NEXT: [1] +// CHECK-NEXT: preds: 4 5 6 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '1' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: +// CHECK-NEXT: [0 (exit)] +// CHECK-NEXT: preds: 1 +// CHECK-NEXT: succs: + +fn nestedLoops(): void { + 8.0; + while 7.0 { + 6.0; + while 5.0 { + 4.0; + } + } + + 1.0; +} +// CHECK: nestedLoops +// CHECK-NEXT: ---------- +// CHECK-NEXT: [9 (entry)] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 8 +// CHECK-NEXT: +// CHECK-NEXT: [8] +// CHECK-NEXT: preds: 9 +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: NumberLiteral: '8' +// CHECK-NEXT: | value: 8 +// CHECK-NEXT: +// CHECK-NEXT: [7] +// CHECK-NEXT: preds: 2 8 +// CHECK-NEXT: succs: 1 6 +// CHECK-NEXT: NumberLiteral: '7' +// CHECK-NEXT: | value: 7 +// CHECK-NEXT: +// CHECK-NEXT: [6] +// CHECK-NEXT: preds: 7 +// CHECK-NEXT: succs: 5 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: +// CHECK-NEXT: [5] +// CHECK-NEXT: preds: 3 6 +// CHECK-NEXT: succs: 2 4 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: +// CHECK-NEXT: [4] +// CHECK-NEXT: preds: 5 +// CHECK-NEXT: succs: 3 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [3] +// CHECK-NEXT: preds: 4 +// CHECK-NEXT: succs: 5 +// CHECK-NEXT: +// CHECK-NEXT: [2] +// CHECK-NEXT: preds: 5 +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: +// CHECK-NEXT: [1] +// CHECK-NEXT: preds: 7 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '1' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: +// CHECK-NEXT: [0 (exit)] +// CHECK-NEXT: preds: 1 +// CHECK-NEXT: succs: + +fn returnMidloop(): void { + 8.0; + while 7.0 { + 6.0; + if 6.0 { + 5.0; + return; + + 4.0; + } + + 3.0; + } + + 1.0; +} +// CHECK: returnMidloop +// CHECK-NEXT: ---------- +// CHECK-NEXT: [9 (entry)] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 8 +// CHECK-NEXT: +// CHECK-NEXT: [8] +// CHECK-NEXT: preds: 9 +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: NumberLiteral: '8' +// CHECK-NEXT: | value: 8 +// CHECK-NEXT: +// CHECK-NEXT: [7] +// CHECK-NEXT: preds: 2 8 +// CHECK-NEXT: succs: 1 6 +// CHECK-NEXT: NumberLiteral: '7' +// CHECK-NEXT: | value: 7 +// CHECK-NEXT: +// CHECK-NEXT: [6] +// CHECK-NEXT: preds: 7 +// CHECK-NEXT: succs: 3 5 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: ResolvedIfStmt +// CHECK-NEXT: NumberLiteral: '6' +// CHECK-NEXT: | value: 6 +// CHECK-NEXT: ResolvedBlock +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: ResolvedReturnStmt +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [5] +// CHECK-NEXT: preds: 6 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '5' +// CHECK-NEXT: | value: 5 +// CHECK-NEXT: ResolvedReturnStmt +// CHECK-NEXT: +// CHECK-NEXT: [4] +// CHECK-NEXT: preds: +// CHECK-NEXT: succs: 3 +// CHECK-NEXT: NumberLiteral: '4' +// CHECK-NEXT: | value: 4 +// CHECK-NEXT: +// CHECK-NEXT: [3] +// CHECK-NEXT: preds: 4 6 +// CHECK-NEXT: succs: 2 +// CHECK-NEXT: NumberLiteral: '3' +// CHECK-NEXT: | value: 3 +// CHECK-NEXT: +// CHECK-NEXT: [2] +// CHECK-NEXT: preds: 3 +// CHECK-NEXT: succs: 7 +// CHECK-NEXT: +// CHECK-NEXT: [1] +// CHECK-NEXT: preds: 7 +// CHECK-NEXT: succs: 0 +// CHECK-NEXT: NumberLiteral: '1' +// CHECK-NEXT: | value: 1 +// CHECK-NEXT: +// CHECK-NEXT: [0 (exit)] +// CHECK-NEXT: preds: 1 5 +// CHECK-NEXT: succs: