diff options
author | Leonard Chan <leonardchan@google.com> | 2018-10-15 16:07:02 +0000 |
---|---|---|
committer | Leonard Chan <leonardchan@google.com> | 2018-10-15 16:07:02 +0000 |
commit | 99bda375a14e4c3b7d0adbc65293879899875fa6 (patch) | |
tree | 747ceecaefd44bb95aa2f5779772ee519f70c77e /clang/lib/CodeGen/CGExprScalar.cpp | |
parent | 06ba9f52460b06f83c9da505aa10fe01d9546945 (diff) | |
download | bcm5719-llvm-99bda375a14e4c3b7d0adbc65293879899875fa6.tar.gz bcm5719-llvm-99bda375a14e4c3b7d0adbc65293879899875fa6.zip |
[Fixed Point Arithmetic] FixedPointCast
This patch is a part of https://reviews.llvm.org/D48456 in an attempt to
split them up. This contains the code for casting between fixed point types
and other fixed point types.
The method for converting between fixed point types is based off the convert()
method in APFixedPoint.
Differential Revision: https://reviews.llvm.org/D50616
llvm-svn: 344530
Diffstat (limited to 'clang/lib/CodeGen/CGExprScalar.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 111 |
1 files changed, 109 insertions, 2 deletions
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)) { |