[analyzer] Add an abstraction for the bit width and signedness of an APSInt. No functionality change.

There are more parts of the analyzer that could use the convenience of APSIntType, particularly the constraint engine, but that needs a fair amount of rewriting to handle mixed-type constraints anyway.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156360 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jordy Rose 2012-05-08 03:26:58 +00:00
Родитель 4ccf0043c6
Коммит d3b6d99cd5
3 изменённых файлов: 120 добавлений и 51 удалений

Просмотреть файл

@ -0,0 +1,86 @@
//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_SA_CORE_APSINTTYPE_H
#define LLVM_CLANG_SA_CORE_APSINTTYPE_H
#include "llvm/ADT/APSInt.h"
namespace clang {
namespace ento {
/// \brief A record of the "type" of an APSInt, used for conversions.
class APSIntType {
uint32_t BitWidth;
bool IsUnsigned;
public:
APSIntType(uint32_t Width, bool Unsigned)
: BitWidth(Width), IsUnsigned(Unsigned) {}
/* implicit */ APSIntType(const llvm::APSInt &Value)
: BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {}
uint32_t getBitWidth() const { return BitWidth; }
bool isUnsigned() const { return IsUnsigned; }
/// \brief Convert a given APSInt, in place, to match this type.
///
/// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives
/// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF).
void apply(llvm::APSInt &Value) const {
// Note the order here. We extend first to preserve the sign, if this value
// is signed, /then/ match the signedness of the result type.
Value = Value.extOrTrunc(BitWidth);
Value.setIsUnsigned(IsUnsigned);
}
/// Convert and return a new APSInt with the given value, but this
/// type's bit width and signedness.
///
/// \see apply
llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY {
llvm::APSInt Result(Value, Value.isUnsigned());
apply(Result);
return Result;
}
/// Returns the minimum value for this type.
llvm::APSInt getMinValue() const LLVM_READONLY {
return llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
}
/// Returns the maximum value for this type.
llvm::APSInt getMaxValue() const LLVM_READONLY {
return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
}
bool operator==(const APSIntType &Other) const {
return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
}
/// \brief Provide an ordering for finding a common conversion type.
///
/// Unsigned integers are considered to be better conversion types than
/// signed integers of the same width.
bool operator<(const APSIntType &Other) const {
if (BitWidth < Other.BitWidth)
return true;
if (BitWidth > Other.BitWidth)
return false;
if (!IsUnsigned && Other.IsUnsigned)
return true;
return false;
}
};
} // end ento namespace
} // end clang namespace
#endif

Просмотреть файл

@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@ -86,28 +87,30 @@ public:
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
/// Returns the type of the APSInt used to store values of the given QualType.
APSIntType getAPSIntType(QualType T) const {
assert(T->isIntegerType() || Loc::isLocType(T));
return APSIntType(Ctx.getTypeSize(T),
!T->isSignedIntegerOrEnumerationType());
}
/// Convert - Create a new persistent APSInt with the same value as 'From'
/// but with the bitwidth and signedness of 'To'.
const llvm::APSInt &Convert(const llvm::APSInt& To,
const llvm::APSInt& From) {
if (To.isUnsigned() == From.isUnsigned() &&
To.getBitWidth() == From.getBitWidth())
APSIntType TargetType(To);
if (TargetType == APSIntType(From))
return From;
return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
return getValue(TargetType.convert(From));
}
const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
assert(T->isIntegerType() || Loc::isLocType(T));
unsigned bitwidth = Ctx.getTypeSize(T);
bool isUnsigned
= T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
APSIntType TargetType = getAPSIntType(T);
if (TargetType == APSIntType(From))
return From;
return getValue(From.getSExtValue(), bitwidth, isUnsigned);
return getValue(TargetType.convert(From));
}
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
@ -116,25 +119,19 @@ public:
}
inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
return getValue(APSIntType(v).getMaxValue());
}
inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
return getValue(APSIntType(v).getMinValue());
}
inline const llvm::APSInt& getMaxValue(QualType T) {
assert(T->isIntegerType() || Loc::isLocType(T));
bool isUnsigned
= T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
return getValue(getAPSIntType(T).getMaxValue());
}
inline const llvm::APSInt& getMinValue(QualType T) {
assert(T->isIntegerType() || Loc::isLocType(T));
bool isUnsigned
= T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
return getValue(getAPSIntType(T).getMinValue());
}
inline const llvm::APSInt& Add1(const llvm::APSInt& V) {

Просмотреть файл

@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
@ -106,9 +107,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
return UnknownVal();
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
Loc::isLocType(castTy));
i = i.extOrTrunc(Context.getTypeSize(castTy));
BasicVals.getAPSIntType(castTy).apply(i);
if (isLocType)
return makeIntLocVal(i);
@ -139,9 +138,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
return makeLocAsInteger(val, BitWidth);
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
Loc::isLocType(castTy));
i = i.extOrTrunc(BitWidth);
BasicVals.getAPSIntType(castTy).apply(i);
return makeIntVal(i);
}
@ -341,8 +338,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
i.setIsUnsigned(true);
i = i.extOrTrunc(Context.getTypeSize(Context.VoidPtrTy));
BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
}
default:
@ -365,23 +361,16 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
llvm::APSInt RHSValue = *KnownRHSValue;
if (BinaryOperator::isComparisonOp(op)) {
// We're looking for a type big enough to compare the two values.
uint32_t LeftWidth = LHSValue.getBitWidth();
uint32_t RightWidth = RHSValue.getBitWidth();
// Based on the conversion rules of [C99 6.3.1.8] and the example
// in SemaExpr's handleIntegerConversion().
if (LeftWidth > RightWidth)
RHSValue = RHSValue.extend(LeftWidth);
else if (LeftWidth < RightWidth)
LHSValue = LHSValue.extend(RightWidth);
else if (LHSValue.isUnsigned() != RHSValue.isUnsigned()) {
LHSValue.setIsUnsigned(true);
RHSValue.setIsUnsigned(true);
}
// 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)) {
// FIXME: These values don't need to be persistent.
LHSValue = BasicVals.Convert(resultTy, LHSValue);
RHSValue = BasicVals.Convert(resultTy, RHSValue);
APSIntType IntType = BasicVals.getAPSIntType(resultTy);
IntType.apply(LHSValue);
IntType.apply(RHSValue);
}
const llvm::APSInt *Result =
@ -490,12 +479,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// (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.
// FIXME: These values don't need to be persistent.
const llvm::APSInt &first =
BasicVals.Convert(resultTy, symIntExpr->getRHS());
const llvm::APSInt &second =
BasicVals.Convert(resultTy, *RHSValue);
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)