[Fixed Point Arithmetic] Fixed Point and Integer Conversions
This patch includes the necessary code for converting between a fixed point type and integer.
This also includes constant expression evaluation for conversions with these types.
Differential Revision: https://reviews.llvm.org/D56900
llvm-svn: 355462
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 09ba2a0..33fbb48 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4162,6 +4162,8 @@
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 d9d8264..161d6ed 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -853,6 +853,8 @@
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 2e69d92..3ae08ed 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -509,6 +509,8 @@
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 62cc12c..64ad582 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -876,6 +876,8 @@
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 e831c82..83e9349 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -363,11 +363,14 @@
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 @@
// 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::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 *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 @@
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 @@
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)) {