summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp111
5 files changed, 113 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 028aa963cda..55fa4551167 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4153,6 +4153,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 62641102861..9e809872ce9 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -851,6 +851,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ZeroToOCLQueue:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index fb176093a74..1d5438668bb 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -509,6 +509,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_ZeroToOCLQueue:
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
+ case CK_FixedPointCast:
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 651b05a26f7..3dbb20dab2a 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -871,6 +871,7 @@ public:
case CK_FloatingCast:
case CK_ZeroToOCLEvent:
case CK_ZeroToOCLQueue:
+ case CK_FixedPointCast:
return nullptr;
}
llvm_unreachable("Invalid CastKind");
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 0bbd788f028..3abb26991a4 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
-#include "CGCleanup.h"
#include "CGCXXABI.h"
+#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +23,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Optional.h"
@@ -327,6 +328,9 @@ public:
SourceLocation Loc,
ScalarConversionOpts Opts = ScalarConversionOpts());
+ Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy,
+ SourceLocation Loc);
+
/// Emit a conversion from the specified complex type to the specified
/// destination type, where the destination type is an LLVM scalar type.
Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
@@ -1011,6 +1015,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType DstType,
SourceLocation Loc,
ScalarConversionOpts Opts) {
+ assert(!SrcType->isFixedPointType() && !DstType->isFixedPointType() &&
+ "Use the ScalarExprEmitter::EmitFixedPoint family functions for "
+ "handling conversions involving fixed point types.");
+
QualType NoncanonicalSrcType = SrcType;
QualType NoncanonicalDstType = DstType;
@@ -1204,6 +1212,101 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Res;
}
+Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
+ QualType DstTy,
+ SourceLocation Loc) {
+ using llvm::APInt;
+ using llvm::ConstantInt;
+ using llvm::Value;
+
+ assert(SrcTy->isFixedPointType());
+ assert(DstTy->isFixedPointType());
+
+ FixedPointSemantics SrcFPSema =
+ CGF.getContext().getFixedPointSemantics(SrcTy);
+ FixedPointSemantics DstFPSema =
+ CGF.getContext().getFixedPointSemantics(DstTy);
+ unsigned SrcWidth = SrcFPSema.getWidth();
+ unsigned DstWidth = DstFPSema.getWidth();
+ unsigned SrcScale = SrcFPSema.getScale();
+ unsigned DstScale = DstFPSema.getScale();
+ bool IsSigned = SrcFPSema.isSigned();
+
+ Value *Result = Src;
+ unsigned ResultWidth = SrcWidth;
+
+ if (!DstFPSema.isSaturated()) {
+ // Downscale
+ if (DstScale < SrcScale) {
+ if (IsSigned)
+ Result = Builder.CreateAShr(Result, SrcScale - DstScale);
+ else
+ Result = Builder.CreateLShr(Result, SrcScale - DstScale);
+ }
+
+ // Resize
+ llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
+ if (IsSigned)
+ Result = Builder.CreateSExtOrTrunc(Result, DstIntTy);
+ else
+ Result = Builder.CreateZExtOrTrunc(Result, DstIntTy);
+
+ // Upscale
+ if (DstScale > SrcScale)
+ Result = Builder.CreateShl(Result, DstScale - SrcScale);
+ } else {
+ if (DstScale > SrcScale) {
+ // Need to extend first before scaling up
+ ResultWidth = SrcWidth + DstScale - SrcScale;
+ llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth);
+
+ if (IsSigned)
+ Result = Builder.CreateSExt(Result, UpscaledTy);
+ else
+ Result = Builder.CreateZExt(Result, UpscaledTy);
+
+ Result = Builder.CreateShl(Result, DstScale - SrcScale);
+ } else if (DstScale < SrcScale) {
+ if (IsSigned)
+ Result = Builder.CreateAShr(Result, SrcScale - DstScale);
+ else
+ Result = Builder.CreateLShr(Result, SrcScale - DstScale);
+ }
+
+ if (DstFPSema.getIntegralBits() < SrcFPSema.getIntegralBits()) {
+ auto Max = ConstantInt::get(
+ CGF.getLLVMContext(),
+ APFixedPoint::getMax(DstFPSema).getValue().extOrTrunc(ResultWidth));
+ Value *TooHigh = IsSigned ? Builder.CreateICmpSGT(Result, Max)
+ : Builder.CreateICmpUGT(Result, Max);
+ Result = Builder.CreateSelect(TooHigh, Max, Result);
+
+ if (IsSigned) {
+ // Cannot overflow min to dest type is src is unsigned since all fixed
+ // point types can cover the unsigned min of 0.
+ auto Min = ConstantInt::get(
+ CGF.getLLVMContext(),
+ APFixedPoint::getMin(DstFPSema).getValue().extOrTrunc(ResultWidth));
+ Value *TooLow = Builder.CreateICmpSLT(Result, Min);
+ Result = Builder.CreateSelect(TooLow, Min, Result);
+ }
+ } else if (IsSigned && !DstFPSema.isSigned()) {
+ llvm::Type *ResultTy = Builder.getIntNTy(ResultWidth);
+ Value *Zero = ConstantInt::getNullValue(ResultTy);
+ Value *LTZero = Builder.CreateICmpSLT(Result, Zero);
+ Result = Builder.CreateSelect(LTZero, Zero, Result);
+ }
+
+ // Final resizing to dst width
+ llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
+ if (IsSigned)
+ Result = Builder.CreateSExtOrTrunc(Result, DstIntTy);
+ else
+ Result = Builder.CreateZExtOrTrunc(Result, DstIntTy);
+ }
+ return Result;
+}
+
/// Emit a conversion from the specified complex type to the specified
/// destination type, where the destination type is an LLVM scalar type.
Value *ScalarExprEmitter::EmitComplexToScalarConversion(
@@ -1894,6 +1997,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
+ case CK_FixedPointCast:
+ return EmitFixedPointConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
+
case CK_IntegralCast: {
ScalarConversionOpts Opts;
if (CGF.SanOpts.hasOneOf(SanitizerKind::ImplicitIntegerTruncation)) {
OpenPOWER on IntegriCloud