Exemple #1
0
ExprVisitor::Action
IndexTransformationExprVisitor::visitConcat(const ConcatExpr &ce) {
  if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(0))) {
    if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) {
      if (width == Expr::InvalidWidth)
        width = ce.getWidth();
    }
  } else if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(1))) {
    if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) {
      if (width == Expr::InvalidWidth)
        width = ce.getWidth();
    }
  }
  return Action::doChildren();
}
Exemple #2
0
//-------------------------- VALUE-BASED OPTIMIZATION------------------------//
ExprVisitor::Action ArrayReadExprVisitor::visitConcat(const ConcatExpr &ce) {
  ReadExpr *base = ArrayExprHelper::hasOrderedReads(ce);
  if (base) {
    return inspectRead(ce.hash(), ce.getWidth(), *base);
  }
  return Action::doChildren();
}
Exemple #3
0
/** if *width_out!=1 then result is a bitvector,
    otherwise it is a bool */
ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) {
    int width;
    if (!width_out) width_out = &width;

    ++stats::queryConstructs;

    switch (e->getKind()) {
    case Expr::Constant: {
        ConstantExpr *CE = cast<ConstantExpr>(e);
        *width_out = CE->getWidth();

        // Coerce to bool if necessary.
        if (*width_out == 1)
            return CE->isTrue() ? getTrue() : getFalse();

        // Fast path.
        if (*width_out <= 32)
            return bvConst32(*width_out, CE->getZExtValue(32));
        if (*width_out <= 64)
            return bvConst64(*width_out, CE->getZExtValue());

        ref<ConstantExpr> Tmp = CE;
        ExprHandle Res = bvConst64(64, Tmp->Extract(0, 64)->getZExtValue());
        while (Tmp->getWidth() > 64) {
            Tmp = Tmp->Extract(64, Tmp->getWidth()-64);
            unsigned Width = std::min(64U, Tmp->getWidth());
            Res = vc_bvConcatExpr(vc, bvConst64(Width,
                                                Tmp->Extract(0, Width)->getZExtValue()),
                                  Res);
        }
        return Res;
    }

    // Special
    case Expr::NotOptimized: {
        NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
        return construct(noe->src, width_out);
    }

    case Expr::Read: {
        ReadExpr *re = cast<ReadExpr>(e);
        assert(re && re->updates.root);
        *width_out = re->updates.root->getRange();
        return vc_readExpr(vc,
                           getArrayForUpdate(re->updates.root, re->updates.head),
                           construct(re->index, 0));
    }

    case Expr::Select: {
        SelectExpr *se = cast<SelectExpr>(e);
        ExprHandle cond = construct(se->cond, 0);
        ExprHandle tExpr = construct(se->trueExpr, width_out);
        ExprHandle fExpr = construct(se->falseExpr, width_out);
        return vc_iteExpr(vc, cond, tExpr, fExpr);
    }

    case Expr::Concat: {
        ConcatExpr *ce = cast<ConcatExpr>(e);
        unsigned numKids = ce->getNumKids();
        ExprHandle res = construct(ce->getKid(numKids-1), 0);
        for (int i=numKids-2; i>=0; i--) {
            res = vc_bvConcatExpr(vc, construct(ce->getKid(i), 0), res);
        }
        *width_out = ce->getWidth();
        return res;
    }

    case Expr::Extract: {
        ExtractExpr *ee = cast<ExtractExpr>(e);
        ExprHandle src = construct(ee->expr, width_out);
        *width_out = ee->getWidth();
        if (*width_out==1) {
            return bvBoolExtract(src, ee->offset);
        } else {
            return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
        }
    }

    // Casting

    case Expr::ZExt: {
        int srcWidth;
        CastExpr *ce = cast<CastExpr>(e);
        ExprHandle src = construct(ce->src, &srcWidth);
        *width_out = ce->getWidth();
        if (srcWidth==1) {
            return vc_iteExpr(vc, src, bvOne(*width_out), bvZero(*width_out));
        } else {
            return vc_bvConcatExpr(vc, bvZero(*width_out-srcWidth), src);
        }
    }

    case Expr::SExt: {
        int srcWidth;
        CastExpr *ce = cast<CastExpr>(e);
        ExprHandle src = construct(ce->src, &srcWidth);
        *width_out = ce->getWidth();
        if (srcWidth==1) {
            return vc_iteExpr(vc, src, bvMinusOne(*width_out), bvZero(*width_out));
        } else {
            return vc_bvSignExtend(vc, src, *width_out);
        }
    }

    // Arithmetic

    case Expr::Add: {
        AddExpr *ae = cast<AddExpr>(e);
        ExprHandle left = construct(ae->left, width_out);
        ExprHandle right = construct(ae->right, width_out);
        assert(*width_out!=1 && "uncanonicalized add");
        return vc_bvPlusExpr(vc, *width_out, left, right);
    }

    case Expr::Sub: {
        SubExpr *se = cast<SubExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized sub");
        return vc_bvMinusExpr(vc, *width_out, left, right);
    }

    case Expr::Mul: {
        MulExpr *me = cast<MulExpr>(e);
        ExprHandle right = construct(me->right, width_out);
        assert(*width_out!=1 && "uncanonicalized mul");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(me->left))
            if (CE->getWidth() <= 64)
                return constructMulByConstant(right, *width_out,
                                              CE->getZExtValue());

        ExprHandle left = construct(me->left, width_out);
        return vc_bvMultExpr(vc, *width_out, left, right);
    }

    case Expr::UDiv: {
        UDivExpr *de = cast<UDivExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized udiv");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
            if (CE->getWidth() <= 64) {
                uint64_t divisor = CE->getZExtValue();

                if (bits64::isPowerOfTwo(divisor)) {
                    return bvRightShift(left,
                                        bits64::indexOfSingleBit(divisor));
                } else if (optimizeDivides) {
                    if (*width_out == 32) //only works for 32-bit division
                        return constructUDivByConstant( left, *width_out,
                                                        (uint32_t) divisor);
                }
            }
        }

        ExprHandle right = construct(de->right, width_out);
        return vc_bvDivExpr(vc, *width_out, left, right);
    }

    case Expr::SDiv: {
        SDivExpr *de = cast<SDivExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized sdiv");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right))
            if (optimizeDivides)
                if (*width_out == 32) //only works for 32-bit division
                    return constructSDivByConstant( left, *width_out,
                                                    CE->getZExtValue(32));

        // XXX need to test for proper handling of sign, not sure I
        // trust STP
        ExprHandle right = construct(de->right, width_out);
        return vc_sbvDivExpr(vc, *width_out, left, right);
    }

    case Expr::URem: {
        URemExpr *de = cast<URemExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        assert(*width_out!=1 && "uncanonicalized urem");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
            if (CE->getWidth() <= 64) {
                uint64_t divisor = CE->getZExtValue();

                if (bits64::isPowerOfTwo(divisor)) {
                    unsigned bits = bits64::indexOfSingleBit(divisor);

                    // special case for modding by 1 or else we bvExtract -1:0
                    if (bits == 0) {
                        return bvZero(*width_out);
                    } else {
                        return vc_bvConcatExpr(vc,
                                               bvZero(*width_out - bits),
                                               bvExtract(left, bits - 1, 0));
                    }
                }

                // Use fast division to compute modulo without explicit division for
                // constant divisor.

                if (optimizeDivides) {
                    if (*width_out == 32) { //only works for 32-bit division
                        ExprHandle quotient = constructUDivByConstant( left, *width_out, (uint32_t)divisor );
                        ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
                        ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
                        return rem;
                    }
                }
            }
        }

        ExprHandle right = construct(de->right, width_out);
        return vc_bvModExpr(vc, *width_out, left, right);
    }

    case Expr::SRem: {
        SRemExpr *de = cast<SRemExpr>(e);
        ExprHandle left = construct(de->left, width_out);
        ExprHandle right = construct(de->right, width_out);
        assert(*width_out!=1 && "uncanonicalized srem");

#if 0 //not faster per first benchmark
        if (optimizeDivides) {
            if (ConstantExpr *cre = de->right->asConstant()) {
                uint64_t divisor = cre->asUInt64;

                //use fast division to compute modulo without explicit division for constant divisor
                if( *width_out == 32 ) { //only works for 32-bit division
                    ExprHandle quotient = constructSDivByConstant( left, *width_out, divisor );
                    ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
                    ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
                    return rem;
                }
            }
        }
#endif

        // XXX implement my fast path and test for proper handling of sign
        return vc_sbvModExpr(vc, *width_out, left, right);
    }

    // Bitwise

    case Expr::Not: {
        NotExpr *ne = cast<NotExpr>(e);
        ExprHandle expr = construct(ne->expr, width_out);
        if (*width_out==1) {
            return vc_notExpr(vc, expr);
        } else {
            return vc_bvNotExpr(vc, expr);
        }
    }

    case Expr::And: {
        AndExpr *ae = cast<AndExpr>(e);
        ExprHandle left = construct(ae->left, width_out);
        ExprHandle right = construct(ae->right, width_out);
        if (*width_out==1) {
            return vc_andExpr(vc, left, right);
        } else {
            return vc_bvAndExpr(vc, left, right);
        }
    }

    case Expr::Or: {
        OrExpr *oe = cast<OrExpr>(e);
        ExprHandle left = construct(oe->left, width_out);
        ExprHandle right = construct(oe->right, width_out);
        if (*width_out==1) {
            return vc_orExpr(vc, left, right);
        } else {
            return vc_bvOrExpr(vc, left, right);
        }
    }

    case Expr::Xor: {
        XorExpr *xe = cast<XorExpr>(e);
        ExprHandle left = construct(xe->left, width_out);
        ExprHandle right = construct(xe->right, width_out);

        if (*width_out==1) {
            // XXX check for most efficient?
            return vc_iteExpr(vc, left,
                              ExprHandle(vc_notExpr(vc, right)), right);
        } else {
            return vc_bvXorExpr(vc, left, right);
        }
    }

    case Expr::Shl: {
        ShlExpr *se = cast<ShlExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        assert(*width_out!=1 && "uncanonicalized shl");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(se->right)) {
            return bvLeftShift(left, (unsigned) CE->getLimitedValue());
        } else {
            int shiftWidth;
            ExprHandle amount = construct(se->right, &shiftWidth);
            return bvVarLeftShift( left, amount);
        }
    }

    case Expr::LShr: {
        LShrExpr *lse = cast<LShrExpr>(e);
        ExprHandle left = construct(lse->left, width_out);
        assert(*width_out!=1 && "uncanonicalized lshr");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(lse->right)) {
            return bvRightShift(left, (unsigned) CE->getLimitedValue());
        } else {
            int shiftWidth;
            ExprHandle amount = construct(lse->right, &shiftWidth);
            return bvVarRightShift( left, amount);
        }
    }

    case Expr::AShr: {
        AShrExpr *ase = cast<AShrExpr>(e);
        ExprHandle left = construct(ase->left, width_out);
        assert(*width_out!=1 && "uncanonicalized ashr");

        if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ase->right)) {
            unsigned shift = (unsigned) CE->getLimitedValue();
            ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
            return constructAShrByConstant(left, shift, signedBool);
        } else {
            int shiftWidth;
            ExprHandle amount = construct(ase->right, &shiftWidth);
            return bvVarArithRightShift( left, amount);
        }
    }

    // Comparison

    case Expr::Eq: {
        EqExpr *ee = cast<EqExpr>(e);
        ExprHandle left = construct(ee->left, width_out);
        ExprHandle right = construct(ee->right, width_out);
        if (*width_out==1) {
            if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ee->left)) {
                if (CE->isTrue())
                    return right;
                return vc_notExpr(vc, right);
            } else {
                return vc_iffExpr(vc, left, right);
            }
        } else {
            *width_out = 1;
            return vc_eqExpr(vc, left, right);
        }
    }

    case Expr::Ult: {
        UltExpr *ue = cast<UltExpr>(e);
        ExprHandle left = construct(ue->left, width_out);
        ExprHandle right = construct(ue->right, width_out);
        assert(*width_out!=1 && "uncanonicalized ult");
        *width_out = 1;
        return vc_bvLtExpr(vc, left, right);
    }

    case Expr::Ule: {
        UleExpr *ue = cast<UleExpr>(e);
        ExprHandle left = construct(ue->left, width_out);
        ExprHandle right = construct(ue->right, width_out);
        assert(*width_out!=1 && "uncanonicalized ule");
        *width_out = 1;
        return vc_bvLeExpr(vc, left, right);
    }

    case Expr::Slt: {
        SltExpr *se = cast<SltExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized slt");
        *width_out = 1;
        return vc_sbvLtExpr(vc, left, right);
    }

    case Expr::Sle: {
        SleExpr *se = cast<SleExpr>(e);
        ExprHandle left = construct(se->left, width_out);
        ExprHandle right = construct(se->right, width_out);
        assert(*width_out!=1 && "uncanonicalized sle");
        *width_out = 1;
        return vc_sbvLeExpr(vc, left, right);
    }

        // unused due to canonicalization
#if 0
    case Expr::Ne:
    case Expr::Ugt:
    case Expr::Uge:
    case Expr::Sgt:
    case Expr::Sge:
#endif

    default:
        assert(0 && "unhandled Expr type");
        return vc_trueExpr(vc);
    }
}
Exemple #4
0
/** if *et_out==etBV then result is a bitvector,
    otherwise it is a bool */
ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out, STPExprType *et_out) {
  int width;
  if (!width_out) width_out = &width;

  ++stats::queryConstructs;

  switch (e->getKind()) {
  case Expr::Constant: {
    ConstantExpr *CE = cast<ConstantExpr>(e);
    *width_out = CE->getWidth();

    // Coerce to bool if necessary.
    if (*width_out == 1 && (*et_out == etBOOL || *et_out == etDontCare)) {
      *et_out = etBOOL;
      return CE->isTrue() ? getTrue() : getFalse();
    }

    *et_out = etBV;

    // Fast path.
    if (*width_out <= 32)
      return bvConst32(*width_out, CE->getZExtValue(32));
    if (*width_out <= 64)
      return bvConst64(*width_out, CE->getZExtValue());

    ref<ConstantExpr> Tmp = CE;
    ExprHandle Res = bvConst64(64, Tmp->Extract(0, 64)->getZExtValue());
    while (Tmp->getWidth() > 64) {
      Tmp = Tmp->Extract(64, Tmp->getWidth()-64);
      unsigned Width = std::min(64U, Tmp->getWidth());
      Res = vc_bvConcatExpr(vc, bvConst64(Width,
                                        Tmp->Extract(0, Width)->getZExtValue()),
                            Res);
    }
    return Res;
  }
    
  // Special
  case Expr::NotOptimized: {
    NotOptimizedExpr *noe = cast<NotOptimizedExpr>(e);
    return construct(noe->src, width_out, et_out);
  }

  case Expr::Read: {
    ReadExpr *re = cast<ReadExpr>(e);
    *width_out = 8;
    *et_out = etBV;
    return vc_readExpr(vc,
                       getArrayForUpdate(re->updates.root, re->updates.head),
                       construct(re->index, 0, etBV));
  }
    
  case Expr::Select: {
    SelectExpr *se = cast<SelectExpr>(e);
    ExprHandle cond = construct(se->cond, 0, etBOOL);
    ExprHandle tExpr = construct(se->trueExpr, width_out, etBV);
    ExprHandle fExpr = construct(se->falseExpr, width_out, etBV);
    *et_out = etBV;
    return vc_iteExpr(vc, cond, tExpr, fExpr);
  }

  case Expr::Concat: {
    ConcatExpr *ce = cast<ConcatExpr>(e);
    unsigned numKids = ce->getNumKids();
    ExprHandle res = construct(ce->getKid(numKids-1), 0, etBV);
    for (int i=numKids-2; i>=0; i--) {
      res = vc_bvConcatExpr(vc, construct(ce->getKid(i), 0, etBV), res);
    }
    *width_out = ce->getWidth();
    *et_out = etBV;
    return res;
  }

  case Expr::Extract: {
    ExtractExpr *ee = cast<ExtractExpr>(e);
    ExprHandle src = construct(ee->expr, width_out, etBV);    
    *width_out = ee->getWidth();
    *et_out = etBV;
    return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
  }

    // Casting

  case Expr::ZExt: {
    int srcWidth;
    CastExpr *ce = cast<CastExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle src = construct(ce->src, &srcWidth, &src_rt);
    *width_out = ce->getWidth();
    *et_out = etBV;
    if (src_rt==etBOOL) {
      return vc_iteExpr(vc, src, bvOne(*width_out), bvZero(*width_out));
    } else {
      return vc_bvConcatExpr(vc, bvZero(*width_out-srcWidth), src);
    }
  }

  case Expr::SExt: {
    int srcWidth;
    CastExpr *ce = cast<CastExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle src = construct(ce->src, &srcWidth, &src_rt);
    *width_out = ce->getWidth();
    *et_out = etBV;
    if (src_rt==etBOOL) {
      return vc_iteExpr(vc, src, bvMinusOne(*width_out), bvZero(*width_out));
    } else {
      return vc_bvSignExtend(vc, src, *width_out);
    }
  }

    // Arithmetic

  case Expr::Add: {
    AddExpr *ae = cast<AddExpr>(e);
    ExprHandle left = construct(ae->left, width_out, etBV);
    ExprHandle right = construct(ae->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized add");
    *et_out = etBV;
    return vc_bvPlusExpr(vc, *width_out, left, right);
  }

  case Expr::Sub: {
    SubExpr *se = cast<SubExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sub");
    *et_out = etBV;
    return vc_bvMinusExpr(vc, *width_out, left, right);
  } 

  case Expr::Mul: {
    MulExpr *me = cast<MulExpr>(e);
    ExprHandle right = construct(me->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized mul");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(me->left))
      if (CE->getWidth() <= 64)
        return constructMulByConstant(right, *width_out, 
                                      CE->getZExtValue());

    ExprHandle left = construct(me->left, width_out, etBV);
    return vc_bvMultExpr(vc, *width_out, left, right);
  }

  case Expr::UDiv: {
    UDivExpr *de = cast<UDivExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized udiv");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
      if (CE->getWidth() <= 64) {
        uint64_t divisor = CE->getZExtValue();
      
        if (bits64::isPowerOfTwo(divisor)) {
          return bvRightShift(left,
                              bits64::indexOfSingleBit(divisor),
                              getShiftBits(*width_out));
        } else if (optimizeDivides) {
          if (*width_out == 32) //only works for 32-bit division
            return constructUDivByConstant( left, *width_out, 
                                            (uint32_t) divisor);
        }
      }
    } 

    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_bvDivExpr(vc, *width_out, left, right);
  }

  case Expr::SDiv: {
    SDivExpr *de = cast<SDivExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sdiv");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right))
      if (optimizeDivides)
	if (*width_out == 32) //only works for 32-bit division
	  return constructSDivByConstant( left, *width_out, 
                                          CE->getZExtValue(32));

    // XXX need to test for proper handling of sign, not sure I
    // trust STP
    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_sbvDivExpr(vc, *width_out, left, right);
  }

  case Expr::URem: {
    URemExpr *de = cast<URemExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized urem");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(de->right)) {
      if (CE->getWidth() <= 64) {
        uint64_t divisor = CE->getZExtValue();

        if (bits64::isPowerOfTwo(divisor)) {
          unsigned bits = bits64::indexOfSingleBit(divisor);

          // special case for modding by 1 or else we bvExtract -1:0
          if (bits == 0) {
            return bvZero(*width_out);
          } else {
            return vc_bvConcatExpr(vc,
                                   bvZero(*width_out - bits),
                                   bvExtract(left, bits - 1, 0));
          }
        }

        // Use fast division to compute modulo without explicit division for
        // constant divisor.

        if (optimizeDivides) {
          if (*width_out == 32) { //only works for 32-bit division
            ExprHandle quotient = constructUDivByConstant( left, *width_out, (uint32_t)divisor );
            ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
            ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
            return rem;
          }
        }
      }
    }
    
    ExprHandle right = construct(de->right, width_out, etBV);
    return vc_bvModExpr(vc, *width_out, left, right);
  }

  case Expr::SRem: {
    SRemExpr *de = cast<SRemExpr>(e);
    ExprHandle left = construct(de->left, width_out, etBV);
    ExprHandle right = construct(de->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized srem");
    *et_out = etBV;

#if 0 //not faster per first benchmark
    if (optimizeDivides) {
      if (ConstantExpr *cre = de->right->asConstant()) {
	uint64_t divisor = cre->asUInt64;

	//use fast division to compute modulo without explicit division for constant divisor
      	if( *width_out == 32 ) { //only works for 32-bit division
	  ExprHandle quotient = constructSDivByConstant( left, *width_out, divisor );
	  ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
	  ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
	  return rem;
	}
      }
    }
#endif

    // XXX implement my fast path and test for proper handling of sign
    return vc_sbvModExpr(vc, *width_out, left, right);
  }

    // Bitwise

  case Expr::Not: {
    NotExpr *ne = cast<NotExpr>(e);
    ExprHandle expr = construct(ne->expr, width_out, et_out);
    if (*et_out == etBOOL) {
      return vc_notExpr(vc, expr);
    } else {
      return vc_bvNotExpr(vc, expr);
    }
  }    

  case Expr::And: {
    AndExpr *ae = cast<AndExpr>(e);
    ExprHandle left = construct(ae->left, width_out, et_out);
    ExprHandle right = construct(ae->right, width_out, *et_out);
    if (*et_out == etBOOL) {
      return vc_andExpr(vc, left, right);
    } else {
      return vc_bvAndExpr(vc, left, right);
    }
  }

  case Expr::Or: {
    OrExpr *oe = cast<OrExpr>(e);
    ExprHandle left = construct(oe->left, width_out, et_out);
    ExprHandle right = construct(oe->right, width_out, *et_out);
    if (*et_out == etBOOL) {
      return vc_orExpr(vc, left, right);
    } else {
      return vc_bvOrExpr(vc, left, right);
    }
  }

  case Expr::Xor: {
    XorExpr *xe = cast<XorExpr>(e);
    ExprHandle left = construct(xe->left, width_out, et_out);
    ExprHandle right = construct(xe->right, width_out, *et_out);
    
    if (*et_out == etBOOL) {
      // XXX check for most efficient?
      return vc_iteExpr(vc, left, 
                        ExprHandle(vc_notExpr(vc, right)), right);
    } else {
      return vc_bvXorExpr(vc, left, right);
    }
  }

  case Expr::Shl: {
    ShlExpr *se = cast<ShlExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized shl");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(se->right)) {
      return bvLeftShift(left, (unsigned) CE->getLimitedValue(), 
                         getShiftBits(*width_out));
    } else {
      int shiftWidth;
      ExprHandle amount = construct(se->right, &shiftWidth, etBV);
      return bvVarLeftShift( left, amount, *width_out );
    }
  }

  case Expr::LShr: {
    LShrExpr *lse = cast<LShrExpr>(e);
    ExprHandle left = construct(lse->left, width_out, etBV);
    unsigned shiftBits = getShiftBits(*width_out);
    assert(*width_out!=1 && "uncanonicalized lshr");
    *et_out = etBV;

    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(lse->right)) {
      return bvRightShift(left, (unsigned) CE->getLimitedValue(), 
                          shiftBits);
    } else {
      int shiftWidth;
      ExprHandle amount = construct(lse->right, &shiftWidth, etBV);
      return bvVarRightShift( left, amount, *width_out );
    }
  }

  case Expr::AShr: {
    AShrExpr *ase = cast<AShrExpr>(e);
    ExprHandle left = construct(ase->left, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ashr");
    *et_out = etBV;
    
    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ase->right)) {
      unsigned shift = (unsigned) CE->getLimitedValue();
      ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
      return constructAShrByConstant(left, shift, signedBool, 
                                     getShiftBits(*width_out));
    } else {
      int shiftWidth;
      ExprHandle amount = construct(ase->right, &shiftWidth, etBV);
      return bvVarArithRightShift( left, amount, *width_out );
    }
  }

    // Comparison

  case Expr::Eq: {
    EqExpr *ee = cast<EqExpr>(e);
    STPExprType src_rt = etDontCare;
    ExprHandle left = construct(ee->left, width_out, &src_rt);
    ExprHandle right = construct(ee->right, width_out, src_rt);
    *et_out = etBOOL;
    *width_out = 1;
    if (src_rt == etBOOL) {
      if (ConstantExpr *CE = dyn_cast<ConstantExpr>(ee->left)) {
        if (CE->isTrue())
          return right;
        return vc_notExpr(vc, right);
      } else {
        return vc_iffExpr(vc, left, right);
      }
    } else {
      return vc_eqExpr(vc, left, right);
    }
  }

  case Expr::Ult: {
    UltExpr *ue = cast<UltExpr>(e);
    ExprHandle left = construct(ue->left, width_out, etBV);
    ExprHandle right = construct(ue->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ult");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_bvLtExpr(vc, left, right);
  }

  case Expr::Ule: {
    UleExpr *ue = cast<UleExpr>(e);
    ExprHandle left = construct(ue->left, width_out, etBV);
    ExprHandle right = construct(ue->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized ule");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_bvLeExpr(vc, left, right);
  }

  case Expr::Slt: {
    SltExpr *se = cast<SltExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized slt");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_sbvLtExpr(vc, left, right);
  }

  case Expr::Sle: {
    SleExpr *se = cast<SleExpr>(e);
    ExprHandle left = construct(se->left, width_out, etBV);
    ExprHandle right = construct(se->right, width_out, etBV);
    assert(*width_out!=1 && "uncanonicalized sle");
    *width_out = 1;
    *et_out = etBOOL;
    return vc_sbvLeExpr(vc, left, right);
  }

    // unused due to canonicalization
#if 0
  case Expr::Ne:
  case Expr::Ugt:
  case Expr::Uge:
  case Expr::Sgt:
  case Expr::Sge:
#endif

  case Expr::FPToSI:
  case Expr::FPToUI: {
    if (UseFPToIAbstraction) {
      std::ostringstream ss;
      ss << "FPtoI" << fpCount++;
      *width_out = e->getWidth();
      *et_out = etBV;
      return buildVar(ss.str().c_str(), e->getWidth());
    } else {
      F2IConvertExpr *ce = cast<F2IConvertExpr>(e);
      ref<Expr> res = floatUtils(ce->src,
          ce->roundNearest()
            ? ieee_floatt::ROUND_TO_EVEN
            : ieee_floatt::ROUND_TO_ZERO).to_integer(ce->src, ce->getWidth(),
                                                  e->getKind() == Expr::FPToSI);
      return constructActual(res, width_out, et_out);
    }
  }

  case Expr::UIToFP: {
    UIToFPExpr *ue = cast<UIToFPExpr>(e);
    ref<Expr> res = floatUtils(e).from_unsigned_integer(ue->src);
    return constructActual(res, width_out, et_out);
  }

  case Expr::SIToFP: {
    SIToFPExpr *se = cast<SIToFPExpr>(e);
    ref<Expr> res = floatUtils(e).from_signed_integer(se->src);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FCmp: {
    FCmpExpr *ce = cast<FCmpExpr>(e);
    float_utilst &u = floatUtils(ce->left);
    ref<Expr> res;
    switch (ce->getPredicate()) {
    case FCmpExpr::OEQ:
      res = u.relation(ce->left, float_utilst::EQ, ce->right);
      break;
    case FCmpExpr::OGT:
      res = u.relation(ce->left, float_utilst::GT, ce->right);
      break;
    case FCmpExpr::OGE:
      res = u.relation(ce->left, float_utilst::GE, ce->right);
      break;
    case FCmpExpr::OLT:
      res = u.relation(ce->left, float_utilst::LT, ce->right);
      break;
    case FCmpExpr::OLE:
      res = u.relation(ce->left, float_utilst::LE, ce->right);
      break;
    case FCmpExpr::ONE:
      res = OrExpr::create(u.relation(ce->left, float_utilst::LT, ce->right),
                           u.relation(ce->left, float_utilst::GT, ce->right));
      break;
    case FCmpExpr::ORD:
      res = Expr::createIsZero(OrExpr::create(u.is_NaN(ce->left),
                                              u.is_NaN(ce->right)));
      break;
    case FCmpExpr::UNO:
      res = OrExpr::create(u.is_NaN(ce->left),
                           u.is_NaN(ce->right));
      break;
    case FCmpExpr::UEQ:
      res = Expr::createIsZero(
              OrExpr::create(u.relation(ce->left, float_utilst::LT, ce->right),
                            u.relation(ce->left, float_utilst::GT, ce->right)));
      break;
    case FCmpExpr::UGT:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::LE, ce->right));
      break;
    case FCmpExpr::UGE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::LT, ce->right));
      break;
    case FCmpExpr::ULT:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::GE, ce->right));
      break;
    case FCmpExpr::ULE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::GT, ce->right));
      break;
    case FCmpExpr::UNE:
      res = Expr::createIsZero(
              u.relation(ce->left, float_utilst::EQ, ce->right));
      break;
    default:
      assert(0 && "fp cmp not implemented yet");
    }
    return constructActual(res, width_out, et_out);
  }

  case Expr::FPExt:
  case Expr::FPTrunc: {
    F2FConvertExpr *ce = cast<F2FConvertExpr>(e);
    float_utilst &fromu = floatUtils(ce->src), &tou = floatUtils(ce);
    ref<Expr> res = fromu.conversion(ce->src, tou.spec);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FAdd: {
    FAddExpr *ae = cast<FAddExpr>(e);
    ref<Expr> res = floatUtils(e).add(ae->left, ae->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FSub: {
    FSubExpr *se = cast<FSubExpr>(e);
    ref<Expr> res = floatUtils(e).sub(se->left, se->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FMul: {
    FMulExpr *me = cast<FMulExpr>(e);
    ref<Expr> res = floatUtils(e).mul(me->left, me->right);
    return constructActual(res, width_out, et_out);
  }

  case Expr::FDiv: {
    FDivExpr *de = cast<FDivExpr>(e);
    ref<Expr> res = floatUtils(e).div(de->left, de->right);
    return constructActual(res, width_out, et_out);
  }

  default: 
    assert(0 && "unhandled Expr type");
    *et_out = etBOOL;
    return vc_trueExpr(vc);
  }
}