summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp30
-rw-r--r--clang/lib/Basic/FixedPoint.cpp37
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp75
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp2
-rw-r--r--clang/lib/Sema/SemaChecking.cpp45
-rw-r--r--clang/lib/Sema/SemaExpr.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp4
12 files changed, 180 insertions, 29 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 85690c76e03..6c69ca31c0e 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1718,6 +1718,8 @@ bool CastExpr::CastConsistency() const {
case CK_ZeroToOCLOpaqueType:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 44ccb74e3f7..1a21ad2539d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9776,6 +9776,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -9810,6 +9811,19 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Success(IntResult, E);
}
+ case CK_FixedPointToIntegral: {
+ APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SrcType));
+ if (!EvaluateFixedPoint(SubExpr, Src, Info))
+ return false;
+ bool Overflowed;
+ llvm::APSInt Result = Src.convertToInt(
+ Info.Ctx.getIntWidth(DestType),
+ DestType->isSignedIntegerOrEnumerationType(), &Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Result, DestType))
+ return false;
+ return Success(Result, E);
+ }
+
case CK_FixedPointToBoolean: {
// Unsigned padding does not affect this.
APValue Val;
@@ -9970,6 +9984,20 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
return Success(Result, E);
}
+ case CK_IntegralToFixedPoint: {
+ APSInt Src;
+ if (!EvaluateInteger(SubExpr, Src, Info))
+ return false;
+
+ bool Overflowed;
+ APFixedPoint IntResult = APFixedPoint::getFromIntValue(
+ Src, Info.Ctx.getFixedPointSemantics(DestType), &Overflowed);
+
+ if (Overflowed && !HandleOverflow(Info, E, IntResult, DestType))
+ return false;
+
+ return Success(IntResult, E);
+ }
case CK_NoOp:
case CK_LValueToRValue:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -10371,6 +10399,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
diff --git a/clang/lib/Basic/FixedPoint.cpp b/clang/lib/Basic/FixedPoint.cpp
index ca84a0cf483..f049e6f64a5 100644
--- a/clang/lib/Basic/FixedPoint.cpp
+++ b/clang/lib/Basic/FixedPoint.cpp
@@ -218,4 +218,41 @@ APFixedPoint APFixedPoint::negate(bool *Overflow) const {
return APFixedPoint(Sema);
}
+llvm::APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
+ bool *Overflow) const {
+ llvm::APSInt Result = getIntPart();
+ unsigned SrcWidth = getWidth();
+
+ llvm::APSInt DstMin = llvm::APSInt::getMinValue(DstWidth, !DstSign);
+ llvm::APSInt DstMax = llvm::APSInt::getMaxValue(DstWidth, !DstSign);
+
+ if (SrcWidth < DstWidth) {
+ Result = Result.extend(DstWidth);
+ } else if (SrcWidth > DstWidth) {
+ DstMin = DstMin.extend(SrcWidth);
+ DstMax = DstMax.extend(SrcWidth);
+ }
+
+ if (Overflow) {
+ if (Result.isSigned() && !DstSign) {
+ *Overflow = Result.isNegative() || Result.ugt(DstMax);
+ } else if (Result.isUnsigned() && DstSign) {
+ *Overflow = Result.ugt(DstMax);
+ } else {
+ *Overflow = Result < DstMin || Result > DstMax;
+ }
+ }
+
+ Result.setIsSigned(DstSign);
+ return Result.extOrTrunc(DstWidth);
+}
+
+APFixedPoint APFixedPoint::getFromIntValue(const llvm::APSInt &Value,
+ const FixedPointSemantics &DstFXSema,
+ bool *Overflow) {
+ FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
+ Value.getBitWidth(), Value.isSigned());
+ return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
+}
+
} // namespace clang
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 09ba2a0eb71..33fbb48bc5b 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4162,6 +4162,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index d9d8264c185..161d6ed34eb 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -853,6 +853,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 2e69d925fb4..3ae08edd5ae 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -509,6 +509,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 62cc12c7def..64ad582c581 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -876,6 +876,8 @@ public:
case CK_FloatingCast:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
case CK_ZeroToOCLOpaqueType:
return nullptr;
}
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index e831c823da7..83e9349492a 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -363,11 +363,14 @@ public:
SourceLocation Loc,
ScalarConversionOpts Opts = ScalarConversionOpts());
+ /// Convert between either a fixed point and other fixed point or fixed point
+ /// and an integer.
Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy,
SourceLocation Loc);
Value *EmitFixedPointConversion(Value *Src, FixedPointSemantics &SrcFixedSema,
FixedPointSemantics &DstFixedSema,
- SourceLocation Loc);
+ SourceLocation Loc,
+ bool DstIsInteger = false);
/// Emit a conversion from the specified complex type to the specified
/// destination type, where the destination type is an LLVM scalar type.
@@ -1225,17 +1228,25 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// TODO(leonardchan): When necessary, add another if statement checking for
// conversions to fixed point types from other types.
if (SrcType->isFixedPointType()) {
- if (DstType->isFixedPointType()) {
- return EmitFixedPointConversion(Src, SrcType, DstType, Loc);
- } else if (DstType->isBooleanType()) {
+ if (DstType->isBooleanType())
+ // It is important that we check this before checking if the dest type is
+ // an integer because booleans are technically integer types.
// We do not need to check the padding bit on unsigned types if unsigned
// padding is enabled because overflow into this bit is undefined
// behavior.
return Builder.CreateIsNotNull(Src, "tobool");
- }
+ if (DstType->isFixedPointType() || DstType->isIntegerType())
+ return EmitFixedPointConversion(Src, SrcType, DstType, Loc);
llvm_unreachable(
- "Unhandled scalar conversion involving a fixed point type.");
+ "Unhandled scalar conversion from a fixed point type to another type.");
+ } else if (DstType->isFixedPointType()) {
+ if (SrcType->isIntegerType())
+ // This also includes converting booleans and enums to fixed point types.
+ return EmitFixedPointConversion(Src, SrcType, DstType, Loc);
+
+ llvm_unreachable(
+ "Unhandled scalar conversion to a fixed point type from another type.");
}
QualType NoncanonicalSrcType = SrcType;
@@ -1443,19 +1454,17 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
QualType DstTy,
SourceLocation Loc) {
- assert(SrcTy->isFixedPointType());
- assert(DstTy->isFixedPointType());
-
FixedPointSemantics SrcFPSema =
CGF.getContext().getFixedPointSemantics(SrcTy);
FixedPointSemantics DstFPSema =
CGF.getContext().getFixedPointSemantics(DstTy);
- return EmitFixedPointConversion(Src, SrcFPSema, DstFPSema, Loc);
+ return EmitFixedPointConversion(Src, SrcFPSema, DstFPSema, Loc,
+ DstTy->isIntegerType());
}
Value *ScalarExprEmitter::EmitFixedPointConversion(
Value *Src, FixedPointSemantics &SrcFPSema, FixedPointSemantics &DstFPSema,
- SourceLocation Loc) {
+ SourceLocation Loc, bool DstIsInteger) {
using llvm::APInt;
using llvm::ConstantInt;
using llvm::Value;
@@ -1472,13 +1481,26 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(
Value *Result = Src;
unsigned ResultWidth = SrcWidth;
- if (!DstFPSema.isSaturated()) {
- // Downscale.
- if (DstScale < SrcScale)
- Result = SrcIsSigned ?
- Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
- Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
+ // Downscale.
+ if (DstScale < SrcScale) {
+ // When converting to integers, we round towards zero. For negative numbers,
+ // right shifting rounds towards negative infinity. In this case, we can
+ // just round up before shifting.
+ if (DstIsInteger && SrcIsSigned) {
+ Value *Zero = llvm::Constant::getNullValue(Result->getType());
+ Value *IsNegative = Builder.CreateICmpSLT(Result, Zero);
+ Value *LowBits = ConstantInt::get(
+ CGF.getLLVMContext(), APInt::getLowBitsSet(ResultWidth, SrcScale));
+ Value *Rounded = Builder.CreateAdd(Result, LowBits);
+ Result = Builder.CreateSelect(IsNegative, Rounded, Result);
+ }
+ Result = SrcIsSigned
+ ? Builder.CreateAShr(Result, SrcScale - DstScale, "downscale")
+ : Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
+ }
+
+ if (!DstFPSema.isSaturated()) {
// Resize.
Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
@@ -1493,10 +1515,6 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(
llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth);
Result = Builder.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize");
Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
- } else if (DstScale < SrcScale) {
- Result = SrcIsSigned ?
- Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
- Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
}
// Handle saturation.
@@ -2228,6 +2246,21 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitScalarConversion(Visit(E), E->getType(), DestTy,
CE->getExprLoc());
+ case CK_FixedPointToIntegral:
+ assert(E->getType()->isFixedPointType() &&
+ "Expected src type to be fixed point type");
+ assert(DestTy->isIntegerType() && "Expected dest type to be an integer");
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+
+ case CK_IntegralToFixedPoint:
+ assert(E->getType()->isIntegerType() &&
+ "Expected src type to be an integer");
+ assert(DestTy->isFixedPointType() &&
+ "Expected dest type to be fixed point type");
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+
case CK_IntegralCast: {
ScalarConversionOpts Opts;
if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 3a628b9af68..4dfe170ed62 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1086,6 +1086,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint:
llvm_unreachable("Fixed point types are disabled for Objective-C");
}
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5d9ae18267b..8dc9c7ffcdb 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11018,10 +11018,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
return;
}
+ // Valid casts involving fixed point types should be accounted for here.
if (Source->isFixedPointType()) {
- // TODO: Only CK_FixedPointCast is supported now. The other valid casts
- // should be accounted for here.
- if (Target->isFixedPointType()) {
+ if (Target->isUnsaturatedFixedPointType()) {
Expr::EvalResult Result;
if (E->EvaluateAsFixedPoint(Result, S.Context,
Expr::SE_AllowSideEffects)) {
@@ -11037,6 +11036,46 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
return;
}
}
+ } else if (Target->isIntegerType()) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsFixedPoint(Result, S.Context,
+ Expr::SE_AllowSideEffects)) {
+ APFixedPoint FXResult = Result.Val.getFixedPoint();
+
+ bool Overflowed;
+ llvm::APSInt IntResult = FXResult.convertToInt(
+ S.Context.getIntWidth(T),
+ Target->isSignedIntegerOrEnumerationType(), &Overflowed);
+
+ if (Overflowed) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_fixed_point_range)
+ << FXResult.toString() << T
+ << E->getSourceRange()
+ << clang::SourceRange(CC));
+ return;
+ }
+ }
+ }
+ } else if (Target->isUnsaturatedFixedPointType()) {
+ if (Source->isIntegerType()) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) {
+ llvm::APSInt Value = Result.Val.getInt();
+
+ bool Overflowed;
+ APFixedPoint IntResult = APFixedPoint::getFromIntValue(
+ Value, S.Context.getFixedPointSemantics(T), &Overflowed);
+
+ if (Overflowed) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_fixed_point_range)
+ << Value.toString(/*radix=*/10) << T
+ << E->getSourceRange()
+ << clang::SourceRange(CC));
+ return;
+ }
+ }
}
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 19ed62d1fe6..187d8e2fddd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6152,6 +6152,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_Bool:
return CK_FixedPointToBoolean;
case Type::STK_Integral:
+ return CK_FixedPointToIntegral;
case Type::STK_Floating:
case Type::STK_IntegralComplex:
case Type::STK_FloatingComplex:
@@ -6196,10 +6197,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
case Type::STK_FixedPoint:
- Diag(Src.get()->getExprLoc(),
- diag::err_unimplemented_conversion_with_fixed_point_type)
- << SrcTy;
- return CK_IntegralCast;
+ return CK_IntegralToFixedPoint;
}
llvm_unreachable("Should have returned before this");
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 07e4eb53003..6c1eda622c8 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -415,7 +415,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_IntToOCLSampler:
case CK_LValueBitCast:
case CK_FixedPointCast:
- case CK_FixedPointToBoolean: {
+ case CK_FixedPointToBoolean:
+ case CK_FixedPointToIntegral:
+ case CK_IntegralToFixedPoint: {
state =
handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
continue;
OpenPOWER on IntegriCloud