[Fixed Point Arithmetic] Fixed Point and Integer Conversions
authorLeonard Chan <leonardchan@google.com>
Wed, 6 Mar 2019 00:28:43 +0000 (00:28 +0000)
committerLeonard Chan <leonardchan@google.com>
Wed, 6 Mar 2019 00:28:43 +0000 (00:28 +0000)
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

17 files changed:
clang/include/clang/AST/OperationKinds.def
clang/include/clang/Basic/FixedPoint.h
clang/lib/AST/Expr.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/Basic/FixedPoint.cpp
clang/lib/CodeGen/CGExpr.cpp
clang/lib/CodeGen/CGExprAgg.cpp
clang/lib/CodeGen/CGExprComplex.cpp
clang/lib/CodeGen/CGExprConstant.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/Edit/RewriteObjCFoundationAPI.cpp
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
clang/test/Frontend/fixed_point_conversions.c
clang/test/Frontend/fixed_point_errors.c
clang/test/Frontend/fixed_point_unknown_conversions.c

index d8b286e..c61f085 100644 (file)
@@ -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)
index f68ed56..a931e21 100644 (file)
@@ -141,6 +141,8 @@ 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());
@@ -148,6 +150,17 @@ class APFixedPoint {
       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;
@@ -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;
index 85690c7..6c69ca3 100644 (file)
@@ -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;
 
index 44ccb74..1a21ad2 100644 (file)
@@ -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:
@@ -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;
@@ -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);
@@ -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:
index ca84a0c..f049e6f 100644 (file)
@@ -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
index 09ba2a0..33fbb48 100644 (file)
@@ -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:
index d9d8264..161d6ed 100644 (file)
@@ -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");
   }
 }
index 2e69d92..3ae08ed 100644 (file)
@@ -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:
index 62cc12c..64ad582 100644 (file)
@@ -876,6 +876,8 @@ public:
     case CK_FloatingCast:
     case CK_FixedPointCast:
     case CK_FixedPointToBoolean:
+    case CK_FixedPointToIntegral:
+    case CK_IntegralToFixedPoint:
     case CK_ZeroToOCLOpaqueType:
       return nullptr;
     }
index e831c82..83e9349 100644 (file)
@@ -363,11 +363,14 @@ public:
                        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.
@@ -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;
@@ -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;
@@ -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");
 
@@ -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.
@@ -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)) {
index 3a628b9..4dfe170 100644 (file)
@@ -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");
     }
   }
index 5d9ae18..8dc9c7f 100644 (file)
@@ -11018,10 +11018,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
     return;
   }
 
+  // Valid casts involving fixed point types should be accounted for here.
   if (Source->isFixedPointType()) {
-    // TODO: Only CK_FixedPointCast is supported now. The other valid casts
-    // should be accounted for here.
-    if (Target->isFixedPointType()) {
+    if (Target->isUnsaturatedFixedPointType()) {
       Expr::EvalResult Result;
       if (E->EvaluateAsFixedPoint(Result, S.Context,
                                   Expr::SE_AllowSideEffects)) {
@@ -11037,6 +11036,46 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
           return;
         }
       }
+    } else if (Target->isIntegerType()) {
+      Expr::EvalResult Result;
+      if (E->EvaluateAsFixedPoint(Result, S.Context,
+                                  Expr::SE_AllowSideEffects)) {
+        APFixedPoint FXResult = Result.Val.getFixedPoint();
+
+        bool Overflowed;
+        llvm::APSInt IntResult = FXResult.convertToInt(
+            S.Context.getIntWidth(T),
+            Target->isSignedIntegerOrEnumerationType(), &Overflowed);
+
+        if (Overflowed) {
+          S.DiagRuntimeBehavior(E->getExprLoc(), E,
+                                S.PDiag(diag::warn_impcast_fixed_point_range)
+                                    << FXResult.toString() << T
+                                    << E->getSourceRange()
+                                    << clang::SourceRange(CC));
+          return;
+        }
+      }
+    }
+  } else if (Target->isUnsaturatedFixedPointType()) {
+    if (Source->isIntegerType()) {
+      Expr::EvalResult Result;
+      if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) {
+        llvm::APSInt Value = Result.Val.getInt();
+
+        bool Overflowed;
+        APFixedPoint IntResult = APFixedPoint::getFromIntValue(
+            Value, S.Context.getFixedPointSemantics(T), &Overflowed);
+
+        if (Overflowed) {
+          S.DiagRuntimeBehavior(E->getExprLoc(), E,
+                                S.PDiag(diag::warn_impcast_fixed_point_range)
+                                    << Value.toString(/*radix=*/10) << T
+                                    << E->getSourceRange()
+                                    << clang::SourceRange(CC));
+          return;
+        }
+      }
     }
   }
 
index 19ed62d..187d8e2 100644 (file)
@@ -6152,6 +6152,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
     case Type::STK_Bool:
       return CK_FixedPointToBoolean;
     case Type::STK_Integral:
+      return CK_FixedPointToIntegral;
     case Type::STK_Floating:
     case Type::STK_IntegralComplex:
     case Type::STK_FloatingComplex:
@@ -6196,10 +6197,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
     case Type::STK_MemberPointer:
       llvm_unreachable("member pointer type in C");
     case Type::STK_FixedPoint:
-      Diag(Src.get()->getExprLoc(),
-           diag::err_unimplemented_conversion_with_fixed_point_type)
-          << SrcTy;
-      return CK_IntegralCast;
+      return CK_IntegralToFixedPoint;
     }
     llvm_unreachable("Should have returned before this");
 
index 07e4eb5..6c1eda6 100644 (file)
@@ -415,7 +415,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       case CK_IntToOCLSampler:
       case CK_LValueBitCast:
       case CK_FixedPointCast:
-      case CK_FixedPointToBoolean: {
+      case CK_FixedPointToBoolean:
+      case CK_FixedPointToIntegral:
+      case CK_IntegralToFixedPoint: {
         state =
             handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
         continue;
index 0b36d9d..86a687b 100644 (file)
-// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT
-// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s -check-prefix=SAME
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
 
 // Between different fixed point types
-short _Accum sa_const = 2.5hk; // DEFAULT-DAG: @sa_const  = {{.*}}global i16 320, align 2
-_Accum a_const = 2.5hk;        // DEFAULT-DAG: @a_const   = {{.*}}global i32 81920, align 4
-short _Accum sa_const2 = 2.5k; // DEFAULT-DAG: @sa_const2 = {{.*}}global i16 320, align 2
+short _Accum sa_const = 2.5hk; // CHECK-DAG: @sa_const  = {{.*}}global i16 320, align 2
+_Accum a_const = 2.5hk;        // CHECK-DAG: @a_const   = {{.*}}global i32 81920, align 4
+short _Accum sa_const2 = 2.5k; // CHECK-DAG: @sa_const2 = {{.*}}global i16 320, align 2
 
-short _Accum sa_from_f_const = 0.5r; // DEFAULT-DAG: sa_from_f_const = {{.*}}global i16 64, align 2
-_Fract f_from_sa_const = 0.5hk;      // DEFAULT-DAG: f_from_sa_const = {{.*}}global i16 16384, align 2
+short _Accum sa_from_f_const = 0.5r; // CHECK-DAG: sa_from_f_const = {{.*}}global i16 64, align 2
+_Fract f_from_sa_const = 0.5hk;      // CHECK-DAG: f_from_sa_const = {{.*}}global i16 16384, align 2
 
 unsigned short _Accum usa_const = 2.5uk;
 unsigned _Accum ua_const = 2.5uhk;
-// DEFAULT-DAG: @usa_const  = {{.*}}global i16 640, align 2
-// DEFAULT-DAG: @ua_const   = {{.*}}global i32 163840, align 4
-// SAME-DAG:    @usa_const  = {{.*}}global i16 320, align 2
-// SAME-DAG:    @ua_const   = {{.*}}global i32 81920, align 4
+// SIGNED-DAG: @usa_const  = {{.*}}global i16 640, align 2
+// SIGNED-DAG: @ua_const   = {{.*}}global i32 163840, align 4
+// UNSIGNED-DAG:    @usa_const  = {{.*}}global i16 320, align 2
+// UNSIGNED-DAG:    @ua_const   = {{.*}}global i32 81920, align 4
+
+// FixedPoint to integer
+int i_const = -128.0hk;  // CHECK-DAG: @i_const  = {{.*}}global i32 -128, align 4
+int i_const2 = 128.0hk;  // CHECK-DAG: @i_const2 = {{.*}}global i32 128, align 4
+int i_const3 = -128.0k;  // CHECK-DAG: @i_const3 = {{.*}}global i32 -128, align 4
+int i_const4 = 128.0k;   // CHECK-DAG: @i_const4 = {{.*}}global i32 128, align 4
+short s_const = -128.0k; // CHECK-DAG: @s_const  = {{.*}}global i16 -128, align 2
+short s_const2 = 128.0k; // CHECK-DAG: @s_const2 = {{.*}}global i16 128, align 2
+
+// Integer to fixed point
+short _Accum sa_const5 = 2;    // CHECK-DAG: @sa_const5 = {{.*}}global i16 256, align 2
+short _Accum sa_const6 = -2;   // CHECK-DAG: @sa_const6 = {{.*}}global i16 -256, align 2
+short _Accum sa_const7 = -256; // CHECK-DAG: @sa_const7 = {{.*}}global i16 -32768, align 2
 
 // Signedness
 unsigned short _Accum usa_const2 = 2.5hk;
-// DEFAULT-DAG: @usa_const2  = {{.*}}global i16 640, align 2
-// SAME-DAG:    @usa_const2  = {{.*}}global i16 320, align 2
-short _Accum sa_const3 = 2.5hk; // DEFAULT-DAG: @sa_const3 = {{.*}}global i16 320, align 2
+// SIGNED-DAG: @usa_const2  = {{.*}}global i16 640, align 2
+// UNSIGNED-DAG:    @usa_const2  = {{.*}}global i16 320, align 2
+short _Accum sa_const3 = 2.5hk; // CHECK-DAG: @sa_const3 = {{.*}}global i16 320, align 2
+
+int i_const5 = 128.0uhk;
+unsigned int ui_const = 128.0hk;
+// CHECK-DAG: @i_const5  = {{.*}}global i32 128, align 4
+// CHECK-DAG: @ui_const  = {{.*}}global i32 128, align 4
+
+short _Accum sa_const9 = 2u; // CHECK-DAG: @sa_const9 = {{.*}}global i16 256, align 2
+unsigned short _Accum usa_const3 = 2;
+// SIGNED-DAG: @usa_const3 = {{.*}}global i16 512, align 2
+// UNSIGNED-DAG:    @usa_const3 = {{.*}}global i16 256, align 2
 
 // Overflow (this is undefined but allowed)
 short _Accum sa_const4 = 256.0k;
+unsigned int ui_const2 = -2.5hk;
+short _Accum sa_const8 = 256;
+unsigned short _Accum usa_const4 = -2;
 
 // Saturation
-_Sat short _Accum sat_sa_const = 2.5hk;   // DEFAULT-DAG: @sat_sa_const  = {{.*}}global i16 320, align 2
-_Sat short _Accum sat_sa_const2 = 256.0k; // DEFAULT-DAG: @sat_sa_const2 = {{.*}}global i16 32767, align 2
+_Sat short _Accum sat_sa_const = 2.5hk;   // CHECK-DAG: @sat_sa_const  = {{.*}}global i16 320, align 2
+_Sat short _Accum sat_sa_const2 = 256.0k; // CHECK-DAG: @sat_sa_const2 = {{.*}}global i16 32767, align 2
 _Sat unsigned short _Accum sat_usa_const = -1.0hk;
-// DEFAULT-DAG: @sat_usa_const = {{.*}}global i16 0, align 2
-// SAME-DAG:    @sat_usa_const = {{.*}}global i16 0, align 2
+// CHECK-DAG: @sat_usa_const = {{.*}}global i16 0, align 2
 _Sat unsigned short _Accum sat_usa_const2 = 256.0k;
-// DEFAULT-DAG: @sat_usa_const2 = {{.*}}global i16 -1, align 2
-// SAME-DAG:    @sat_usa_const2 = {{.*}}global i16 32767, align 2
+// SIGNED-DAG: @sat_usa_const2 = {{.*}}global i16 -1, align 2
+// UNSIGNED-DAG:    @sat_usa_const2 = {{.*}}global i16 32767, align 2
+
+_Sat short _Accum sat_sa_const3 = 256;  // CHECK-DAG: @sat_sa_const3 = {{.*}}global i16 32767, align 2
+_Sat short _Accum sat_sa_const4 = -257; // CHECK-DAG: @sat_sa_const4 = {{.*}}global i16 -32768, align 2
+_Sat unsigned short _Accum sat_usa_const3 = -1;
+// CHECK-DAG: @sat_usa_const3 = {{.*}}global i16 0, align 2
+_Sat unsigned short _Accum sat_usa_const4 = 256;
+// SIGNED-DAG: @sat_usa_const4 = {{.*}}global i16 -1, align 2
+// UNSIGNED-DAG:    @sat_usa_const4 = {{.*}}global i16 32767, align 2
 
 void TestFixedPointCastSameType() {
   _Accum a = 2.5k;
   _Accum a2 = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
 
   a2 = (_Accum)a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
 }
 
 void TestFixedPointCastDown() {
   long _Accum la = 2.5lk;
   _Accum a = la;
-  // DEFAULT:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
-  // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
+  // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   a = (_Accum)la;
-  // DEFAULT:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
-  // DEFAULT-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
+  // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   short _Accum sa = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
-  // DEFAULT-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
-  // DEFAULT-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
+  // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
+  // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
 
   sa = (short _Accum)a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
-  // DEFAULT-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
-  // DEFAULT-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
+  // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
+  // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
 }
 
 void TestFixedPointCastUp() {
   short _Accum sa = 2.5hk;
   _Accum a = sa;
-  // DEFAULT:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
-  // DEFAULT-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   long _Accum la = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
-  // DEFAULT-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
-  // DEFAULT-NEXT: store i64 [[LACCUM]], i64* %la, align 8
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
+  // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
+  // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
 
   a = (_Accum)sa;
-  // DEFAULT:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
-  // DEFAULT-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   la = (long _Accum)a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
-  // DEFAULT-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
-  // DEFAULT-NEXT: store i64 [[LACCUM]], i64* %la, align 8
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
+  // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
+  // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
 }
 
 void TestFixedPointCastSignedness() {
   _Accum a = 2.5k;
   unsigned _Accum ua = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
-  // DEFAULT-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
-  // SAME:      TestFixedPointCastSignedness
-  // SAME:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // SAME-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
+  // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
+  // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
+  // UNSIGNED:      TestFixedPointCastSignedness
+  // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
 
   a = ua;
-  // DEFAULT:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
-  // SAME:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
-  // SAME-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // SIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
+  // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
+  // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
+  // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   ua = (unsigned _Accum)a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
-  // DEFAULT-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
+  // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
+  // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
+  // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
 
   a = (_Accum)ua;
-  // DEFAULT:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // SIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
+  // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
+  // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // UNSIGNED:      [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
+  // UNSIGNED-NEXT: store i32 [[UACCUM]], i32* %a, align 4
 
   _Accum a2;
   unsigned long _Accum ula = a2;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
-  // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
-  // DEFAULT-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 17
-  // DEFAULT-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
-  // SAME:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
-  // SAME-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
-  // SAME-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 16
-  // SAME-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
+  // SIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
+  // SIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
+  // SIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 17
+  // SIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
+  // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
+  // UNSIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
+  // UNSIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 16
+  // UNSIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
 }
 
 void TestFixedPointCastSaturation() {
@@ -153,112 +190,112 @@ void TestFixedPointCastSaturation() {
 
   // Casting down between types
   sat_sa = sat_a;
-  // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
+  // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
+  // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
+  // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
+  // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
+  // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
+  // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
 
   // Accum to Fract, decreasing scale
   sat_sf = sat_a;
-  // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8
-  // DEFAULT-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
+  // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
+  // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127
+  // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128
+  // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
+  // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8
+  // CHECK-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
 
   // Accum to Fract, same scale
   sat_f = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
+  // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
+  // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
+  // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
+  // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
 
   // Accum to Fract, increasing scale
   sat_lf = sat_a;
-  // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48
-  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[ACCUM]], 16
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32
-  // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_lf, align 4
+  // CHECK:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // CHECK-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48
+  // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[RESIZE]], 16
+  // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647
+  // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648
+  // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
+  // CHECK-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32
+  // CHECK-NEXT: store i32 [[TRUNC]], i32* %sat_lf, align 4
 
   // Signed to unsigned, decreasing scale
   _Sat _Accum sat_a2;
   sat_usa = sat_a2;
-  // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
-  // SAME:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
-  // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // SAME-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
-  // SAME-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
-  // SAME-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // SAME-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
+  // SIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
+  // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7
+  // SIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535
+  // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
+  // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
+  // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
+  // SIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
+  // SIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
+  // UNSIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
+  // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
+  // UNSIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
+  // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
+  // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
+  // UNSIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
+  // UNSIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
+  // UNSIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
 
   // Signed to unsigned, increasing scale
   sat_ua = sat_a;
-  // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[ACCUM_EXT]], 1
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32
-  // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_ua, align 4
-  // SAME:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
-  // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
-  // SAME-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
+  // SIGNED:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // SIGNED-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33
+  // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[RESIZE]], 1
+  // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0
+  // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
+  // SIGNED-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32
+  // SIGNED-NEXT: store i32 [[TRUNC]], i32* %sat_ua, align 4
+  // UNSIGNED:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+  // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
+  // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
 
   // Nothing when saturating to the same type and size
   sat_a = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
 
   // Nothing when assigning back
   a = sat_a;
-  // DEFAULT:      [[SAT_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: store i32 [[SAT_ACCUM]], i32* %a, align 4
+  // CHECK:      [[SAT_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
+  // CHECK-NEXT: store i32 [[SAT_ACCUM]], i32* %a, align 4
 
   // No overflow when casting from fract to signed accum
   sat_a = sat_f;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %sat_f, align 2
-  // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
-  // DEFAULT-NEXT: store i32 [[FRACT_EXT]], i32* %sat_a, align 4
+  // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %sat_f, align 2
+  // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
+  // CHECK-NEXT: store i32 [[FRACT_EXT]], i32* %sat_a, align 4
 
   // Only get overflow checking if signed fract to unsigned accum
   sat_ua = sat_sf;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
-  // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
-  // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
-  // DEFAULT-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
-  // SAME:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
-  // SAME-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
-  // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
-  // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
-  // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
-  // SAME-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
+  // SIGNED:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
+  // SIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
+  // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
+  // SIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+  // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
+  // SIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
+  // UNSIGNED:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
+  // UNSIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
+  // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
+  // UNSIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+  // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
+  // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
 }
 
 void TestFixedPointCastBetFractAccum() {
@@ -273,43 +310,176 @@ void TestFixedPointCastBetFractAccum() {
 
   // To lower scale
   sf = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
-  // DEFAULT-NEXT: [[FRACT_TRUNC:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8
-  // DEFAULT-NEXT: store i8 [[FRACT_TRUNC]], i8* %sf, align 1
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
+  // CHECK-NEXT: [[FRACT_TRUNC:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8
+  // CHECK-NEXT: store i8 [[FRACT_TRUNC]], i8* %sf, align 1
 
   // To higher scale
   a = sf;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sf, align 1
-  // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sf, align 1
+  // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   // To same scale
   f = a;
-  // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
-  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
-  // DEFAULT-NEXT: store i16 [[FRACT]], i16* %f, align 2
+  // CHECK:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
+  // CHECK-NEXT: store i16 [[FRACT]], i16* %f, align 2
 
   a = f;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %f, align 2
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %a, align 4
+  // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %f, align 2
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
 
   // To unsigned
   ua = uf;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %uf, align 2
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = zext i16 [[FRACT]] to i32
-  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
-  // SAME:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %uf, align 2
-  // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = zext i16 [[FRACT]] to i32
-  // SAME-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
+  // CHECK:      [[FRACT:%[0-9a-z]+]] = load i16, i16* %uf, align 2
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = zext i16 [[FRACT]] to i32
+  // CHECK-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
 
   uf = ua;
-  // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i32, i32* %ua, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i16
-  // DEFAULT-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
-  // SAME:      [[FRACT:%[0-9a-z]+]] = load i32, i32* %ua, align 4
-  // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i16
-  // SAME-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
+  // CHECK:      [[FRACT:%[0-9a-z]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i16
+  // CHECK-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
+}
+
+void TestFixedPointToInt() {
+  int i;
+  short _Accum sa;
+  unsigned short _Accum usa;
+
+  // Will need to check for negative values
+  i = sa;
+  // CHECK:      [[FX:%[0-9]+]] = load i16, i16* %sa, align 2
+  // CHECK-NEXT: [[NEG:%[0-9]+]] = icmp slt i16 [[FX]], 0
+  // CHECK-NEXT: [[ROUNDED:%[0-9]+]] = add i16 [[FX]], 127
+  // CHECK-NEXT: [[VAL:%[0-9]+]] = select i1 [[NEG]], i16 [[ROUNDED]], i16 [[FX]]
+  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i16 [[VAL]], 7
+  // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = sext i16 [[RES]] to i32
+  // CHECK-NEXT: store i32 [[RES2]], i32* %i, align 4
+
+  // No check needed for unsigned fixed points. Can just right shift.
+  i = usa;
+  // SIGNED:      [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
+  // SIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 8
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
+  // SIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
+  // UNSIGNED:      [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
+  // UNSIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 7
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
+  // UNSIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
+}
+
+void TestIntToFixedPoint() {
+  short s;
+  int i, i2;
+  unsigned int ui;
+  short _Accum sa;
+  long _Accum la;
+  unsigned short _Accum usa;
+  _Sat short _Accum sat_sa;
+  _Sat unsigned short _Accum sat_usa;
+
+  sa = i;
+  // CHECK:      [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
+  // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
+
+  sa = ui;
+  // CHECK:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
+  // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
+
+  usa = i2;
+  // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
+  // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
+  // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
+  // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
+  // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
+  // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
+
+  usa = ui;
+  // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
+  // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
+  // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
+  // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
+  // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
+
+  la = s;
+  // CHECK:      [[I:%[0-9]+]] = load i16, i16* %s, align 2
+  // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i16 [[I]] to i64
+  // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i64 [[I_EXT]], 31
+  // CHECK-NEXT: store i64 [[FX]], i64* %la, align 8
+}
+
+void TestIntToSatFixedPoint() {
+  int i, i2;
+  unsigned int ui;
+  _Sat short _Accum sat_sa;
+  _Sat unsigned short _Accum sat_usa;
+
+  sat_sa = i;
+  // CHECK:      [[I:%[0-9]+]] = load i32, i32* %i, align 4
+  // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+  // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
+  // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], -32768
+  // CHECK-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[SATMAX]]
+  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
+  // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
+
+  sat_sa = ui;
+  // CHECK:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+  // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
+  // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
+  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
+  // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
+
+  sat_usa = i2;
+  // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
+  // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i40
+  // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
+  // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[FX]], 65535
+  // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
+  // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SATMAX]], 0
+  // SIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[SATMAX]]
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMIN]] to i16
+  // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
+  // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %i2, align 4
+  // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+  // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
+  // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
+  // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], 0
+  // UNSIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[SATMAX]]
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
+  // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
+
+  sat_usa = ui;
+  // SIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
+  // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
+  // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i40 [[FX]], 65535
+  // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMAX]] to i16
+  // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
+  // UNSIGNED:      [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+  // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
+  // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+  // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
+  // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
+  // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
 }
index 43c5057..db15bd8 100644 (file)
@@ -233,8 +233,20 @@ void CheckSuffixOnIntegerLiterals() {
                          // expected-warning@-1{{type specifier missing, defaults to 'int'}}
 }
 
+// Ok conversions
+int i_const = -2.5hk;
+_Sat short _Accum sat_sa_const2 = 256.0k;
+_Sat unsigned short _Accum sat_usa_const = -1.0hk;
+short _Accum sa_const3 = 2;
+short _Accum sa_const4 = -2;
+
 // Overflow
 short _Accum sa_const = 256.0k;   // expected-warning{{implicit conversion from 256.0 cannot fit within the range of values for 'short _Accum'}}
 short _Fract sf_const = 1.0hk;    // expected-warning{{implicit conversion from 1.0 cannot fit within the range of values for 'short _Fract'}}
 unsigned _Accum ua_const = -1.0k; // expected-warning{{implicit conversion from -1.0 cannot fit within the range of values for 'unsigned _Accum'}}
 short _Accum sa_const2 = 128.0k + 128.0k; // expected-warning{{implicit conversion from 256.0 cannot fit within the range of values for 'short _Accum'}}
+short s_const = 65536.0lk;                // expected-warning{{implicit conversion from 65536.0 cannot fit within the range of values for 'short'}}
+unsigned u_const = -2.5hk;                // expected-warning{{implicit conversion from -2.5 cannot fit within the range of values for 'unsigned int'}}
+char c_const = 256.0uk;                   // expected-warning{{implicit conversion from 256.0 cannot fit within the range of values for 'char'}}
+short _Accum sa_const5 = 256;             // expected-warning{{implicit conversion from 256 cannot fit within the range of values for 'short _Accum'}}
+unsigned short _Accum usa_const2 = -2;    // expected-warning{{implicit conversion from -2 cannot fit within the range of values for 'unsigned short _Accum'}}
index 0cd3d04..c6a02e9 100644 (file)
@@ -22,28 +22,19 @@ void func() {
   _Fract fract = accum; // ok
   _Accum *accum_ptr;
 
-  accum = b;       // expected-error{{conversion between fixed point and '_Bool' is not yet supported}}
-  accum = i;       // expected-error{{conversion between fixed point and 'int' is not yet supported}}
-  accum = i;       // expected-error{{conversion between fixed point and 'int' is not yet supported}}
   accum = f;       // expected-error{{conversion between fixed point and 'float' is not yet supported}}
   accum = d;       // expected-error{{conversion between fixed point and 'double' is not yet supported}}
   accum = dc;      // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}}
   accum = ic;      // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}}
   accum = s;       // expected-error{{assigning to '_Accum' from incompatible type 'struct S'}}
-  accum = e;       // expected-error{{conversion between fixed point and 'enum E' is not yet supported}}
   accum = ptr;     // expected-error{{assigning to '_Accum' from incompatible type 'int *'}}
   accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}}
-  accum = i2;      // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}}
 
-  c = accum;       // expected-error{{conversion between fixed point and 'char' is not yet supported}}
-  i = accum;       // expected-error{{conversion between fixed point and 'int' is not yet supported}}
   f = accum;       // expected-error{{conversion between fixed point and 'float' is not yet supported}}
   d = accum;       // expected-error{{conversion between fixed point and 'double' is not yet supported}}
   dc = accum;      // expected-error{{conversion between fixed point and '_Complex double' is not yet supported}}
   ic = accum;      // expected-error{{conversion between fixed point and '_Complex int' is not yet supported}}
   s = accum;       // expected-error{{assigning to 'struct S' from incompatible type '_Accum'}}
-  e = accum;       // expected-error{{conversion between fixed point and 'enum E' is not yet supported}}
   ptr = accum;     // expected-error{{assigning to 'int *' from incompatible type '_Accum'}}
   ptr = accum_ptr; // expected-warning{{incompatible pointer types assigning to 'int *' from '_Accum *'}}
-  i2 = accum;      // expected-error{{conversion between fixed point and 'int' is not yet supported}}
 }