leonardchan created this revision.
leonardchan added reviewers: phosek, mcgrathr, jakehehrlich.
leonardchan added a project: clang.

This patch contains the changes and tests for augmented assignments for primary 
fixed point types.

  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);

This is a parent of https://reviews.llvm.org/D46926


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
@@ -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
@@ -6057,7 +6057,7 @@
       default: llvm_unreachable("Unable to convert from fixed point type");
       case Type::STK_Integral: llvm_unreachable("Unimplemented scalar cast from fixed point to int");  // TODO
       case Type::STK_Floating: return CK_FixedPointToFloating;
-      case Type::STK_FixedPoint: llvm_unreachable("Unimplemented scalar cast from fixed point to fixed point");  // TODO
+      case Type::STK_FixedPoint: 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,
@@ -957,6 +968,50 @@
                 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,
@@ -1115,6 +1170,14 @@
     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());
@@ -1142,6 +1205,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");
@@ -1811,37 +1879,7 @@
   }
 
   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!");
     case BuiltinType::ShortAccum:
@@ -4050,10 +4050,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!");
     case BuiltinType::ShortAccum:
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -6557,10 +6557,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