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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits