Skip to content

Commit

Permalink
[Constexpr] add option to the tree-walk interpreter to ignore side ef…
Browse files Browse the repository at this point in the history
…fects
  • Loading branch information
isuckatcs committed Jul 17, 2024
1 parent ec9a8ab commit 4fd87f7
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 28 deletions.
2 changes: 2 additions & 0 deletions include/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>

#include "ast.h"
#include "constexpr.h"

namespace yl {
struct BasicBlock {
Expand Down Expand Up @@ -42,6 +43,7 @@ struct CFG : public Dumpable {
};

class CFGBuilder {
ConstantExpressionEvaluator cee;
CFG cfg;

int insertBlock(const ResolvedBlock &block, int successor);
Expand Down
6 changes: 4 additions & 2 deletions include/constexpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
namespace yl {
class ConstantExpressionEvaluator {
std::optional<double>
evaluateBinaryOperator(const ResolvedBinaryOperator &binop);
evaluateBinaryOperator(const ResolvedBinaryOperator &binop,
bool allowSideEffects = false);
std::optional<double> evaluateUnaryOperator(const ResolvedUnaryOperator &op);
std::optional<double> evaluateDeclRefExpr(const ResolvedDeclRefExpr &dre);

public:
std::optional<double> evaluate(const ResolvedExpr &expr);
std::optional<double> evaluate(const ResolvedExpr &expr,
bool allowSideEffects = false);
};
} // namespace yl

Expand Down
4 changes: 2 additions & 2 deletions src/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ int CFGBuilder::insertIfStmt(const ResolvedIfStmt &stmt, int exit) {
int trueBlock = insertBlock(*stmt.trueBlock, exit);
int entry = cfg.insertNewBlock();

std::optional<double> val = stmt.condition->getConstantValue();
std::optional<double> val = cee.evaluate(*stmt.condition, true);
cfg.insertEdge(entry, trueBlock, val != 0);
cfg.insertEdge(entry, falseBlock, val.value_or(0) == 0);

Expand All @@ -61,7 +61,7 @@ int CFGBuilder::insertWhileStmt(const ResolvedWhileStmt &stmt, int exit) {
int header = cfg.insertNewBlock();
cfg.insertEdge(latch, header, true);

std::optional<double> val = stmt.condition->getConstantValue();
std::optional<double> val = cee.evaluate(*stmt.condition, true);
cfg.insertEdge(header, body, val != 0);
cfg.insertEdge(header, exit, val.value_or(0) == 0);

Expand Down
42 changes: 27 additions & 15 deletions src/constexpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,44 @@ std::optional<bool> toBool(std::optional<double> d) {

namespace yl {
std::optional<double> ConstantExpressionEvaluator::evaluateBinaryOperator(
const ResolvedBinaryOperator &binop) {
const ResolvedBinaryOperator &binop, bool allowSideEffects) {
std::optional<double> lhs = evaluate(*binop.lhs);

if (!lhs && !allowSideEffects)
return std::nullopt;

if (binop.op == TokenKind::PipePipe) {
// If the LHS of || is true, we don't need to evaluate the RHS.
if (toBool(lhs).value_or(false))
if (toBool(lhs) == true)
return 1.0;

// If the LHS is false, or side effects are allowed and the RHS is true, the
// result is true.
std::optional<double> rhs = evaluate(*binop.rhs);
if (toBool(rhs) == true)
return 1.0;

return toBool(evaluate(*binop.rhs));
// If both sides are known but none of them is true, the result is false.
if (lhs && rhs)
return 0.0;

// Otherwise one of the sides is unknown, so the result is unknown too.
return std::nullopt;
}

if (binop.op == TokenKind::AmpAmp) {
// If the LHS of && is false, we don't need to evaluate the RHS.
if (binop.op == TokenKind::AmpAmp && !toBool(lhs).value_or(true))
if (toBool(lhs) == false)
return 0.0;

// If the LHS is unknown, but the RHS is false, the expression is false.
std::optional<double> rhs = evaluate(*binop.rhs);
if (!lhs) {
if (rhs == 0.0)
return rhs;
if (toBool(rhs) == false)
return 0.0;

return std::nullopt;
}
if (lhs && rhs)
return 1.0;

// Otherwise LHS is known to be true, so the result depends on the RHS.
return toBool(rhs);
return std::nullopt;
}

if (!lhs)
Expand Down Expand Up @@ -95,7 +106,8 @@ std::optional<double> ConstantExpressionEvaluator::evaluateDeclRefExpr(
}

std::optional<double>
ConstantExpressionEvaluator::evaluate(const ResolvedExpr &expr) {
ConstantExpressionEvaluator::evaluate(const ResolvedExpr &expr,
bool allowSideEffects) {
// Don't evaluate the same expression multiple times.
if (std::optional<double> val = expr.getConstantValue())
return val;
Expand All @@ -106,11 +118,11 @@ ConstantExpressionEvaluator::evaluate(const ResolvedExpr &expr) {

if (const auto *groupingExpr =
dynamic_cast<const ResolvedGroupingExpr *>(&expr))
return evaluate(*groupingExpr->expr);
return evaluate(*groupingExpr->expr, allowSideEffects);

if (const auto *binaryOperator =
dynamic_cast<const ResolvedBinaryOperator *>(&expr))
return evaluateBinaryOperator(*binaryOperator);
return evaluateBinaryOperator(*binaryOperator, allowSideEffects);

if (const auto *unaryOperator =
dynamic_cast<const ResolvedUnaryOperator *>(&expr))
Expand Down
14 changes: 5 additions & 9 deletions test/constexpr/special_cases.yl
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,15 @@ fn lhsUnknownRhsFalse(x: number): number {
}
// CHECK: ResolvedReturnStmt
// CHECK-NEXT: ResolvedBinaryOperator: '&&'
// CHECK-NEXT: | value: 0
// CHECK-NEXT: ResolvedDeclRefExpr: @({{.*}}) x
// CHECK-NEXT: ResolvedNumberLiteral: '0'

fn lhsUnknownRhsTrue(x: number): number {
return x && (0.0 - 1.0);
return x || 1.0;
}
// CHECK: ResolvedReturnStmt
// CHECK-NEXT: ResolvedBinaryOperator: '&&'
// CHECK-NEXT: ResolvedDeclRefExpr: @({{.*}}) x
// CHECK-NEXT: ResolvedGroupingExpr:
// CHECK-NEXT: ResolvedBinaryOperator: '-'
// CHECK-NEXT: ResolvedNumberLiteral: '0'
// CHECK-NEXT: ResolvedNumberLiteral: '1'
// CHECK: ResolvedReturnStmt
// CHECK-NEXT: ResolvedBinaryOperator: '||'
// CHECK-NEXT: ResolvedDeclRefExpr: @({{.*}}) x
// CHECK-NEXT: ResolvedNumberLiteral: '1'

fn main(): void {}
15 changes: 15 additions & 0 deletions test/sema/return_on_every_branch.yl
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,20 @@ fn noReturnNeverRunningLoop(): number {
while 0.0 {}
}

fn returnAllPath(x: number): number {
if (x || 1) {
return 1;
} else {

}
}

fn returnAllPathElse(x: number): number {
if (x && 0) {
} else {
return 1;
}
}

fn main(): void {}
// CHECK-NOT: {{.*}}

0 comments on commit 4fd87f7

Please sign in to comment.