summaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExprScalar.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
commit2298981669bf3bd63335a4be179bc0f96823a8f4 (patch)
tree1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/CodeGen/CGExprScalar.cpp
parent9a83721404652cea39e9f02ae3e3b5c964602a5c (diff)
Notes
Diffstat (limited to 'lib/CodeGen/CGExprScalar.cpp')
-rw-r--r--lib/CodeGen/CGExprScalar.cpp467
1 files changed, 304 insertions, 163 deletions
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 1c14d4c99a23..3d082de2a14f 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1,9 +1,8 @@
//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -17,6 +16,7 @@
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -125,6 +125,21 @@ struct BinOpInfo {
return CFP->isZero();
return true;
}
+
+ /// Check if either operand is a fixed point type or integer type, with at
+ /// least one being a fixed point type. In any case, this
+ /// operation did not follow usual arithmetic conversion and both operands may
+ /// not be the same.
+ bool isFixedPointBinOp() const {
+ // We cannot simply check the result type since comparison operations return
+ // an int.
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
+ QualType LHSType = BinOp->getLHS()->getType();
+ QualType RHSType = BinOp->getRHS()->getType();
+ return LHSType->isFixedPointType() || RHSType->isFixedPointType();
+ }
+ return false;
+ }
};
static bool MustVisitNullValue(const Expr *E) {
@@ -298,7 +313,7 @@ public:
/// boolean (i1) truth value. This is equivalent to "Val != 0".
Value *EmitConversionToBool(Value *Src, QualType DstTy);
- /// Emit a check that a conversion to or from a floating-point type does not
+ /// Emit a check that a conversion from a floating-point type does not
/// overflow.
void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
Value *Src, QualType SrcType, QualType DstType,
@@ -349,8 +364,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,
+ 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.
@@ -620,12 +641,20 @@ public:
Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) {
return EmitLoadOfLValue(E);
}
+ Value *VisitSourceLocExpr(SourceLocExpr *SLE) {
+ auto &Ctx = CGF.getContext();
+ APValue Evaluated =
+ SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getDefaultExpr());
+ return ConstantEmitter(CGF.CGM, &CGF)
+ .emitAbstract(SLE->getLocation(), Evaluated, SLE->getType());
+ }
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ CodeGenFunction::CXXDefaultArgExprScope Scope(CGF, DAE);
return Visit(DAE->getExpr());
}
Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
- CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
+ CodeGenFunction::CXXDefaultInitExprScope Scope(CGF, DIE);
return Visit(DIE->getExpr());
}
Value *VisitCXXThisExpr(CXXThisExpr *TE) {
@@ -729,6 +758,9 @@ public:
return Builder.CreateOr(Ops.LHS, Ops.RHS, "or");
}
+ // Helper functions for fixed point binary operations.
+ Value *EmitFixedPointBinOp(const BinOpInfo &Ops);
+
BinOpInfo EmitBinOps(const BinaryOperator *E);
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
@@ -832,128 +864,63 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
void ScalarExprEmitter::EmitFloatConversionCheck(
Value *OrigSrc, QualType OrigSrcType, Value *Src, QualType SrcType,
QualType DstType, llvm::Type *DstTy, SourceLocation Loc) {
+ assert(SrcType->isFloatingType() && "not a conversion from floating point");
+ if (!isa<llvm::IntegerType>(DstTy))
+ return;
+
CodeGenFunction::SanitizerScope SanScope(&CGF);
using llvm::APFloat;
using llvm::APSInt;
- llvm::Type *SrcTy = Src->getType();
-
llvm::Value *Check = nullptr;
- if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
- // Integer to floating-point. This can fail for unsigned short -> __half
- // or unsigned __int128 -> float.
- assert(DstType->isFloatingType());
- bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
-
- APFloat LargestFloat =
- APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
- APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
-
- bool IsExact;
- if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
- &IsExact) != APFloat::opOK)
- // The range of representable values of this floating point type includes
- // all values of this integer type. Don't need an overflow check.
- return;
-
- llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
- if (SrcIsUnsigned)
- Check = Builder.CreateICmpULE(Src, Max);
- else {
- llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
- llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
- llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
- Check = Builder.CreateAnd(GE, LE);
- }
- } else {
- const llvm::fltSemantics &SrcSema =
- CGF.getContext().getFloatTypeSemantics(OrigSrcType);
- if (isa<llvm::IntegerType>(DstTy)) {
- // Floating-point to integer. This has undefined behavior if the source is
- // +-Inf, NaN, or doesn't fit into the destination type (after truncation
- // to an integer).
- unsigned Width = CGF.getContext().getIntWidth(DstType);
- bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
-
- APSInt Min = APSInt::getMinValue(Width, Unsigned);
- APFloat MinSrc(SrcSema, APFloat::uninitialized);
- if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
- APFloat::opOverflow)
- // Don't need an overflow check for lower bound. Just check for
- // -Inf/NaN.
- MinSrc = APFloat::getInf(SrcSema, true);
- else
- // Find the largest value which is too small to represent (before
- // truncation toward zero).
- MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
-
- APSInt Max = APSInt::getMaxValue(Width, Unsigned);
- APFloat MaxSrc(SrcSema, APFloat::uninitialized);
- if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
- APFloat::opOverflow)
- // Don't need an overflow check for upper bound. Just check for
- // +Inf/NaN.
- MaxSrc = APFloat::getInf(SrcSema, false);
- else
- // Find the smallest value which is too large to represent (before
- // truncation toward zero).
- MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
-
- // If we're converting from __half, convert the range to float to match
- // the type of src.
- if (OrigSrcType->isHalfType()) {
- const llvm::fltSemantics &Sema =
- CGF.getContext().getFloatTypeSemantics(SrcType);
- bool IsInexact;
- MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- }
-
- llvm::Value *GE =
- Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
- llvm::Value *LE =
- Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
- Check = Builder.CreateAnd(GE, LE);
- } else {
- // FIXME: Maybe split this sanitizer out from float-cast-overflow.
- //
- // Floating-point to floating-point. This has undefined behavior if the
- // source is not in the range of representable values of the destination
- // type. The C and C++ standards are spectacularly unclear here. We
- // diagnose finite out-of-range conversions, but allow infinities and NaNs
- // to convert to the corresponding value in the smaller type.
- //
- // C11 Annex F gives all such conversions defined behavior for IEC 60559
- // conforming implementations. Unfortunately, LLVM's fptrunc instruction
- // does not.
-
- // Converting from a lower rank to a higher rank can never have
- // undefined behavior, since higher-rank types must have a superset
- // of values of lower-rank types.
- if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
- return;
-
- assert(!OrigSrcType->isHalfType() &&
- "should not check conversion from __half, it has the lowest rank");
-
- const llvm::fltSemantics &DstSema =
- CGF.getContext().getFloatTypeSemantics(DstType);
- APFloat MinBad = APFloat::getLargest(DstSema, false);
- APFloat MaxBad = APFloat::getInf(DstSema, false);
-
- bool IsInexact;
- MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
- MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
-
- Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
- CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
- llvm::Value *GE =
- Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
- llvm::Value *LE =
- Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
- Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
- }
- }
+ const llvm::fltSemantics &SrcSema =
+ CGF.getContext().getFloatTypeSemantics(OrigSrcType);
+
+ // Floating-point to integer. This has undefined behavior if the source is
+ // +-Inf, NaN, or doesn't fit into the destination type (after truncation
+ // to an integer).
+ unsigned Width = CGF.getContext().getIntWidth(DstType);
+ bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
+
+ APSInt Min = APSInt::getMinValue(Width, Unsigned);
+ APFloat MinSrc(SrcSema, APFloat::uninitialized);
+ if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
+ APFloat::opOverflow)
+ // Don't need an overflow check for lower bound. Just check for
+ // -Inf/NaN.
+ MinSrc = APFloat::getInf(SrcSema, true);
+ else
+ // Find the largest value which is too small to represent (before
+ // truncation toward zero).
+ MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
+
+ APSInt Max = APSInt::getMaxValue(Width, Unsigned);
+ APFloat MaxSrc(SrcSema, APFloat::uninitialized);
+ if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
+ APFloat::opOverflow)
+ // Don't need an overflow check for upper bound. Just check for
+ // +Inf/NaN.
+ MaxSrc = APFloat::getInf(SrcSema, false);
+ else
+ // Find the smallest value which is too large to represent (before
+ // truncation toward zero).
+ MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
+
+ // If we're converting from __half, convert the range to float to match
+ // the type of src.
+ if (OrigSrcType->isHalfType()) {
+ const llvm::fltSemantics &Sema =
+ CGF.getContext().getFloatTypeSemantics(SrcType);
+ bool IsInexact;
+ MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ }
+
+ llvm::Value *GE =
+ Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
+ Check = Builder.CreateAnd(GE, LE);
llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc),
CGF.EmitCheckTypeDescriptor(OrigSrcType),
@@ -1205,17 +1172,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 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 involving a fixed point type.");
+ "Unhandled scalar conversion to a fixed point type from another type.");
}
QualType NoncanonicalSrcType = SrcType;
@@ -1351,9 +1326,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
llvm::Type *ResTy = DstTy;
// An overflowing conversion has undefined behavior if either the source type
- // or the destination type is a floating-point type.
+ // or the destination type is a floating-point type. However, we consider the
+ // range of representable values for all floating-point types to be
+ // [-inf,+inf], so no overflow can ever happen when the destination type is a
+ // floating-point type.
if (CGF.SanOpts.has(SanitizerKind::FloatCastOverflow) &&
- (OrigSrcType->isFloatingType() || DstType->isFloatingType()))
+ OrigSrcType->isFloatingType())
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy,
Loc);
@@ -1423,17 +1401,21 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
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);
+ return EmitFixedPointConversion(Src, SrcFPSema, DstFPSema, Loc,
+ DstTy->isIntegerType());
+}
+
+Value *ScalarExprEmitter::EmitFixedPointConversion(
+ Value *Src, FixedPointSemantics &SrcFPSema, FixedPointSemantics &DstFPSema,
+ SourceLocation Loc, bool DstIsInteger) {
+ using llvm::APInt;
+ using llvm::ConstantInt;
+ using llvm::Value;
+
unsigned SrcWidth = SrcFPSema.getWidth();
unsigned DstWidth = DstFPSema.getWidth();
unsigned SrcScale = SrcFPSema.getScale();
@@ -1446,13 +1428,26 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
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");
@@ -1462,14 +1457,11 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
} else {
// Adjust the number of fractional bits.
if (DstScale > SrcScale) {
- ResultWidth = SrcWidth + DstScale - SrcScale;
+ // Compare to DstWidth to prevent resizing twice.
+ ResultWidth = std::max(SrcWidth + DstScale - SrcScale, DstWidth);
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.
@@ -1493,7 +1485,8 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
}
// Resize the integer part to get the final destination size.
- Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
+ if (ResultWidth != DstWidth)
+ Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
}
return Result;
}
@@ -1978,6 +1971,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitLoadOfLValue(LV, CE->getExprLoc());
}
+ case CK_LValueToRValueBitCast: {
+ LValue SourceLVal = CGF.EmitLValue(E);
+ Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(),
+ CGF.ConvertTypeForMem(DestTy));
+ LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy);
+ DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
+ return EmitLoadOfLValue(DestLV, CE->getExprLoc());
+ }
+
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
@@ -2017,6 +2019,12 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
}
+ // Update heapallocsite metadata when there is an explicit cast.
+ if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(Src))
+ if (CI->getMetadata("heapallocsite") && isa<ExplicitCastExpr>(CE))
+ CGF.getDebugInfo()->
+ addHeapAllocSiteMetadata(CI, CE->getType(), CE->getExprLoc());
+
return Builder.CreateBitCast(Src, DstTy);
}
case CK_AddressSpaceConversion: {
@@ -2087,14 +2095,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_NullToPointer:
if (MustVisitNullValue(E))
- (void) Visit(E);
+ CGF.EmitIgnoredExpr(E);
return CGF.CGM.getNullPointer(cast<llvm::PointerType>(ConvertType(DestTy)),
DestTy);
case CK_NullToMemberPointer: {
if (MustVisitNullValue(E))
- (void) Visit(E);
+ CGF.EmitIgnoredExpr(E);
const MemberPointerType *MPT = CE->getType()->getAs<MemberPointerType>();
return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
@@ -2200,6 +2208,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)) {
@@ -2527,14 +2550,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
if (atomicPHI) {
- llvm::BasicBlock *opBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *curBlock = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
auto Pair = CGF.EmitAtomicCompareExchange(
LV, RValue::get(atomicPHI), RValue::get(value), E->getExprLoc());
llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), type);
llvm::Value *success = Pair.second;
- atomicPHI->addIncoming(old, opBB);
- Builder.CreateCondBr(success, contBB, opBB);
+ atomicPHI->addIncoming(old, curBlock);
+ Builder.CreateCondBr(success, contBB, atomicPHI->getParent());
Builder.SetInsertPoint(contBB);
return isPre ? value : input;
}
@@ -2881,14 +2904,14 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
Loc, ScalarConversionOpts(CGF.SanOpts));
if (atomicPHI) {
- llvm::BasicBlock *opBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *curBlock = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
auto Pair = CGF.EmitAtomicCompareExchange(
LHSLV, RValue::get(atomicPHI), RValue::get(Result), E->getExprLoc());
llvm::Value *old = CGF.EmitToMemory(Pair.first.getScalarVal(), LHSTy);
llvm::Value *success = Pair.second;
- atomicPHI->addIncoming(old, opBB);
- Builder.CreateCondBr(success, contBB, opBB);
+ atomicPHI->addIncoming(old, curBlock);
+ Builder.CreateCondBr(success, contBB, atomicPHI->getParent());
Builder.SetInsertPoint(contBB);
return LHSLV;
}
@@ -2908,7 +2931,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
bool Ignore = TestAndClearIgnoreResultAssign();
- Value *RHS;
+ Value *RHS = nullptr;
LValue LHS = EmitCompoundAssignLValue(E, Func, RHS);
// If the result is clearly ignored, return now.
@@ -3090,7 +3113,8 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
llvm::FunctionType *handlerTy =
llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
- llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
+ llvm::FunctionCallee handler =
+ CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
// Sign extend the args to 64-bit, so that we can use the same handler for
// all types of overflow.
@@ -3338,9 +3362,119 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
return propagateFMFlags(V, op);
}
+ if (op.isFixedPointBinOp())
+ return EmitFixedPointBinOp(op);
+
return Builder.CreateAdd(op.LHS, op.RHS, "add");
}
+/// The resulting value must be calculated with exact precision, so the operands
+/// may not be the same type.
+Value *ScalarExprEmitter::EmitFixedPointBinOp(const BinOpInfo &op) {
+ using llvm::APSInt;
+ using llvm::ConstantInt;
+
+ const auto *BinOp = cast<BinaryOperator>(op.E);
+
+ // The result is a fixed point type and at least one of the operands is fixed
+ // point while the other is either fixed point or an int. This resulting type
+ // should be determined by Sema::handleFixedPointConversions().
+ QualType ResultTy = op.Ty;
+ QualType LHSTy = BinOp->getLHS()->getType();
+ QualType RHSTy = BinOp->getRHS()->getType();
+ ASTContext &Ctx = CGF.getContext();
+ Value *LHS = op.LHS;
+ Value *RHS = op.RHS;
+
+ auto LHSFixedSema = Ctx.getFixedPointSemantics(LHSTy);
+ auto RHSFixedSema = Ctx.getFixedPointSemantics(RHSTy);
+ auto ResultFixedSema = Ctx.getFixedPointSemantics(ResultTy);
+ auto CommonFixedSema = LHSFixedSema.getCommonSemantics(RHSFixedSema);
+
+ // Convert the operands to the full precision type.
+ Value *FullLHS = EmitFixedPointConversion(LHS, LHSFixedSema, CommonFixedSema,
+ BinOp->getExprLoc());
+ Value *FullRHS = EmitFixedPointConversion(RHS, RHSFixedSema, CommonFixedSema,
+ BinOp->getExprLoc());
+
+ // Perform the actual addition.
+ Value *Result;
+ switch (BinOp->getOpcode()) {
+ case BO_Add: {
+ if (ResultFixedSema.isSaturated()) {
+ llvm::Intrinsic::ID IID = ResultFixedSema.isSigned()
+ ? llvm::Intrinsic::sadd_sat
+ : llvm::Intrinsic::uadd_sat;
+ Result = Builder.CreateBinaryIntrinsic(IID, FullLHS, FullRHS);
+ } else {
+ Result = Builder.CreateAdd(FullLHS, FullRHS);
+ }
+ break;
+ }
+ case BO_Sub: {
+ if (ResultFixedSema.isSaturated()) {
+ llvm::Intrinsic::ID IID = ResultFixedSema.isSigned()
+ ? llvm::Intrinsic::ssub_sat
+ : llvm::Intrinsic::usub_sat;
+ Result = Builder.CreateBinaryIntrinsic(IID, FullLHS, FullRHS);
+ } else {
+ Result = Builder.CreateSub(FullLHS, FullRHS);
+ }
+ break;
+ }
+ case BO_LT:
+ return CommonFixedSema.isSigned() ? Builder.CreateICmpSLT(FullLHS, FullRHS)
+ : Builder.CreateICmpULT(FullLHS, FullRHS);
+ case BO_GT:
+ return CommonFixedSema.isSigned() ? Builder.CreateICmpSGT(FullLHS, FullRHS)
+ : Builder.CreateICmpUGT(FullLHS, FullRHS);
+ case BO_LE:
+ return CommonFixedSema.isSigned() ? Builder.CreateICmpSLE(FullLHS, FullRHS)
+ : Builder.CreateICmpULE(FullLHS, FullRHS);
+ case BO_GE:
+ return CommonFixedSema.isSigned() ? Builder.CreateICmpSGE(FullLHS, FullRHS)
+ : Builder.CreateICmpUGE(FullLHS, FullRHS);
+ case BO_EQ:
+ // For equality operations, we assume any padding bits on unsigned types are
+ // zero'd out. They could be overwritten through non-saturating operations
+ // that cause overflow, but this leads to undefined behavior.
+ return Builder.CreateICmpEQ(FullLHS, FullRHS);
+ case BO_NE:
+ return Builder.CreateICmpNE(FullLHS, FullRHS);
+ case BO_Mul:
+ case BO_Div:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_Cmp:
+ case BO_LAnd:
+ case BO_LOr:
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ llvm_unreachable("Found unimplemented fixed point binary operation");
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ case BO_Rem:
+ case BO_Xor:
+ case BO_And:
+ case BO_Or:
+ case BO_Assign:
+ case BO_RemAssign:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ case BO_Comma:
+ llvm_unreachable("Found unsupported binary operation for fixed point types.");
+ }
+
+ // Convert to the result type.
+ return EmitFixedPointConversion(Result, CommonFixedSema, ResultFixedSema,
+ BinOp->getExprLoc());
+}
+
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// The LHS is always a pointer if either side is.
if (!op.LHS->getType()->isPointerTy()) {
@@ -3372,6 +3506,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return propagateFMFlags(V, op);
}
+ if (op.isFixedPointBinOp())
+ return EmitFixedPointBinOp(op);
+
return Builder.CreateSub(op.LHS, op.RHS, "sub");
}
@@ -3450,7 +3587,8 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
bool SanitizeBase = CGF.SanOpts.has(SanitizerKind::ShiftBase) &&
Ops.Ty->hasSignedIntegerRepresentation() &&
- !CGF.getLangOpts().isSignedOverflowDefined();
+ !CGF.getLangOpts().isSignedOverflowDefined() &&
+ !CGF.getLangOpts().CPlusPlus2a;
bool SanitizeExponent = CGF.SanOpts.has(SanitizerKind::ShiftExponent);
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
@@ -3591,8 +3729,9 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison(
CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE);
} else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) {
- Value *LHS = Visit(E->getLHS());
- Value *RHS = Visit(E->getRHS());
+ BinOpInfo BOInfo = EmitBinOps(E);
+ Value *LHS = BOInfo.LHS;
+ Value *RHS = BOInfo.RHS;
// If AltiVec, the comparison results in a numeric type, so we use
// intrinsics comparing vectors and giving 0 or 1 as a result
@@ -3670,7 +3809,9 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
E->getExprLoc());
}
- if (LHS->getType()->isFPOrFPVectorTy()) {
+ if (BOInfo.isFixedPointBinOp()) {
+ Result = EmitFixedPointBinOp(BOInfo);
+ } else if (LHS->getType()->isFPOrFPVectorTy()) {
Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
} else if (LHSTy->hasSignedIntegerRepresentation()) {
Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp");