示例#1
0
SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
                                  BinaryOperator::Opcode op,
                                  NonLoc lhs, NonLoc rhs,
                                  QualType resultTy)  {
  NonLoc InputLHS = lhs;
  NonLoc InputRHS = rhs;

  // Handle trivial case where left-side and right-side are the same.
  if (lhs == rhs)
    switch (op) {
      default:
        break;
      case BO_EQ:
      case BO_LE:
      case BO_GE:
        return makeTruthVal(true, resultTy);
      case BO_LT:
      case BO_GT:
      case BO_NE:
        return makeTruthVal(false, resultTy);
      case BO_Xor:
      case BO_Sub:
        if (resultTy->isIntegralOrEnumerationType())
          return makeIntVal(0, resultTy);
        return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy);
      case BO_Or:
      case BO_And:
        return evalCastFromNonLoc(lhs, resultTy);
    }

  while (1) {
    switch (lhs.getSubKind()) {
    default:
      return makeSymExprValNN(state, op, lhs, rhs, resultTy);
    case nonloc::LocAsIntegerKind: {
      Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
      switch (rhs.getSubKind()) {
        case nonloc::LocAsIntegerKind:
          return evalBinOpLL(state, op, lhsL,
                             cast<nonloc::LocAsInteger>(rhs).getLoc(),
                             resultTy);
        case nonloc::ConcreteIntKind: {
          // Transform the integer into a location and compare.
          llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
          BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
          return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
        }
        default:
          switch (op) {
            case BO_EQ:
              return makeTruthVal(false, resultTy);
            case BO_NE:
              return makeTruthVal(true, resultTy);
            default:
              // This case also handles pointer arithmetic.
              return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
          }
      }
    }
    case nonloc::ConcreteIntKind: {
      llvm::APSInt LHSValue = cast<nonloc::ConcreteInt>(lhs).getValue();

      // If we're dealing with two known constants, just perform the operation.
      if (const llvm::APSInt *KnownRHSValue = getKnownValue(state, rhs)) {
        llvm::APSInt RHSValue = *KnownRHSValue;
        if (BinaryOperator::isComparisonOp(op)) {
          // We're looking for a type big enough to compare the two values.
          // FIXME: This is not correct. char + short will result in a promotion
          // to int. Unfortunately we have lost types by this point.
          APSIntType CompareType = std::max(APSIntType(LHSValue),
                                            APSIntType(RHSValue));
          CompareType.apply(LHSValue);
          CompareType.apply(RHSValue);
        } else if (!BinaryOperator::isShiftOp(op)) {
          APSIntType IntType = BasicVals.getAPSIntType(resultTy);
          IntType.apply(LHSValue);
          IntType.apply(RHSValue);
        }

        const llvm::APSInt *Result =
          BasicVals.evalAPSInt(op, LHSValue, RHSValue);
        if (!Result)
          return UndefinedVal();

        return nonloc::ConcreteInt(*Result);
      }

      // Swap the left and right sides and flip the operator if doing so
      // allows us to better reason about the expression (this is a form
      // of expression canonicalization).
      // While we're at it, catch some special cases for non-commutative ops.
      switch (op) {
      case BO_LT:
      case BO_GT:
      case BO_LE:
      case BO_GE:
        op = ReverseComparison(op);
        // FALL-THROUGH
      case BO_EQ:
      case BO_NE:
      case BO_Add:
      case BO_Mul:
      case BO_And:
      case BO_Xor:
      case BO_Or:
        std::swap(lhs, rhs);
        continue;
      case BO_Shr:
        // (~0)>>a
        if (LHSValue.isAllOnesValue() && LHSValue.isSigned())
          return evalCastFromNonLoc(lhs, resultTy);
        // FALL-THROUGH
      case BO_Shl:
        // 0<<a and 0>>a
        if (LHSValue == 0)
          return evalCastFromNonLoc(lhs, resultTy);
        return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
      default:
        return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
      }
    }
    case nonloc::SymbolValKind: {
      // We only handle LHS as simple symbols or SymIntExprs.
      SymbolRef Sym = cast<nonloc::SymbolVal>(lhs).getSymbol();

      // LHS is a symbolic expression.
      if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) {

        // Is this a logical not? (!x is represented as x == 0.)
        if (op == BO_EQ && rhs.isZeroConstant()) {
          // We know how to negate certain expressions. Simplify them here.

          BinaryOperator::Opcode opc = symIntExpr->getOpcode();
          switch (opc) {
          default:
            // We don't know how to negate this operation.
            // Just handle it as if it were a normal comparison to 0.
            break;
          case BO_LAnd:
          case BO_LOr:
            llvm_unreachable("Logical operators handled by branching logic.");
          case BO_Assign:
          case BO_MulAssign:
          case BO_DivAssign:
          case BO_RemAssign:
          case BO_AddAssign:
          case BO_SubAssign:
          case BO_ShlAssign:
          case BO_ShrAssign:
          case BO_AndAssign:
          case BO_XorAssign:
          case BO_OrAssign:
          case BO_Comma:
            llvm_unreachable("'=' and ',' operators handled by ExprEngine.");
          case BO_PtrMemD:
          case BO_PtrMemI:
            llvm_unreachable("Pointer arithmetic not handled here.");
          case BO_LT:
          case BO_GT:
          case BO_LE:
          case BO_GE:
          case BO_EQ:
          case BO_NE:
            // Negate the comparison and make a value.
            opc = NegateComparison(opc);
            assert(symIntExpr->getType(Context) == resultTy);
            return makeNonLoc(symIntExpr->getLHS(), opc,
                symIntExpr->getRHS(), resultTy);
          }
        }

        // For now, only handle expressions whose RHS is a constant.
        if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) {
          // If both the LHS and the current expression are additive,
          // fold their constants and try again.
          if (BinaryOperator::isAdditiveOp(op)) {
            BinaryOperator::Opcode lop = symIntExpr->getOpcode();
            if (BinaryOperator::isAdditiveOp(lop)) {
              // Convert the two constants to a common type, then combine them.

              // resultTy may not be the best type to convert to, but it's
              // probably the best choice in expressions with mixed type
              // (such as x+1U+2LL). The rules for implicit conversions should
              // choose a reasonable type to preserve the expression, and will
              // at least match how the value is going to be used.
              APSIntType IntType = BasicVals.getAPSIntType(resultTy);
              const llvm::APSInt &first = IntType.convert(symIntExpr->getRHS());
              const llvm::APSInt &second = IntType.convert(*RHSValue);

              const llvm::APSInt *newRHS;
              if (lop == op)
                newRHS = BasicVals.evalAPSInt(BO_Add, first, second);
              else
                newRHS = BasicVals.evalAPSInt(BO_Sub, first, second);

              assert(newRHS && "Invalid operation despite common type!");
              rhs = nonloc::ConcreteInt(*newRHS);
              lhs = nonloc::SymbolVal(symIntExpr->getLHS());
              op = lop;
              continue;
            }
          }

          // Otherwise, make a SymIntExpr out of the expression.
          return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy);
        }


      } else if (isa<SymbolData>(Sym)) {
        // Does the symbol simplify to a constant?  If so, "fold" the constant
        // by setting 'lhs' to a ConcreteInt and try again.
        if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
          lhs = nonloc::ConcreteInt(*Constant);
          continue;
        }

        // Is the RHS a constant?
        if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
          return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
      }

      // Give up -- this is not a symbolic expression we can handle.
      return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
    }
    }
  }
}