예제 #1
0
ExpressionPtr OrExpression::getDNFImpl() const
{
    UnaryExpression * leftLeaf = dynamic_cast<UnaryExpression*>(left());
    UnaryExpression * rightLeaf = dynamic_cast<UnaryExpression*>(right());

    // A or B
    if (leftLeaf && rightLeaf)
    {
        return clone();
    }

    // A or (B and C) => (A and B) or (A and C)
    BinaryExpression * rightAnd = dynamic_cast<AndExpression*>(right());
    if (leftLeaf && rightAnd)
    {
        return Or(And(leftLeaf, rightAnd->left()),
                  And(leftLeaf, rightAnd->right()));
    }

    // (A and B) or C => (A and C) or (B and C)
    BinaryExpression * leftAnd = dynamic_cast<AndExpression*>(left());
    if (leftAnd && rightLeaf)
    {
        return Or(And(leftAnd->left(),  rightLeaf),
                  And(leftAnd->right(), rightLeaf));
    }

    return Or(left()->getDNF(), right()->getDNF());
}
예제 #2
0
// visitForTest helps optimize statements with expressions like:
//    if (x && y || z)
//
// Where, with a naive conversion we would reduce (x && y) to a boolean, and
// then reduce (that || z) to another boolean, and another test - we can simply
// test each individual component and combine the jump paths with the paths
// the if-test needs to take.
//
// Unfortunately, this logic comes at a complexity price: it is illegal to
// emit non-statements from SemA, since the following situation could occur:
//    (1) SemA builds HIR chain #1 for statement X.
//    (2) SemA builds HIR chain #2 for statement X.
//    (3) SemA forces HIR chain #2 to be emitted to the code stream.
//    (4) SemA emits statement X, with HIR chain #1.
//
// In this situation, the HIR chains have been emitted out-of-order. So,
// visitForTest takes in a HIRList which it populates with instructions, which
// may include internal statements (like jumps and binds).
//
// The trueBranch and falseBranch parameters are self-explanatory. The
// fallthrough case describes which branch comes immediately after the
// test. This is used to optimize cases like:
//   if (x) {
//     ...
//   }
//   do {
//     ...
//   } while (y);
//
// After testing |x|, if it evaluated to true, there is no need to jump to the
// true branch, because we'll fallthrough (as long as the expression does not
// have logical ands/ors which could short-circuit). Similarly for |y|, the
// false condition does not need an actual jump target.
//
void
SemanticAnalysis::visitForTest(HIRList *output,
                               Expression *expr,
                               Label *trueBranch,
                               Label *falseBranch,
                               Label *fallthrough)
{
  Type *boolType = cc_.types()->getPrimitive(PrimitiveType::Bool);

  // Handle logical and/or.
  BinaryExpression *bin = expr->asBinaryExpression();
  if (bin && (bin->token() == TOK_AND || bin->token() == TOK_OR)) {
    HLabel *next = new (pool_) HLabel();
    if (bin->token() == TOK_AND)
      visitForTest(output, bin->left(), next, falseBranch, next);
    else
      visitForTest(output, bin->left(), trueBranch, next, next);
    output->append(new (pool_) HBind(expr, next));
    visitForTest(output, bin->right(), trueBranch, falseBranch, fallthrough);
    return;
  }

  // Handle equality and relational operators.
  if (bin && (bin->token() >= TOK_EQUALS && bin->token() <= TOK_GE)) {
    HIR *left = rvalue(bin->left());
    HIR *right = rvalue(bin->right());
    if (!left || !right)
      return;
    Type *coercion = coercionType(bin->token(), left, right);
    if (!coercion ||
        ((left = coerce(left, coercion, Coerce_Arg)) == nullptr) ||
        ((right = coerce(right, coercion, Coerce_Arg)) == nullptr))
    {
      return;
    }
    Label *target = (fallthrough == trueBranch) ? falseBranch : trueBranch;
    TokenKind token = (fallthrough == trueBranch)
                      ? InvertTest(bin->token())
                      : bin->token();
    output->append(new (pool_) HCompareAndJump(bin, token, left, right, target));
    return;
  }

  // Handle unary not (!)
  UnaryExpression *unary = expr->asUnaryExpression();
  if (unary && unary->token() == TOK_NOT) {
    // Re-invoke visitForTest but invert the branches. Note that we don't touch
    // |fallthrough|, since it's used to determine whether to jump on success
    // or failure, so inverting it as well would do nothing.
    visitForTest(output, unary->expression(), falseBranch, trueBranch, fallthrough);
    return;
  }

  // We couldn't match anything easy, so just coerce the input to a boolean.
  HIR *hir = rvalue(expr);
  if (!hir || ((hir = coerce(hir, boolType, Coerce_Assign)) == nullptr))
    return;

  if (fallthrough == falseBranch)
    output->append(new (pool_) HJump(expr, hir, true, trueBranch));
  else
    output->append(new (pool_) HJump(expr, hir, false, falseBranch));
}