leonardchan updated this revision to Diff 152385.

Repository:
  rC Clang

https://reviews.llvm.org/D48456

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/OperationKinds.def
  include/clang/AST/Type.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/TargetInfo.h
  include/clang/Lex/LiteralSupport.h
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprConstant.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Edit/RewriteObjCFoundationAPI.cpp
  lib/Lex/LiteralSupport.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaCast.cpp
  lib/Sema/SemaExpr.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  test/Frontend/fixed_point_bit_widths.c
  test/Frontend/fixed_point_conversions.c
  test/Frontend/fixed_point_declarations.c
  test/Frontend/fixed_point_errors.c
  test/Frontend/fixed_point_same_fbits.c

Index: test/Frontend/fixed_point_same_fbits.c
===================================================================
--- test/Frontend/fixed_point_same_fbits.c
+++ test/Frontend/fixed_point_same_fbits.c
@@ -1,5 +1,5 @@
-// RUN: %clang -ffixed-point -S -emit-llvm -o - %s | FileCheck %s -check-prefix=DEFAULT
-// RUN: %clang -ffixed-point -fsame-fbits -S -emit-llvm -o - %s | FileCheck %s -check-prefix=SAME
+// RUN: %clang --target=x86_64-linux -ffixed-point -S -emit-llvm -o - %s | FileCheck %s -check-prefix=DEFAULT
+// RUN: %clang --target=x86_64-linux -ffixed-point -fsame-fbits -S -emit-llvm -o - %s | FileCheck %s -check-prefix=SAME
 
 /* The scale for unsigned fixed point types should be the same as that of signed
  * fixed point types when -fsame-fbits is enabled. */
Index: test/Frontend/fixed_point_errors.c
===================================================================
--- test/Frontend/fixed_point_errors.c
+++ test/Frontend/fixed_point_errors.c
@@ -142,6 +142,8 @@
 _Accum rk = 1.0rk;    // expected-error{{invalid suffix 'rk' on integer constant}}
 _Accum rk = 1.0rr;    // expected-error{{invalid suffix 'rr' on integer constant}}
 _Accum qk = 1.0qr;    // expected-error{{invalid suffix 'qr' on integer constant}}
+_Accum no_dec = 0k;   // expected-error{{invalid suffix 'k' on integer constant}}
+_Fract no_dec2 = 0r;  // expected-error{{invalid suffix 'r' on integer constant}}
 
 /* Using wrong exponent notation */
 _Accum dec_with_hex_exp1 = 0.1p10k;    // expected-error{{invalid suffix 'p10k' on integer constant}}
Index: test/Frontend/fixed_point_declarations.c
===================================================================
--- test/Frontend/fixed_point_declarations.c
+++ test/Frontend/fixed_point_declarations.c
@@ -1,5 +1,4 @@
 // RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-linux | FileCheck %s
-// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-scei-ps4-ubuntu-fast | FileCheck %s
 
 // Primary fixed point types
 signed short _Accum   s_short_accum;  // CHECK-DAG: @s_short_accum  = {{.*}}global i16 0, align 2
Index: test/Frontend/fixed_point_conversions.c
===================================================================
--- /dev/null
+++ test/Frontend/fixed_point_conversions.c
@@ -0,0 +1,472 @@
+// RUN: %clang --target=x86_64-linux -ffixed-point -S -emit-llvm %s -o - | FileCheck %s -check-prefix=DEFAULT
+
+void TestFixedPointCastSameType() {
+  _Accum a = 2.5k;
+  _Accum a2 = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a2, align 4
+
+  a2 = (_Accum)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a2, align 4
+}
+
+void TestFixedToBool() {
+  _Accum a = 2.0k;
+  _Bool b = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[NE:%[-1-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT-NEXT: [[FROMBOOL:%[a-z0-9]+]] = zext i1 [[NE]] to i8
+// DEFAULT-NEXT: store i8 [[FROMBOOL]], i8* %b, align 1
+
+  if (a) {}
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[TOBOOL:%[a-z0-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT-NEXT: br i1 [[TOBOOL]], label %if.then, label %if.end
+
+  b = a ? 1 : 2;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[TOBOOL:%[a-z0-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT:      {{.*}} = select i1 [[TOBOOL]], i32 1, i32 2
+
+  b = (_Bool)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[NE:%[0-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT-NEXT: [[FROMBOOL:%[a-z0-9]+]] = zext i1 [[NE]] to i8
+// DEFAULT-NEXT: store i8 [[FROMBOOL]], i8* %b, align 1
+}
+
+_Bool FixedToBool(_Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[NE:%[0-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT-NEXT: ret i1 [[NE]]
+
+void TestFixedToInt() {
+  _Accum a = 2.0k;
+  unsigned _Accum ua = 2.0uk;
+  int i;
+  unsigned int ui;
+
+  i = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %i, align 4
+
+  i = ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %i, align 4
+
+  ui = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ui, align 4
+
+  ui = ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ui, align 4
+
+  i = (int)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %i, align 4
+
+  i = (int)ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %i, align 4
+
+  ui = (unsigned int)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ui, align 4
+
+  ui = (unsigned int)ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ui, align 4
+}
+
+int FixedPointToInt(_Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 15
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+int UFixedPointToInt(unsigned _Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = ashr i32 [[ACC]], 16
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+unsigned int FixedPointToUInt(_Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 15
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+unsigned int UFixedPointToUInt(unsigned _Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 16
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+void TestIntToFixed() {
+  int i = 2;
+  unsigned int ui = 2;
+  _Accum a;
+  unsigned _Accum ua;
+
+  a = i;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %a, align 4
+
+  a = ui;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %a, align 4
+
+  ua = i;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ua, align 4
+
+  ua = ui;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ua, align 4
+
+  a = (_Accum)i;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %a, align 4
+
+  a = (_Accum)ui;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: store i32 [[INT]], i32* %a, align 4
+
+  ua = (unsigned _Accum)i;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ua, align 4
+
+  ua = (unsigned _Accum)ui;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %ua, align 4
+}
+
+_Accum IntToFixedPoint(int i) { return i; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+_Accum UIntToFixedPoint(unsigned int i) { return i; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 15
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+unsigned _Accum IntToUFixedPoint(int i) { return i; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+unsigned _Accum UIntToUFixedPoint(int i) { return i; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %i.addr, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = shl i32 [[ACC]], 16
+// DEFAULT-NEXT: ret i32 [[INT]]
+
+void TestFixedPointToFloat() {
+  _Accum a = 2.5k;
+  unsigned _Accum ua = 2.5k;
+  float f = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = sitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3F00000000000000
+// DEFAULT-NEXT: store float [[ASFLOAT]], float* %f, align 4
+
+  f = ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = uitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3EF0000000000000
+// DEFAULT-NEXT: store float [[ASFLOAT]], float* %f, align 4
+
+  f = (float)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = sitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3F00000000000000
+// DEFAULT-NEXT: store float [[ASFLOAT]], float* %f, align 4
+
+  f = (float)ua;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = uitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3EF0000000000000
+// DEFAULT-NEXT: store float [[ASFLOAT]], float* %f, align 4
+}
+
+float FixedPointToFloat(_Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = sitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3F00000000000000
+// DEFAULT-NEXT: ret float [[ASFLOAT]]
+
+float UFixedPointToFloat(unsigned _Accum a) { return a; }
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a.addr, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = uitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3EF0000000000000
+// DEFAULT-NEXT: ret float [[ASFLOAT]]
+
+void TestFloatToFixedPoint() {
+  float f = 2.5;
+  _Accum a = f;
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 3.276800e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptosi float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  unsigned _Accum ua = f;
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 6.553600e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptoui float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %ua, align 4
+
+  a = (_Accum)f;
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 3.276800e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptosi float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  ua = f;
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 6.553600e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptoui float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %ua, align 4
+}
+
+_Accum FloatToFixedPoint(float f) { return f; }
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f.addr, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 3.276800e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptosi float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: ret i32 [[ACC]]
+
+unsigned _Accum FloatToUFixedPoint(float f) { return f; }
+// DEFAULT:      [[FLOAT:%[0-9]+]] = load float, float* %f.addr, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLOAT]], 6.553600e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptoui float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: ret i32 [[ACC]]
+
+void TestFixedPointCastDown() {
+  long _Accum la = 2.5lk;
+  _Accum a = la;
+// DEFAULT:      [[LACC:%[0-9]+]] = load i64, i64* %la, align 8
+// DEFAULT-NEXT: [[ACC_AS_I64:%[0-9]+]] = ashr i64 [[LACC]], 16
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = trunc i64 [[ACC_AS_I64]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  a = (_Accum)la;
+// DEFAULT:      [[LACC:%[0-9]+]] = load i64, i64* %la, align 8
+// DEFAULT-NEXT: [[ACC_AS_I64:%[0-9]+]] = ashr i64 [[LACC]], 16
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = trunc i64 [[ACC_AS_I64]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  short _Accum sa = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[SACC_AS_I32:%[0-9]+]] = ashr i32 [[ACC]], 8
+// DEFAULT-NEXT: [[SACC:%[0-9]+]] = trunc i32 [[SACC_AS_I32]] to i16
+// DEFAULT-NEXT: store i16 [[SACC]], i16* %sa, align 2
+
+  sa = (short _Accum)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[SACC_AS_I32:%[0-9]+]] = ashr i32 [[ACC]], 8
+// DEFAULT-NEXT: [[SACC:%[0-9]+]] = trunc i32 [[SACC_AS_I32]] to i16
+// DEFAULT-NEXT: store i16 [[SACC]], i16* %sa, align 2
+}
+
+void TestFixedPointCastUp() {
+  short _Accum sa = 2.5hk;
+  _Accum a = sa;
+// DEFAULT:      [[SACC:%[0-9]+]] = load i16, i16* %sa, align 2
+// DEFAULT-NEXT: [[SACC_AS_I32:%[0-9]+]] = sext i16 [[SACC]] to i32
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = shl i32 [[SACC_AS_I32]], 8
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  long _Accum la = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[ACC_AS_I64:%[0-9]+]] = sext i32 [[ACC]] to i64
+// DEFAULT-NEXT: [[LACC:%[0-9]+]] = shl i64 [[ACC_AS_I64]], 16
+// DEFAULT-NEXT: store i64 [[LACC]], i64* %la, align 8
+
+  a = (_Accum)sa;
+// DEFAULT:      [[SACC:%[0-9]+]] = load i16, i16* %sa, align 2
+// DEFAULT-NEXT: [[SACC_AS_I32:%[0-9]+]] = sext i16 [[SACC]] to i32
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = shl i32 [[SACC_AS_I32]], 8
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  la = (long _Accum)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[ACC_AS_I64:%[0-9]+]] = sext i32 [[ACC]] to i64
+// DEFAULT-NEXT: [[LACC:%[0-9]+]] = shl i64 [[ACC_AS_I64]], 16
+// DEFAULT-NEXT: store i64 [[LACC]], i64* %la, align 8
+}
+
+void TestFixedPointCastSignedness() {
+  _Accum a = 2.5k;
+  unsigned _Accum ua = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[UACC:%[0-9]+]] = shl i32 [[ACC]], 1
+// DEFAULT-NEXT: store i32 [[UACC]], i32* %ua, align 4
+
+  a = ua;
+// DEFAULT:      [[UACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = lshr i32 [[UACC]], 1
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+
+  ua = (unsigned _Accum)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[UACC:%[0-9]+]] = shl i32 [[ACC]], 1
+// DEFAULT-NEXT: store i32 [[UACC]], i32* %ua, align 4
+
+  a = (_Accum)ua;
+// DEFAULT:      [[UACC:%[0-9]+]] = load i32, i32* %ua, align 4
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = lshr i32 [[UACC]], 1
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+}
+
+void TestFixedPointCastSaturation() {
+  _Accum a = 2.5k;
+  _Sat _Accum sat_a = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %sat_a, align 4
+
+  a = sat_a;
+// DEFAULT:      [[SAT_ACC:%[0-9]+]] = load i32, i32* %sat_a, align 4
+// DEFAULT-NEXT: store i32 [[SAT_ACC]], i32* %a, align 4
+
+  sat_a = (_Sat _Accum)a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %sat_a, align 4
+
+  a = (_Accum)sat_a;
+// DEFAULT:      [[SAT_ACC:%[0-9]+]] = load i32, i32* %sat_a, align 4
+// DEFAULT-NEXT: store i32 [[SAT_ACC]], i32* %a, align 4
+}
+
+void TestFixedPointCastBetFractAccum() {
+  _Accum a = 0.5k;
+  _Fract f = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[FRACT:%[0-9]+]] = trunc i32 [[ACC]] to i16
+// DEFAULT-NEXT: store i16 [[FRACT]], i16* %f, align 2
+
+  a = f;
+// DEFAULT:      [[FRACT:%[0-9]+]] = load i16, i16* %f, align 2
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = sext i16 [[FRACT]] to i32
+// DEFAULT-NEXT: store i32 [[ACC]], i32* %a, align 4
+}
+
+void TestIntToSaturatedFixedPoint() {
+  int i = 2;
+  unsigned int ui = 2;
+
+  _Sat _Accum sat_a = i;
+// DEFAULT:      [[INT:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[SAT_A:%[0-9]+]] = shl i32 [[INT]], 15
+// DEFAULT-NEXT: [[EXT_INT:%[0-9]+]] = sext i32 [[INT]] to i33
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i33 [[EXT_INT]], 65535
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i33 [[EXT_INT]], -65536
+// DEFAULT-NEXT: [[RESULT1:%[0-9]+]] = select i1 [[USE_MIN]], i32 -2147483648, i32 [[SAT_A]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 2147483647, i32 [[RESULT1]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_a, align 4
+
+  sat_a = ui;
+// DEFAULT:      [[INT:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[SAT_A:%[0-9]+]] = shl i32 [[INT]], 15
+// DEFAULT-NEXT: [[EXT_INT:%[0-9]+]] = zext i32 [[INT]] to i33
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i33 [[EXT_INT]], 65535
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i33 [[EXT_INT]], -65536
+// DEFAULT-NEXT: [[RESULT1:%[0-9]+]] = select i1 [[USE_MIN]], i32 -2147483648, i32 [[SAT_A]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 2147483647, i32 [[RESULT1]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_a, align 4
+
+  _Sat unsigned _Accum sat_ua = i;
+// DEFAULT:      [[INT:%[0-9]+]] = load i32, i32* %i, align 4
+// DEFAULT-NEXT: [[SAT_A:%[0-9]+]] = shl i32 [[INT]], 16
+// DEFAULT-NEXT: [[EXT_INT:%[0-9]+]] = sext i32 [[INT]] to i33
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i33 [[EXT_INT]], 65535
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i33 [[EXT_INT]], 0
+// DEFAULT-NEXT: [[RESULT1:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[SAT_A]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 -1, i32 [[RESULT1]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_ua, align 4
+
+  sat_ua = ui;
+// DEFAULT:      [[INT:%[0-9]+]] = load i32, i32* %ui, align 4
+// DEFAULT-NEXT: [[SAT_A:%[0-9]+]] = shl i32 [[INT]], 16
+// DEFAULT-NEXT: [[EXT_INT:%[0-9]+]] = zext i32 [[INT]] to i33
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i33 [[EXT_INT]], 65535
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i33 [[EXT_INT]], 0
+// DEFAULT-NEXT: [[RESULT1:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[SAT_A]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 -1, i32 [[RESULT1]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_ua, align 4
+}
+
+void TestFloatToSaturatedFixedPoint() {
+  float f = 2.5;
+  _Sat _Accum a = f;
+// DEFAULT:      [[FLT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLT]], 3.276800e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptosi float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = fcmp uge float [[FLT]], 6.553600e+04
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = fcmp ule float [[FLT]], -6.553600e+04
+// DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MIN]], i32 -2147483648, i32 [[ACC]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 2147483647, i32 [[RESULT]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %a, align 4
+
+  _Sat unsigned _Accum ua = f;
+// DEFAULT:      [[FLT:%[0-9]+]] = load float, float* %f, align 4
+// DEFAULT-NEXT: [[ACC_AS_FLT:%[0-9]+]] = fmul float [[FLT]], 6.553600e+04
+// DEFAULT-NEXT: [[ACC:%[0-9]+]] = fptoui float [[ACC_AS_FLT]] to i32
+// DEFAULT-NEXT: [[USE_MAX:%[0-9]+]] = fcmp uge float [[FLT]], 6.553600e+04
+// DEFAULT-NEXT: [[USE_MIN:%[0-9]+]] = fcmp ule float [[FLT]], 0.000000e+00
+// DEFAULT-NEXT: [[RESULT:%[0-9]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACC]]
+// DEFAULT-NEXT: [[RESULT2:%[0-9]+]] = select i1 [[USE_MAX]], i32 -1, i32 [[RESULT]]
+// DEFAULT-NEXT: store i32 [[RESULT2]], i32* %ua, align 4
+}
+
+void TestUnsignedSameFBitsFixedPointToBool() {
+  unsigned _Accum a = 2.0k;
+  _Bool b = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[NE:%[-1-9]+]] = icmp ne i32 [[ACC]], 0
+// DEFAULT-NEXT: [[FROMBOOL:%[a-z0-9]+]] = zext i1 [[NE]] to i8
+// DEFAULT-NEXT: store i8 [[FROMBOOL]], i8* %b, align 1
+// SAME:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// SAME-NEXT: [[MASKED_ACC:%[0-9]+]] = and i32 [[ACC]], 2147483647
+// SAME-NEXT: [[NE:%[0-9]+]] = icmp ne i32 [[MASKED_ACC]], 0
+// SAME-NEXT: [[FROMBOOL:%[a-z0-9]+]] = zext i1 [[NE]] to i8
+// SAME-NEXT: store i8 [[FROMBOOL]], i8* %b, align 1
+}
+
+void TestUnsignedSameFBitsFixedPointToInt() {
+  unsigned _Accum a = 2;
+  unsigned int i = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[INT:%[0-9]+]] = lshr i32 [[ACC]], 16
+// DEFAULT-NEXT: store i32 [[INT]], i32* %i, align 4
+// SAME:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// SAME-NEXT: [[MASKED_ACC:%[0-9]+]] = and i32 [[ACC]], 2147483647
+// SAME-NEXT: [[INT:%[0-9]+]] = lshr i32 [[MASKED_ACC]], 15
+// SAME-NEXT: store i32 [[INT]], i32* %i, align 4
+}
+
+void TestUnsignedSameFBitsFixedPointToFloat() {
+  unsigned _Accum a = 2.5k;
+  float f = a;
+// DEFAULT:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// DEFAULT-NEXT: [[CONV:%[a-z0-9]+]] = uitofp i32 [[ACC]] to float
+// DEFAULT-NEXT: [[ASFLOAT:%[0-9]+]] = fmul float [[CONV]], 0x3EF0000000000000
+// DEFAULT-NEXT: store float [[ASFLOAT]], float* %f, align 4
+// SAME:      [[ACC:%[0-9]+]] = load i32, i32* %a, align 4
+// SAME-NEXT: [[MASKED_ACC:%[0-9]+]] = and i32 [[ACC]], 2147483647
+// SAME-NEXT: [[FLT:%[0-9]+]] = uitofp i32 [[MASKED_ACC]] to float
+// SAME-NEXT: [[FIXED_AS_FLT:%[0-9]+]] = fmul float [[FLT]], 0x3F00000000000000
+// SAME-NEXT: store float [[FIXED_AS_FLT]], float* %f, align 4
+}
Index: test/Frontend/fixed_point_bit_widths.c
===================================================================
--- test/Frontend/fixed_point_bit_widths.c
+++ test/Frontend/fixed_point_bit_widths.c
@@ -1,7 +1,4 @@
-// RUN: %clang -x c -ffixed-point -S -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang -x c -ffixed-point -S -emit-llvm -o - --target=x86_64-scei-ps4-ubuntu-fast %s | FileCheck %s
-// RUN: %clang -x c -ffixed-point -S -emit-llvm -o - --target=ppc64 %s | FileCheck %s
-// RUN: %clang -x c -ffixed-point -S -emit-llvm -o - --target=x86_64-scei-ps4-windows10pro-fast %s | FileCheck %s
+// RUN: %clang -x c -ffixed-point -S -emit-llvm -o - --target=x86_64-linux %s | FileCheck %s
 
 /* Primary signed _Accum */
 
Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -415,7 +415,13 @@
       case CK_ZeroToOCLEvent:
       case CK_ZeroToOCLQueue:
       case CK_IntToOCLSampler:
-      case CK_LValueBitCast: {
+      case CK_LValueBitCast:
+      case CK_FixedPointToBoolean:
+      case CK_IntegralToFixedPoint:
+      case CK_FixedPointToIntegral:
+      case CK_FloatingToFixedPoint:
+      case CK_FixedPointToFloating:
+      case CK_FixedPointCast: {
         state =
             handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
         continue;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3351,15 +3351,12 @@
 
     bool isSigned = !Literal.isUnsigned;
     unsigned scale = Context.getFixedPointScale(Ty);
-    unsigned ibits = Context.getFixedPointIBits(Ty);
     unsigned bit_width = Context.getTypeInfo(Ty).Width;
 
     llvm::APInt Val(bit_width, 0, isSigned);
     bool Overflowed = Literal.GetFixedPointValue(Val, scale);
 
-    // Do not use bit_width since some types may have padding like _Fract or
-    // unsigned _Accums if SameFBits is set.
-    auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width);
+    auto MaxVal = Context.getFixedPointMax(Ty);
     if (Literal.isFract && Val == MaxVal + 1)
       // Clause 6.4.4 - The value of a constant shall be in the range of
       // representable values for its type, with exception for constants of a
@@ -5852,6 +5849,7 @@
     case Type::STK_FloatingComplex:
     case Type::STK_IntegralComplex:
     case Type::STK_MemberPointer:
+    case Type::STK_FixedPoint:
       llvm_unreachable("illegal cast from pointer");
     }
     llvm_unreachable("Should have returned before this");
@@ -5884,6 +5882,32 @@
       return CK_FloatingRealToComplex;
     case Type::STK_MemberPointer:
       llvm_unreachable("member pointer type in C");
+    case Type::STK_FixedPoint:
+      return CK_IntegralToFixedPoint;
+    }
+    llvm_unreachable("Should have returned before this");
+
+  case Type::STK_FixedPoint:
+    switch (DestTy->getScalarTypeKind()) {
+      case Type::STK_CPointer:
+      case Type::STK_ObjCObjectPointer:
+      case Type::STK_BlockPointer:
+        llvm_unreachable("Invalid fixed point to pointer cast");
+      case Type::STK_Bool:
+        return CK_FixedPointToBoolean;
+      case Type::STK_Integral:
+        return CK_FixedPointToIntegral;
+      case Type::STK_Floating:
+        return CK_FixedPointToFloating;
+      case Type::STK_IntegralComplex:
+      case Type::STK_FloatingComplex:
+        // Do not allow conversion with floating points for now since these are
+        // not required by Embedded-C.
+        llvm_unreachable("Invalid fixed point to complex cast");
+      case Type::STK_MemberPointer:
+        llvm_unreachable("member pointer type in C");
+      case Type::STK_FixedPoint:
+        return CK_FixedPointCast;
     }
     llvm_unreachable("Should have returned before this");
 
@@ -5911,6 +5935,8 @@
       llvm_unreachable("valid float->pointer cast?");
     case Type::STK_MemberPointer:
       llvm_unreachable("member pointer type in C");
+    case Type::STK_FixedPoint:
+      return CK_FloatingToFixedPoint;
     }
     llvm_unreachable("Should have returned before this");
 
@@ -5940,6 +5966,8 @@
       llvm_unreachable("valid complex float->pointer cast?");
     case Type::STK_MemberPointer:
       llvm_unreachable("member pointer type in C");
+    case Type::STK_FixedPoint:
+      llvm_unreachable("Invalid complex float to fixed point cast");
     }
     llvm_unreachable("Should have returned before this");
 
@@ -5969,6 +5997,8 @@
       llvm_unreachable("valid complex int->pointer cast?");
     case Type::STK_MemberPointer:
       llvm_unreachable("member pointer type in C");
+    case Type::STK_FixedPoint:
+      llvm_unreachable("Invalid complex int to fixed point cast");
     }
     llvm_unreachable("Should have returned before this");
   }
@@ -6870,6 +6900,18 @@
     return QualType();
   }
 
+  // Check on fixed point types
+  if (RHSTy->isFixedPointType() && !Sema::CheckSupportedFixedPointCast(LHSTy)) {
+    Diag(LHS.get()->getLocStart(), diag::err_invalid_cast_with_fixed_point)
+        << LHSTy << LHS.get()->getSourceRange();
+    return QualType();
+  }
+  if (LHSTy->isFixedPointType() && !Sema::CheckSupportedFixedPointCast(RHSTy)) {
+    Diag(RHS.get()->getLocStart(), diag::err_invalid_cast_with_fixed_point)
+        << RHSTy << RHS.get()->getSourceRange();
+    return QualType();
+  }
+
   // If both operands have arithmetic type, do the usual arithmetic conversions
   // to find a common type: C99 6.5.15p3,5.
   if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
@@ -7715,6 +7757,14 @@
       !LHSType->getAs<ComplexType>())
     return Incompatible;
 
+  // Check on fixed point types
+  if ((RHSType->isFixedPointType() &&
+       !Sema::CheckSupportedFixedPointCast(LHSType)) ||
+      (LHSType->isFixedPointType() &&
+       !Sema::CheckSupportedFixedPointCast(RHSType))) {
+    return Incompatible;
+  }
+
   // Arithmetic conversions.
   if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
       !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -2607,7 +2607,25 @@
       return;
     }
   }
-  
+
+  // Check on fixed point types
+  if (SrcType->isFixedPointType() &&
+      !Sema::CheckSupportedFixedPointCast(DestType)) {
+    Self.Diag(SrcExpr.get()->getLocStart(),
+              diag::err_invalid_cast_with_fixed_point)
+        << DestType << SrcExpr.get()->getSourceRange();
+    SrcExpr = ExprError();
+    return;
+  }
+  if (DestType->isFixedPointType() &&
+      !Sema::CheckSupportedFixedPointCast(SrcType)) {
+    Self.Diag(SrcExpr.get()->getLocStart(),
+              diag::err_invalid_cast_with_fixed_point)
+        << SrcType << SrcExpr.get()->getSourceRange();
+    SrcExpr = ExprError();
+    return;
+  }
+
   DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
   DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
   DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
@@ -2705,3 +2723,10 @@
                          Op.ValueKind, CastTypeInfo, Op.Kind,
                          Op.SrcExpr.get(), &Op.BasePath, LPLoc, RPLoc));
 }
+
+bool Sema::CheckSupportedFixedPointCast(const QualType &Ty) {
+  if (!Ty->isScalarType()) return false;
+  Type::ScalarTypeKind Kind = Ty->getScalarTypeKind();
+  return (Kind == Type::STK_Bool || Kind == Type::STK_Integral ||
+          Kind == Type::STK_Floating || Kind == Type::STK_FixedPoint);
+}
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -532,6 +532,7 @@
   case Type::STK_Floating: return CK_FloatingToBoolean;
   case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean;
   case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean;
+  case Type::STK_FixedPoint: return CK_FixedPointToBoolean;
   }
   llvm_unreachable("unknown scalar type kind");
 }
Index: lib/Lex/LiteralSupport.cpp
===================================================================
--- lib/Lex/LiteralSupport.cpp
+++ lib/Lex/LiteralSupport.cpp
@@ -589,11 +589,13 @@
     switch (*s) {
     case 'R':
     case 'r':
+      if (!isFixedPointLiteral()) break;
       if (isFract || isAccum) break;
       isFract = true;
       continue;
     case 'K':
     case 'k':
+      if (!isFixedPointLiteral()) break;
       if (isFract || isAccum) break;
       isAccum = true;
       continue;
@@ -732,7 +734,7 @@
     }
   }
 
-  if (!hadError && saw_fixed_point_suffix) {
+  if (!hadError && isFixedPointLiteral()) {
     assert(isFract || isAccum);
     assert(radix == 16 || radix == 10);
   }
Index: lib/Edit/RewriteObjCFoundationAPI.cpp
===================================================================
--- lib/Edit/RewriteObjCFoundationAPI.cpp
+++ lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1086,6 +1086,14 @@
 
     case CK_BooleanToSignedIntegral:
       llvm_unreachable("OpenCL-specific cast in Objective-C?");
+
+    case CK_FixedPointToBoolean:
+    case CK_IntegralToFixedPoint:
+    case CK_FixedPointToIntegral:
+    case CK_FloatingToFixedPoint:
+    case CK_FixedPointToFloating:
+    case CK_FixedPointCast:
+      llvm_unreachable("Fixed point types are disabled for Objective-C");
     }
   }
 
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -762,6 +762,17 @@
   }
   Value *VisitAsTypeExpr(AsTypeExpr *CE);
   Value *VisitAtomicExpr(AtomicExpr *AE);
+
+  Value *ClearFixedPointPadding(QualType Ty, Value *Val) {
+    if (CGF.getContext().getTargetInfo().unsignedFixedPointTypesHavePadding() &&
+        Ty->isUnsignedFixedPointType()) {
+      unsigned NumBits = CGF.getContext().getTypeSize(Ty);
+      auto Mask = llvm::APInt::getLowBitsSet(NumBits, NumBits - 1);
+      auto MaskVal = llvm::ConstantInt::get(CGF.getLLVMContext(), Mask);
+      return Builder.CreateAnd(Val, MaskVal);
+    }
+    return Val;
+  }
 };
 }  // end anonymous namespace.
 
@@ -780,7 +791,8 @@
   if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(SrcType))
     return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT);
 
-  assert((SrcType->isIntegerType() || isa<llvm::PointerType>(Src->getType())) &&
+  assert((SrcType->isIntegerType() || SrcType->isFixedPointType() ||
+          isa<llvm::PointerType>(Src->getType())) &&
          "Unknown scalar type to convert");
 
   if (isa<llvm::IntegerType>(Src->getType()))
@@ -1775,6 +1787,188 @@
     return Builder.CreateVectorSplat(NumElements, Elt, "splat");
   }
 
+  case CK_FixedPointToIntegral: {
+    const QualType &SrcTy = E->getType();
+    assert(SrcTy->isFixedPointType());
+    assert(DestTy->isIntegerType());
+    unsigned scale = CGF.getContext().getFixedPointScale(SrcTy);
+    llvm::Value *Val = ClearFixedPointPadding(SrcTy, Visit(E));
+    if (DestTy->isSignedIntegerType())
+      return Builder.CreateAShr(
+          EmitScalarConversion(Val, SrcTy, DestTy, CE->getExprLoc()), scale);
+    else
+      return Builder.CreateLShr(
+          EmitScalarConversion(Val, SrcTy, DestTy, CE->getExprLoc()), scale);
+  }
+
+  case CK_IntegralToFixedPoint: {
+    const QualType &SrcTy = E->getType();
+    assert(SrcTy->isIntegerType());
+    assert(DestTy->isFixedPointType());
+    unsigned scale = CGF.getContext().getFixedPointScale(DestTy);
+
+    llvm::Value *IntVal = Visit(E);
+    llvm::Value *Result = Builder.CreateShl(
+        EmitScalarConversion(IntVal, SrcTy, DestTy, CE->getExprLoc()), scale);
+
+    if (DestTy->isSaturatedFixedPointType()) {
+      // Cast both sides up to one more than the highest width of the 2 to
+      // prevent truncating any bits and be able to do a simple signed
+      // comparison regardless of the signedness of either operand.
+      bool isSignedSrc = SrcTy->isSignedIntegerType();
+      bool isSignedDst = DestTy->isSignedFixedPointType();
+      unsigned IntWidth = IntVal->getType()->getIntegerBitWidth();
+      unsigned BufferWidth =
+          std::max(IntWidth, ConvertType(DestTy)->getIntegerBitWidth()) + 1;
+      llvm::Type *TmpType = Builder.getIntNTy(BufferWidth);
+
+      llvm::APInt MaxVal = CGF.getContext().getFixedPointMax(DestTy);
+      llvm::APInt MinVal = CGF.getContext().getFixedPointMin(DestTy);
+
+      llvm::APInt MaxValIntPart = MaxVal.lshr(scale);
+      llvm::APInt MinValIntPart = MinVal.ashr(scale);
+
+      MaxValIntPart = isSignedDst ? MaxValIntPart.sextOrSelf(BufferWidth)
+                                  : MaxValIntPart.zextOrSelf(BufferWidth);
+      MinValIntPart = isSignedDst ? MinValIntPart.sextOrSelf(BufferWidth)
+                                  : MinValIntPart.zextOrSelf(BufferWidth);
+
+      auto MaxValLLVM = llvm::ConstantInt::get(CGF.getLLVMContext(), MaxVal);
+      auto MinValLLVM = llvm::ConstantInt::get(CGF.getLLVMContext(), MinVal);
+      auto MaxValIntPartLLVM =
+          llvm::ConstantInt::get(CGF.getLLVMContext(), MaxValIntPart);
+      auto MinValIntPartLLVM =
+          llvm::ConstantInt::get(CGF.getLLVMContext(), MinValIntPart);
+      Value *IntValCasted = Builder.CreateIntCast(IntVal, TmpType, isSignedSrc);
+
+      llvm::Value *UseMax =
+          Builder.CreateICmpSGT(IntValCasted, MaxValIntPartLLVM);
+      llvm::Value *UseMin =
+          Builder.CreateICmpSLT(IntValCasted, MinValIntPartLLVM);
+      Result = Builder.CreateSelect(
+          UseMax, MaxValLLVM, Builder.CreateSelect(UseMin, MinValLLVM, Result));
+    }
+
+    return Result;
+  }
+
+  case CK_FixedPointToFloating: {
+    // IIRC the optimization of divide-by-power-of-two --> multiply-by-inverse
+    // does not occur at -O0, so it would be better to multiply by 2^(-fbits)
+    // instead.
+    const QualType &SrcTy = E->getType();
+    assert(SrcTy->isFixedPointType());
+    assert(DestTy->isFloatingType());
+    unsigned scale = CGF.getContext().getFixedPointScale(SrcTy);
+    auto NormalizerVal = llvm::ConstantFP::get(
+        CGF.CGM.getTypes().ConvertTypeForMem(DestTy), 1.0 / (1ULL << scale));
+    llvm::Value *Val = ClearFixedPointPadding(SrcTy, Visit(E));
+    llvm::Value *Result;
+    if (SrcTy->isSignedFixedPointType())
+      Result = Builder.CreateSIToFP(Val, CGF.ConvertType(DestTy));
+    else
+      Result = Builder.CreateUIToFP(Val, CGF.ConvertType(DestTy));
+    return Builder.CreateFMul(Result, NormalizerVal);
+  }
+
+  case CK_FloatingToFixedPoint: {
+    const QualType &SrcTy = E->getType();
+    assert(DestTy->isFixedPointType());
+    assert(SrcTy->isFloatingType());
+    bool isSignedDst = DestTy->isSignedFixedPointType();
+    const llvm::fltSemantics &SrcSema =
+        CGF.getContext().getFloatTypeSemantics(SrcTy);
+
+    llvm::APInt Normalizer = CGF.getContext().getFixedPointOne(DestTy);
+    llvm::APFloat NormalizerFlt(SrcSema, 1);
+    llvm::APFloat::roundingMode Rounding = llvm::APFloat::rmNearestTiesToEven;
+    assert(!NormalizerFlt.convertFromAPInt(Normalizer, isSignedDst, Rounding));
+
+    llvm::Value *Flt = Visit(E);
+    auto NormalizerVal = llvm::ConstantFP::get(Flt->getType(), NormalizerFlt);
+    llvm::Value *Result = Builder.CreateFMul(Flt, NormalizerVal);
+
+    if (DestTy->isSignedFixedPointType())
+      Result = Builder.CreateFPToSI(Result, CGF.ConvertType(DestTy));
+    else
+      Result = Builder.CreateFPToUI(Result, CGF.ConvertType(DestTy));
+
+    if (DestTy->isSaturatedFixedPointType()) {
+      llvm::APInt MaxVal = CGF.getContext().getFixedPointMax(DestTy);
+      llvm::APInt MinVal = CGF.getContext().getFixedPointMin(DestTy);
+      auto MaxValLLVM = llvm::ConstantInt::get(CGF.getLLVMContext(), MaxVal);
+      auto MinValLLVM = llvm::ConstantInt::get(CGF.getLLVMContext(), MinVal);
+      llvm::APFloat MaxValFlt(SrcSema, 1);
+      llvm::APFloat MinValFlt(SrcSema, 1);
+
+      if (MaxValFlt.convertFromAPInt(MaxVal, isSignedDst, Rounding) &
+          llvm::APFloat::opOverflow) {
+        return MaxValLLVM;
+      }
+
+      if (MinValFlt.convertFromAPInt(MinVal, isSignedDst, Rounding) &
+          llvm::APFloat::opOverflow) {
+        return MinValLLVM;
+      }
+
+      MaxValFlt = MaxValFlt / NormalizerFlt;
+      MinValFlt = MinValFlt / NormalizerFlt;
+
+      auto MaxValFltLLVM =
+          llvm::ConstantFP::get(CGF.getLLVMContext(), MaxValFlt);
+      auto MinValFltLLVM =
+          llvm::ConstantFP::get(CGF.getLLVMContext(), MinValFlt);
+
+      llvm::Value *UseMax = Builder.CreateFCmpUGE(Flt, MaxValFltLLVM);
+      llvm::Value *UseMin = Builder.CreateFCmpULE(Flt, MinValFltLLVM);
+      Result = Builder.CreateSelect(
+          UseMax, MaxValLLVM, Builder.CreateSelect(UseMin, MinValLLVM, Result));
+    }
+
+    return Result;
+  }
+
+  case CK_FixedPointToBoolean: {
+    const QualType &SrcTy = E->getType();
+    assert(SrcTy->isFixedPointType());
+    assert(DestTy->isBooleanType());
+    return Builder.CreateIsNotNull(ClearFixedPointPadding(SrcTy, Visit(E)));
+  }
+
+  case CK_FixedPointCast: {
+    const QualType &SrcTy = E->getType();
+    assert(DestTy->isFixedPointType());
+    assert(SrcTy->isFixedPointType());
+
+    unsigned SrcScale = CGF.getContext().getFixedPointScale(SrcTy);
+    unsigned DstScale = CGF.getContext().getFixedPointScale(DestTy);
+    unsigned SrcWidth = CGF.getContext().getTypeInfo(SrcTy).Width;
+    unsigned DstWidth = CGF.getContext().getTypeInfo(DestTy).Width;
+    llvm::Value *Result = ClearFixedPointPadding(SrcTy, Visit(E));
+    bool isSigned = SrcTy->isSignedFixedPointType();
+
+    if (DstWidth > SrcWidth)
+      // Upcast beforhand
+      Result = Builder.CreateIntCast(
+          Result, CGF.CGM.getTypes().ConvertTypeForMem(DestTy), isSigned);
+
+    if (DstScale > SrcScale) {
+      Result = Builder.CreateShl(Result, DstScale - SrcScale);
+    } else if (DstScale < SrcScale) {
+      if (isSigned)
+        Result = Builder.CreateAShr(Result, SrcScale - DstScale);
+      else
+        Result = Builder.CreateLShr(Result, SrcScale - DstScale);
+    }
+
+    if (DstWidth < SrcWidth)
+      // Downcast afterwards
+      Result = Builder.CreateIntCast(
+          Result, CGF.CGM.getTypes().ConvertTypeForMem(DestTy), isSigned);
+
+    return Result;
+  }
+
   case CK_IntegralCast:
   case CK_IntegralToFloating:
   case CK_FloatingToIntegral:
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -859,6 +859,12 @@
     case CK_FloatingCast:
     case CK_ZeroToOCLEvent:
     case CK_ZeroToOCLQueue:
+    case CK_FixedPointToBoolean:
+    case CK_IntegralToFixedPoint:
+    case CK_FixedPointToIntegral:
+    case CK_FloatingToFixedPoint:
+    case CK_FixedPointToFloating:
+    case CK_FixedPointCast:
       return nullptr;
     }
     llvm_unreachable("Invalid CastKind");
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp
+++ lib/CodeGen/CGExprComplex.cpp
@@ -509,6 +509,12 @@
   case CK_ZeroToOCLQueue:
   case CK_AddressSpaceConversion:
   case CK_IntToOCLSampler:
+  case CK_FixedPointToBoolean:
+  case CK_IntegralToFixedPoint:
+  case CK_FixedPointToIntegral:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -851,6 +851,12 @@
   case CK_ZeroToOCLQueue:
   case CK_AddressSpaceConversion:
   case CK_IntToOCLSampler:
+  case CK_FixedPointToBoolean:
+  case CK_IntegralToFixedPoint:
+  case CK_FixedPointToIntegral:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -4106,6 +4106,12 @@
   case CK_CopyAndAutoreleaseBlockObject:
   case CK_AddressSpaceConversion:
   case CK_IntToOCLSampler:
+  case CK_FixedPointToBoolean:
+  case CK_IntegralToFixedPoint:
+  case CK_FixedPointToIntegral:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -1936,6 +1936,7 @@
     if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer;
     if (BT->isInteger()) return STK_Integral;
     if (BT->isFloatingPoint()) return STK_Floating;
+    if (BT->isFixedPointType()) return STK_FixedPoint;
     llvm_unreachable("unknown scalar builtin type");
   } else if (isa<PointerType>(T)) {
     return STK_CPointer;
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -9386,6 +9386,10 @@
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
   case CK_IntToOCLSampler:
+  case CK_IntegralToFixedPoint:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -9410,7 +9414,8 @@
   case CK_FloatingToBoolean:
   case CK_BooleanToSignedIntegral:
   case CK_FloatingComplexToBoolean:
-  case CK_IntegralComplexToBoolean: {
+  case CK_IntegralComplexToBoolean:
+  case CK_FixedPointToBoolean: {
     bool BoolResult;
     if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
       return false;
@@ -9487,6 +9492,14 @@
       return false;
     return Success(Value, E);
   }
+
+  case CK_FixedPointToIntegral: {
+    assert(SrcType->isFixedPointType());
+    unsigned Scale = Info.Ctx.getFixedPointScale(SrcType);
+    if (!FixedPointExprEvaluator(Info, Result).Visit(E))
+      return false;
+    return Success(Result.getInt() >> Scale, E);
+  }
   }
 
   llvm_unreachable("unknown cast resulting in integral value");
@@ -9921,6 +9934,12 @@
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
   case CK_IntToOCLSampler:
+  case CK_FixedPointToBoolean:
+  case CK_IntegralToFixedPoint:
+  case CK_FixedPointToIntegral:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1640,6 +1640,11 @@
   case CK_ZeroToOCLEvent:
   case CK_ZeroToOCLQueue:
   case CK_IntToOCLSampler:
+  case CK_IntegralToFixedPoint:
+  case CK_FixedPointToIntegral:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
@@ -1657,6 +1662,7 @@
   case CK_LValueBitCast:            // -> bool&
   case CK_UserDefinedConversion:    // operator bool()
   case CK_BuiltinFnToFnPtr:
+  case CK_FixedPointToBoolean:
   CheckNoBasePath:
     assert(path_empty() && "Cast kind should not have a base path!");
     break;
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -10251,3 +10251,34 @@
       return 0;
   }
 }
+
+llvm::APInt ASTContext::getFixedPointMax(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  unsigned NumBits = getTypeSize(Ty);
+  llvm::APInt Val;
+
+  if (Ty->isSignedFixedPointType())
+    Val = llvm::APInt::getSignedMaxValue(NumBits);
+  else
+    Val = llvm::APInt::getMaxValue(NumBits);
+
+  if (getTargetInfo().unsignedFixedPointTypesHavePadding()) Val = Val.lshr(1);
+  return Val;
+}
+
+llvm::APInt ASTContext::getFixedPointMin(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  unsigned NumBits = getTypeSize(Ty);
+  if (Ty->isSignedFixedPointType())
+    return llvm::APInt::getSignedMinValue(NumBits);
+  else
+    return llvm::APInt::getMinValue(NumBits);
+}
+
+llvm::APInt ASTContext::getFixedPointOne(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  unsigned Scale = getFixedPointScale(Ty);
+  unsigned NumBits = getTypeSize(Ty);
+  llvm::APInt One(NumBits, 1, Ty->isSignedFixedPointType());
+  return One.shl(Scale);
+}
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2306,6 +2306,10 @@
                               QualType EnumUnderlyingTy, bool IsFixed,
                               const EnumDecl *Prev);
 
+  /// Returns true if the source type can be casted to or from a fixed point
+  /// type.
+  static bool CheckSupportedFixedPointCast(const QualType &Ty);
+
   /// Determine whether the body of an anonymous enumeration should be skipped.
   /// \param II The name of the first enumerator.
   SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
Index: include/clang/Lex/LiteralSupport.h
===================================================================
--- include/clang/Lex/LiteralSupport.h
+++ include/clang/Lex/LiteralSupport.h
@@ -72,7 +72,9 @@
   bool isFract : 1;         // 1.0hr/r/lr/uhr/ur/ulr
   bool isAccum : 1;         // 1.0hk/k/lk/uhk/uk/ulk
 
-  bool isFixedPointLiteral() const { return saw_fixed_point_suffix; }
+  bool isFixedPointLiteral() const {
+    return saw_fixed_point_suffix && (saw_period || saw_exponent);
+  }
 
   bool isIntegerLiteral() const {
     return !saw_period && !saw_exponent && !isFixedPointLiteral();
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -311,6 +311,13 @@
     }
   }
 
+  /// In the event this target uses the same number of fractional bits for its
+  /// unsigned types as it does with its signed counterparts, there will be
+  /// exactly one bit of padding.
+  /// Return true if unsigned fixed point types have padding for this target.
+  /// False otherwise.
+  bool unsignedFixedPointTypesHavePadding() const { return SameFBits; }
+
   /// Return the width (in bits) of the specified integer type enum.
   ///
   /// For example, SignedInt -> getIntWidth().
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7220,6 +7220,8 @@
 def warn_unused_volatile : Warning<
   "expression result unused; assign into a variable to force a volatile load">,
   InGroup<DiagGroup<"unused-volatile-lvalue">>;
+def err_invalid_cast_with_fixed_point : Error<
+  "%0 cannot be cast to or from a fixed point type">;
 
 def ext_cxx14_attr : Extension<
   "use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1919,7 +1919,8 @@
     STK_Integral,
     STK_Floating,
     STK_IntegralComplex,
-    STK_FloatingComplex
+    STK_FloatingComplex,
+    STK_FixedPoint
   };
 
   /// Given that this is a scalar type, classify it.
Index: include/clang/AST/OperationKinds.def
===================================================================
--- include/clang/AST/OperationKinds.def
+++ include/clang/AST/OperationKinds.def
@@ -197,6 +197,30 @@
 ///    float f = i;
 CAST_OPERATION(IntegralToFloating)
 
+/// CK_FixedPointToBoolean - Fixed point to boolean. A check against zero.
+///    (bool) 2.0k
+CAST_OPERATION(FixedPointToBoolean)
+
+/// CK_IntegralToFixedPoint - Integral to fixed point.
+///    _Accum a = i;
+CAST_OPERATION(IntegralToFixedPoint)
+
+/// CK_FixedPointToIntegral - Fixed point to integral.
+///    (int) 2.0k
+CAST_OPERATION(FixedPointToIntegral)
+
+/// CK_FloatingToFixedPoint - Floating to fixed point.
+///    _Accum a = f;
+CAST_OPERATION(FloatingToFixedPoint)
+
+/// CK_FixedPointToFloating - Fixed point to floating.
+///    (float) 2.5k
+CAST_OPERATION(FixedPointToFloating)
+
+/// CK_FixedPointCast - Fixed point tyo fixed point.
+///    (_Accum) 0.5r
+CAST_OPERATION(FixedPointCast)
+
 /// CK_FloatingToIntegral - Floating point to integral.  Rounds
 /// towards zero, discarding any fractional component.
 ///    (int) f
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1949,6 +1949,9 @@
 
   unsigned char getFixedPointScale(QualType Ty) const;
   unsigned char getFixedPointIBits(QualType Ty) const;
+  llvm::APInt getFixedPointMax(QualType Ty) const;
+  llvm::APInt getFixedPointMin(QualType Ty) const;
+  llvm::APInt getFixedPointOne(QualType Ty) const;
 
   DeclarationNameInfo getNameForTemplate(TemplateName Name,
                                          SourceLocation NameLoc) const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to