Skip to content

Commit

Permalink
Add boolean folding.
Browse files Browse the repository at this point in the history
Note: The original plan was to have this fully replace the optimizer's
boolean folding. However, it turns out that that doesn't quite work
because it would mess up the optimizer's tracking of feature usage.
For now, we special-case the feature constants in the folder and don't
touch them.
  • Loading branch information
rsmmr committed Dec 16, 2022
1 parent 224718d commit 7ce919c
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 42 deletions.
58 changes: 56 additions & 2 deletions hilti/toolchain/src/compiler/visitors/constant-folder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
#include <hilti/rt/safe-math.h>

#include <hilti/ast/builder/expression.h>
#include <hilti/ast/ctors/bool.h>
#include <hilti/ast/ctors/integer.h>
#include <hilti/ast/detail/visitor.h>
#include <hilti/ast/expression.h>
#include <hilti/ast/expressions/grouping.h>
#include <hilti/ast/operators/real.h>
#include <hilti/ast/operators/signed-integer.h>
#include <hilti/ast/types/integer.h>
#include <hilti/base/logger.h>
#include <hilti/base/util.h>
#include <hilti/compiler/detail/visitors.h>

#include "exception.h"

using namespace hilti;

namespace {
Expand Down Expand Up @@ -90,6 +90,60 @@ struct VisitorConstantFolder : public visitor::PreOrder<std::optional<Ctor>, Vis
return ctor::SignedInteger(-op->value(), op->width(), p.node.meta());
}

result_t operator()(const expression::Grouping& n, position_t p) {
auto x = _foldConstant(n.expression());
if ( ! x )
return std::nullopt;

return *x;
}

result_t operator()(const expression::LogicalOr& n, position_t p) {
auto op0 = foldConstant<ctor::Bool>(n.op0());
auto op1 = foldConstant<ctor::Bool>(n.op1());
if ( ! (op0 && op1) )
return std::nullopt;

return ctor::Bool(op0->value() || op1->value(), p.node.meta());
}

result_t operator()(const expression::LogicalAnd& n, position_t p) {
auto op0 = foldConstant<ctor::Bool>(n.op0());
auto op1 = foldConstant<ctor::Bool>(n.op1());
if ( ! (op0 && op1) )
return std::nullopt;

return ctor::Bool(op0->value() && op1->value(), p.node.meta());
}

result_t operator()(const expression::LogicalNot& n, position_t p) {
auto op = foldConstant<ctor::Bool>(n.expression());
if ( ! op )
return std::nullopt;

return ctor::Bool(! op->value(), p.node.meta());
}

result_t operator()(const expression::ResolvedID& n, position_t p) {
// We cannot fold the optimizer's feature constants currently because
// that would mess up its state tracking. We continue to let the
// optimizer handle expressions involving these.
//
// TODO: Can we unify this?
if ( util::startsWith(n.id().sub(1), "__feat") )
return std::nullopt;

auto const_ = n.declaration().tryAs<declaration::Constant>();
if ( ! const_ )
return std::nullopt;

auto x = _foldConstant(const_->value());
if ( ! x )
return std::nullopt;

return *x;
}

result_t operator()(const operator_::unsigned_integer::SignNeg& n, position_t p) {
auto op = foldConstant<ctor::UnsignedInteger>(n.op0());
if ( ! op )
Expand Down
24 changes: 0 additions & 24 deletions tests/Baseline/hilti.optimization.const/log
Original file line number Diff line number Diff line change
@@ -1,28 +1,4 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::f'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] inlining constant 'Foo::t'
[debug/optimizer] removing declaration for unused function hilti::abort
[debug/optimizer] removing declaration for unused function hilti::current_time
[debug/optimizer] removing declaration for unused function hilti::debug
Expand Down
32 changes: 16 additions & 16 deletions tests/Baseline/hilti.optimization.const/noopt.hlt
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,43 @@ import hilti;
const bool t = True;
const bool f = False;

hilti::print(Foo::t, True);
hilti::print(Foo::f, True);
hilti::print(True, True);
hilti::print(False, True);

if ( t ) {
if ( True ) {
0;
}
else {
1;
}


if ( f ) {
if ( False ) {
2;
}
else {
3;
}


if ( t ) {
if ( True ) {
4;
}


if ( f ) {
if ( False ) {
5;
}

t || t;
t || f;
f || t;
f || f;
t && t;
t && f;
f && t;
f && f;
! t;
! f;
True;
True;
True;
False;
True;
False;
False;
False;
False;
True;

}
12 changes: 12 additions & 0 deletions tests/Baseline/hilti.types.bool.fold/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
module Test {

const bool b1 = True;
const bool b2 = False;

assert True;
assert True;
assert True;
assert True;

}
17 changes: 17 additions & 0 deletions tests/hilti/types/bool/fold.hlt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# @TEST-EXEC: hiltic -p %INPUT >>output
# @TEST-EXEC: hiltic -j %INPUT >>output
# @TEST-EXEC: btest-diff output
#
# @TEST-DOC: Test boolean constant folding.

module Test {

const b1 = (True || False);
const b2 = (True && False);

assert True && True;
assert (True && (False || (!False)));
assert b1 || b2;
assert !(b1 && b2);

}

0 comments on commit 7ce919c

Please sign in to comment.