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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to