leonardchan updated this revision to Diff 147882.
leonardchan added a comment.
formatting
Repository:
rC Clang
https://reviews.llvm.org/D46927
Files:
include/clang/AST/Type.h
lib/AST/Type.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/SemaExpr.cpp
test/Frontend/fixed_point_validation.c
Index: test/Frontend/fixed_point_validation.c
===================================================================
--- test/Frontend/fixed_point_validation.c
+++ test/Frontend/fixed_point_validation.c
@@ -1,5 +1,5 @@
-// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli
+// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s
// The first test checks the emitted llvm IR.
// The second test checks the output.
@@ -279,4 +279,35 @@
float laccum_diff = abs(base - 2.333lk);
assert(accum_diff < saccum_diff);
assert(laccum_diff < accum_diff);
+
+ /**************** Auxillary assignments ***************/
+
+ s_accum = 7.5hk;
+ s_accum2 = 2.0hk;
+ s_accum += s_accum2;
+ assert(s_accum == 9.5hk);
+ s_accum += 2.5k;
+ assert(s_accum == 12);
+
+ s_accum -= s_accum2;
+ assert(s_accum == 10);
+ s_accum -= 2.5lk;
+ assert(s_accum == 7.5k);
+
+ s_accum2 = 3.0k;
+ s_accum *= s_accum2;
+ assert(s_accum == 22.5k);
+ s_accum *= 0.5r;
+ assert(s_accum == 11.25hk);
+
+ s_accum /= s_accum2;
+ assert(s_accum == 3.75k);
+ s_accum /= 0.5hr;
+ assert(s_accum == 7.5k);
+
+ s_accum <<= 3;
+ assert(s_accum == 60);
+
+ s_accum >>= 3;
+ assert(s_accum == 7.5k);
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -6076,8 +6076,7 @@
case Type::STK_Floating:
return CK_FixedPointToFloating;
case Type::STK_FixedPoint:
- llvm_unreachable(
- "Unimplemented scalar cast from fixed point to fixed point"); // TODO
+ return CK_FixedPointCast;
}
}
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -308,6 +308,17 @@
Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy,
SourceLocation Loc, bool TreatBooleanAsSigned);
+ /// Emit a conversion between fixed point types by moving the radix point.
+ /// This does not take into account resizing of the underlying llvm type
+ /// which should be handled either before or after calling this function.
+ ///
+ /// If the type is being scaled up, this method should be called after
+ /// performing an intcast. If the type is scaled down, this method should be
+ /// called before performing an intcast. This is necessary such that the
+ /// shift operations retain as much of the original data as possible before
+ /// truncation or after extension.
+ Value *EmitFixedPointRadixShift(Value *Src, QualType SrcTy, QualType DstTy);
+
/// 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,
@@ -961,6 +972,49 @@
SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc);
}
+/// Emit a conversion between fixed point types by moving the radix point.
+/// This does not take into account resizing of the underlying llvm type
+/// which should be handled either before or after calling this function.
+///
+/// If the type is being scaled up, this method should be called after
+/// performing an intcast. If the type is scaled down, this method should be
+/// called before performing an intcast. This is necessary such that the
+/// shift operations retain as much of the original data as possible before
+/// truncation or after extension.
+Value *ScalarExprEmitter::EmitFixedPointRadixShift(Value *Src, QualType SrcTy,
+ QualType DstTy) {
+ assert(DstTy->isFixedPointType());
+ assert(SrcTy->isFixedPointType());
+
+ Value *Res = Src;
+
+ // Casting between fixed point types involves separating the integral and
+ // fractional bits, potentially shifting them, then joining back together.
+ unsigned dest_fbits = getFixedPointFBits(DstTy);
+ unsigned src_fbits = getFixedPointFBits(SrcTy);
+ unsigned dest_ibits = getFixedPointIBits(DstTy);
+ unsigned src_ibits = getFixedPointIBits(SrcTy);
+
+ // If the number of integral bits is decreasing, trim off any extra bits while
+ // retaining the sign.
+ if (dest_ibits < src_ibits) {
+ Res = Builder.CreateShl(Res, src_ibits - dest_ibits);
+ Res = Builder.CreateAShr(Res, src_ibits - dest_ibits);
+ }
+
+ // Move the radix. For irrational numbers, there will be loss of precision
+ // using this method when the number of fbits increases since we will be right
+ // padding zeros. Precision can still be retained if we temporarily convert to
+ // a float and perform some floating point arithmetic, though this may cost
+ // more. Enable that if #pragma FX_FULL_PRECISION is provided.
+ if (dest_fbits > src_fbits) {
+ Res = Builder.CreateShl(Res, dest_fbits - src_fbits);
+ } else if (dest_fbits < src_fbits) {
+ Res = Builder.CreateAShr(Res, src_fbits - dest_fbits);
+ }
+ return Res;
+}
+
/// Emit a conversion from the specified type to the specified destination type,
/// both of which are LLVM scalar types.
Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
@@ -1119,6 +1173,17 @@
DstTy = CGF.FloatTy;
}
+ bool WorkingOnFixedPoints =
+ DstType->isFixedPointType() && SrcType->isFixedPointType();
+ int order = WorkingOnFixedPoints
+ ? CGF.getContext().getFixedPointTypeOrder(DstType, SrcType)
+ : 0;
+
+ if (WorkingOnFixedPoints && order < 0) {
+ // Casting down, so we will need to shift early as to not lose data
+ Src = EmitFixedPointRadixShift(Src, SrcType, DstType);
+ }
+
if (isa<llvm::IntegerType>(SrcTy)) {
bool InputSigned = (SrcType->isSignedIntegerOrEnumerationType() ||
SrcType->isFixedPointType());
@@ -1146,6 +1211,11 @@
Res = Builder.CreateFPExt(Src, DstTy, "conv");
}
+ if (WorkingOnFixedPoints && order >= 0) {
+ // Casting up (or same type), so we can safely shift without losing data
+ Res = EmitFixedPointRadixShift(Res, SrcType, DstType);
+ }
+
if (DstTy != ResTy) {
if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
@@ -1815,39 +1885,8 @@
}
case CK_FixedPointCast: {
- // Casting between fixed point types involves separating the integral and
- // fractional bits, potentially shifting them, then joining back together.
- assert(DestTy->isFixedPointType());
- assert(E->getType()->isFixedPointType());
-
- unsigned dest_fbits = getFixedPointFBits(DestTy);
- unsigned src_fbits = getFixedPointFBits(E->getType());
- unsigned dest_ibits = getFixedPointIBits(DestTy);
- unsigned src_ibits = getFixedPointIBits(E->getType());
-
- llvm::Value *result =
- EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc());
-
- // If the number of integral bits is decreasing, trim off any extra bits
- // while retaining the sign.
- if (dest_ibits < src_ibits) {
- result = Builder.CreateShl(result, src_ibits - dest_ibits);
- result = Builder.CreateAShr(result, src_ibits - dest_ibits);
- }
-
- // Move the radix. For irrational numbers, there will be loss of precision
- // using this method when the number of fbits increases since we will be
- // right padding zeros. Precision can still be retained if we temporarily
- // convert to a float and perform some floating point arithmetic, though
- // this may cost more. Enable that if #pragma FX_FULL_PRECISION is provided.
- if (dest_fbits > src_fbits) {
- result =
- EmitScalarConversion(result, E->getType(), DestTy, CE->getExprLoc());
- result = Builder.CreateShl(result, dest_fbits - src_fbits);
- } else if (dest_fbits < src_fbits) {
- result = Builder.CreateAShr(result, src_fbits - dest_fbits);
- }
- return result;
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc());
}
case CK_IntegralToFixedPoint: {
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -3994,10 +3994,10 @@
return getClass()->getAsCXXRecordDecl()->getMostRecentDecl();
}
-unsigned clang::getFixedPointFBits(const QualType &Ty) {
- assert(Ty->isFixedPointType());
+unsigned clang::getFixedPointFBits(const Type &Ty) {
+ assert(Ty.isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
+ const auto &BT = Ty.getAs<BuiltinType>();
switch (BT->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
@@ -4051,10 +4051,10 @@
}
}
-unsigned clang::getFixedPointIBits(const QualType &Ty) {
- assert(Ty->isFixedPointType());
+unsigned clang::getFixedPointIBits(const Type &Ty) {
+ assert(Ty.isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
+ const auto &BT = Ty.getAs<BuiltinType>();
switch (BT->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -6572,10 +6572,18 @@
}
// Return the number of fractional bits in a fixed point type.
-unsigned getFixedPointFBits(const QualType &Ty);
+unsigned getFixedPointFBits(const Type &Ty);
+
+inline unsigned getFixedPointFBits(const QualType &Ty) {
+ return getFixedPointFBits(*Ty);
+}
// Return the number of integral bits in a fixed point type.
-unsigned getFixedPointIBits(const QualType &Ty);
+unsigned getFixedPointIBits(const Type &Ty);
+
+inline unsigned getFixedPointIBits(const QualType &Ty) {
+ return getFixedPointIBits(*Ty);
+}
} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits