Skip to content

Commit

Permalink
[Fixed Point Arithmetic] Fixed Point and Integer Conversions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
PiJoules committed Mar 6, 2019
1 parent f0c21e2 commit 8f7caae
Show file tree
Hide file tree
Showing 17 changed files with 576 additions and 223 deletions.
8 changes: 8 additions & 0 deletions clang/include/clang/AST/OperationKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ CAST_OPERATION(IntegralToFloating)
/// (_Accum) 0.5r
CAST_OPERATION(FixedPointCast)

/// CK_FixedPointToIntegral - Fixed point to integral.
/// (int) 2.0k
CAST_OPERATION(FixedPointToIntegral)

/// CK_IntegralToFixedPoint - Integral to a fixed point.
/// (_Accum) 2
CAST_OPERATION(IntegralToFixedPoint)

/// CK_FixedPointToBoolean - Fixed point to boolean.
/// (bool) 0.5r
CAST_OPERATION(FixedPointToBoolean)
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/Basic/FixedPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,26 @@ class APFixedPoint {
return APFixedPoint(Val << Amt, Sema);
}

/// Return the integral part of this fixed point number, rounded towards
/// zero. (-2.5k -> -2)
llvm::APSInt getIntPart() const {
if (Val < 0 && Val != -Val) // Cover the case when we have the min val
return -(-Val >> getScale());
else
return Val >> getScale();
}

/// Return the integral part of this fixed point number, rounded towards
/// zero. The value is stored into an APSInt with the provided width and sign.
/// If the overflow parameter is provided, and the integral value is not able
/// to be fully stored in the provided width and sign, the overflow parameter
/// is set to true.
///
/// If the overflow parameter is provided, set this value to true or false to
/// indicate if this operation results in an overflow.
llvm::APSInt convertToInt(unsigned DstWidth, bool DstSign,
bool *Overflow = nullptr) const;

void toString(llvm::SmallVectorImpl<char> &Str) const;
std::string toString() const {
llvm::SmallString<40> S;
Expand Down Expand Up @@ -175,6 +188,14 @@ class APFixedPoint {
static APFixedPoint getMax(const FixedPointSemantics &Sema);
static APFixedPoint getMin(const FixedPointSemantics &Sema);

/// Create an APFixedPoint with a value equal to that of the provided integer,
/// and in the same semantics as the provided target semantics. If the value
/// is not able to fit in the specified fixed point semantics, and the
/// overflow parameter is provided, it is set to true.
static APFixedPoint getFromIntValue(const llvm::APSInt &Value,
const FixedPointSemantics &DstFXSema,
bool *Overflow = nullptr);

private:
llvm::APSInt Val;
FixedPointSemantics Sema;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,8 @@ bool CastExpr::CastConsistency() const {
case CK_ZeroToOCLOpaqueType:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;

Expand Down
30 changes: 30 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9776,6 +9776,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_AddressSpaceConversion:
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_IntegralToFixedPoint:
llvm_unreachable("invalid cast kind for integral value");

case CK_BitCast:
Expand Down Expand Up @@ -9810,6 +9811,19 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Success(IntResult, E);
}

case CK_FixedPointToIntegral: {
APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SrcType));
if (!EvaluateFixedPoint(SubExpr, Src, Info))
return false;
bool Overflowed;
llvm::APSInt Result = Src.convertToInt(
Info.Ctx.getIntWidth(DestType),
DestType->isSignedIntegerOrEnumerationType(), &Overflowed);
if (Overflowed && !HandleOverflow(Info, E, Result, DestType))
return false;
return Success(Result, E);
}

case CK_FixedPointToBoolean: {
// Unsigned padding does not affect this.
APValue Val;
Expand Down Expand Up @@ -9970,6 +9984,20 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
return Success(Result, E);
}
case CK_IntegralToFixedPoint: {
APSInt Src;
if (!EvaluateInteger(SubExpr, Src, Info))
return false;

bool Overflowed;
APFixedPoint IntResult = APFixedPoint::getFromIntValue(
Src, Info.Ctx.getFixedPointSemantics(DestType), &Overflowed);

if (Overflowed && !HandleOverflow(Info, E, IntResult, DestType))
return false;

return Success(IntResult, E);
}
case CK_NoOp:
case CK_LValueToRValue:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
Expand Down Expand Up @@ -10371,6 +10399,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
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_LValueToRValue:
Expand Down
37 changes: 37 additions & 0 deletions clang/lib/Basic/FixedPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,41 @@ APFixedPoint APFixedPoint::negate(bool *Overflow) const {
return APFixedPoint(Sema);
}

llvm::APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
bool *Overflow) const {
llvm::APSInt Result = getIntPart();
unsigned SrcWidth = getWidth();

llvm::APSInt DstMin = llvm::APSInt::getMinValue(DstWidth, !DstSign);
llvm::APSInt DstMax = llvm::APSInt::getMaxValue(DstWidth, !DstSign);

if (SrcWidth < DstWidth) {
Result = Result.extend(DstWidth);
} else if (SrcWidth > DstWidth) {
DstMin = DstMin.extend(SrcWidth);
DstMax = DstMax.extend(SrcWidth);
}

if (Overflow) {
if (Result.isSigned() && !DstSign) {
*Overflow = Result.isNegative() || Result.ugt(DstMax);
} else if (Result.isUnsigned() && DstSign) {
*Overflow = Result.ugt(DstMax);
} else {
*Overflow = Result < DstMin || Result > DstMax;
}
}

Result.setIsSigned(DstSign);
return Result.extOrTrunc(DstWidth);
}

APFixedPoint APFixedPoint::getFromIntValue(const llvm::APSInt &Value,
const FixedPointSemantics &DstFXSema,
bool *Overflow) {
FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
Value.getBitWidth(), Value.isSigned());
return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
}

} // namespace clang
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4162,6 +4162,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");

case CK_Dependent:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_IntToOCLSampler:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGExprComplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
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:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,8 @@ class ConstExprEmitter :
case CK_FloatingCast:
case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
case CK_ZeroToOCLOpaqueType:
return nullptr;
}
Expand Down
75 changes: 54 additions & 21 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,14 @@ class ScalarExprEmitter
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.
Expand Down Expand Up @@ -1225,17 +1228,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 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;
Expand Down Expand Up @@ -1443,19 +1454,17 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
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;
Expand All @@ -1472,13 +1481,26 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(
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");

Expand All @@ -1493,10 +1515,6 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(
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.
Expand Down Expand Up @@ -2228,6 +2246,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)) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Edit/RewriteObjCFoundationAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,

case CK_FixedPointCast:
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint:
llvm_unreachable("Fixed point types are disabled for Objective-C");
}
}
Expand Down
Loading

0 comments on commit 8f7caae

Please sign in to comment.