[PATCH] D46927: Augmented Assignment for Fixed Point Types

2018-05-16 Thread Roman Lebedev via Phabricator via cfe-commits
lebedev.ri added a comment.

Hi @leonardchan.
Could you please prepend some appropriate tag to the subjects of all your 
differentials, so it is less hard to read through cfe-commits mails, please?


Repository:
  rC Clang

https://reviews.llvm.org/D46927



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46927: Augmented Assignment for Fixed Point Types

2018-05-15 Thread Leonard Chan via Phabricator via cfe-commits
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 -