diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprComplex.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 111 |
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)) { |