leonardchan created this revision.
leonardchan added reviewers: phosek, mcgrathr, jakehehrlich, rsmith, ebevhan.
leonardchan added a project: clang.
leonardchan added a dependency: D46917: [Fixed Point Arithmetic] Comparison and 
Unary Operations for Fixed Point Types.

Add support for casting between fixed point types and integer types, floating 
point types, or other fixed point types.

Tested casts include implicit casting during assignment, passing as a function 
argument, returning from a function, and an explicit C style cast.

This patch introduces 6 different cast types: fixed to int, int to fixed, fixed 
to float, float to fix, fixed to boolean, and fixed to fixed.

Also included are:

  - A small fix for a bug where we could parse `0k` as a fixed point literal.
  - Limit the targets tested on to x86_64-linux when checking LLVM IR. This is 
done to avoid not capturing extra keywords we did not expect when running these 
tests on other platforms. 


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 = 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