leonardchan updated this revision to Diff 175965.
leonardchan marked 14 inline comments as done.
Repository:
rC Clang
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D53738/new/
https://reviews.llvm.org/D53738
Files:
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/Type.h
clang/include/clang/Basic/FixedPoint.h
clang/lib/AST/ASTContext.cpp
clang/lib/Basic/FixedPoint.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/Frontend/fixed_point_add.c
clang/test/Frontend/fixed_point_add_ast.c
clang/test/Frontend/fixed_point_conversions.c
Index: clang/test/Frontend/fixed_point_conversions.c
===================================================================
--- clang/test/Frontend/fixed_point_conversions.c
+++ clang/test/Frontend/fixed_point_conversions.c
@@ -214,19 +214,17 @@
// Only get overflow checking if signed fract to unsigned accum
sat_ua = sat_sf;
// DEFAULT: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
- // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i17
- // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i17 [[FRACT_EXT]], 9
- // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i17 [[ACCUM]], 0
- // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i17 0, i17 [[ACCUM]]
- // DEFAULT-NEXT: [[RESULT_EXT:%[0-9a-z]+]] = sext i17 [[RESULT]] to i32
- // DEFAULT-NEXT: store i32 [[RESULT_EXT]], i32* %sat_ua, align 4
+ // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
+ // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
+ // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+ // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
+ // DEFAULT-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
// SAME: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
- // SAME-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i16
- // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i16 [[FRACT_EXT]], 8
- // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i16 [[ACCUM]], 0
- // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i16 0, i16 [[ACCUM]]
- // SAME-NEXT: [[RESULT_EXT:%[0-9a-z]+]] = sext i16 [[RESULT]] to i32
- // SAME-NEXT: store i32 [[RESULT_EXT]], i32* %sat_ua, align 4
+ // SAME-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
+ // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
+ // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+ // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
+ // SAME-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
}
void TestFixedPointCastBetFractAccum() {
Index: clang/test/Frontend/fixed_point_add_ast.c
===================================================================
--- /dev/null
+++ clang/test/Frontend/fixed_point_add_ast.c
@@ -0,0 +1,337 @@
+// RUN: %clang_cc1 -x c -ffixed-point -ast-dump %s | FileCheck %s --strict-whitespace
+
+void SignedAdditions() {
+ // CHECK-LABEL: SignedAdditions
+ short _Accum sa;
+ _Accum a;
+ long _Accum la;
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ short _Fract sf;
+ _Fract f;
+ long _Fract lf;
+ unsigned short _Fract usf;
+ unsigned _Fract uf;
+ unsigned long _Fract ulf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ sa = sa + sa;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Accum' {{.*}} 'a' '_Accum'
+ a = sa + a;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'long _Accum' {{.*}} 'la' 'long _Accum'
+ la = sa + la;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-ImplicitCastExpr {{.*}} 'long _Accum' <FixedPointCast>
+ // CHECK-NEXT: `-BinaryOperator {{.*}} '_Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Accum' {{.*}} 'a' '_Accum'
+ la = sa + a;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'short _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'short _Fract' {{.*}} 'sf' 'short _Fract'
+ sa = sa + sf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Fract' {{.*}} 'f' '_Fract'
+ sa = sa + f;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'long _Fract' {{.*}} 'lf' 'long _Fract'
+ sa = sa + lf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'short _Accum' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ sa = sa + usa;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Accum' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned _Accum' {{.*}} 'ua' 'unsigned _Accum'
+ a = sa + ua;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long _Accum' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned long _Accum' {{.*}} 'ula' 'unsigned long _Accum'
+ la = sa + ula;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'short _Fract' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned short _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned short _Fract' {{.*}} 'usf' 'unsigned short _Fract'
+ sa = sa + usf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Fract' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned _Fract' {{.*}} 'uf' 'unsigned _Fract'
+ sa = sa + uf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long _Fract' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned long _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned long _Fract' {{.*}} 'ulf' 'unsigned long _Fract'
+ sa = sa + ulf;
+}
+
+void UnsignedAdditions() {
+ // CHECK-LABEL: UnsignedAdditions
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ unsigned short _Fract usf;
+ unsigned _Fract uf;
+ unsigned long _Fract ulf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ usa = usa + usa;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned _Accum' {{.*}} 'ua' 'unsigned _Accum'
+ ua = usa + ua;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned long _Accum' {{.*}} 'ula' 'unsigned long _Accum'
+ ula = usa + ula;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned short _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned short _Fract' {{.*}} 'usf' 'unsigned short _Fract'
+ usa = usa + usf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned _Fract' {{.*}} 'uf' 'unsigned _Fract'
+ usa = usa + uf;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned long _Fract' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned long _Fract' {{.*}} 'ulf' 'unsigned long _Fract'
+ usa = usa + ulf;
+}
+
+void IntAdditions() {
+ // CHECK-LABEL: IntAdditions
+ short _Accum sa;
+ unsigned short _Accum usa;
+ int i;
+ unsigned int ui;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' {{.*}} 'i' 'int'
+ sa = sa + i;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned int' {{.*}} 'ui' 'unsigned int'
+ sa = sa + ui;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' {{.*}} 'i' 'int'
+ usa = usa + i;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} 'unsigned short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned int' {{.*}} 'ui' 'unsigned int'
+ usa = usa + ui;
+}
+
+void SaturatedAdditions() {
+ // CHECK-LABEL: SaturatedAdditions
+ short _Accum sa;
+ _Accum a;
+ long _Accum la;
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ _Sat short _Accum sa_sat;
+ _Sat _Accum a_sat;
+ _Sat long _Accum la_sat;
+ _Sat unsigned short _Accum usa_sat;
+ _Sat unsigned _Accum ua_sat;
+ _Sat unsigned long _Accum ula_sat;
+
+ short _Fract sf;
+ _Fract f;
+ long _Fract lf;
+ unsigned short _Fract usf;
+ unsigned _Fract uf;
+ unsigned long _Fract ulf;
+
+ int i;
+ unsigned int ui;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ sa_sat = sa + sa_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat long _Accum' {{.*}} 'la_sat' '_Sat long _Accum'
+ la_sat = sa + la_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'long _Accum' {{.*}} 'la' 'long _Accum'
+ la_sat = sa_sat + la;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'short _Accum' {{.*}} 'sa' 'short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat short _Accum' <FixedPointCast>
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat unsigned short _Accum' {{.*}} 'usa_sat' '_Sat unsigned short _Accum'
+ sa_sat = sa + usa_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'short _Accum' <FixedPointCast>
+ // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat long _Accum' {{.*}} 'la_sat' '_Sat long _Accum'
+ la_sat = usa + la_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat unsigned long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'unsigned short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'unsigned short _Accum' {{.*}} 'usa' 'unsigned short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat unsigned long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat unsigned long _Accum' {{.*}} 'ula_sat' '_Sat unsigned long _Accum'
+ ula_sat = usa + ula_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ sa_sat = sa_sat + sa_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat long _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Sat long _Accum' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} '_Sat long _Accum' {{.*}} 'la_sat' '_Sat long _Accum'
+ la_sat = sa_sat + la_sat;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' {{.*}} 'i' 'int'
+ sa_sat = sa_sat + i;
+
+ // CHECK-NOT: FixedPointCast
+ // CHECK: `-BinaryOperator {{.*}} '_Sat short _Accum' '+'
+ // CHECK-NEXT: |-ImplicitCastExpr {{.*}} '_Sat short _Accum' <LValueToRValue>
+ // CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Sat short _Accum' {{.*}} 'sa_sat' '_Sat short _Accum'
+ // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'unsigned int' <LValueToRValue>
+ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'unsigned int' {{.*}} 'ui' 'unsigned int'
+ sa_sat = sa_sat + ui;
+}
Index: clang/test/Frontend/fixed_point_add.c
===================================================================
--- /dev/null
+++ clang/test/Frontend/fixed_point_add.c
@@ -0,0 +1,351 @@
+// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -fpadding-on-unsigned-fixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
+void SignedAddition() {
+ // CHECK-LABEL: SignedAddition
+ short _Accum sa;
+ _Accum a, b, c, d;
+ long _Accum la;
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ short _Fract sf;
+ _Fract f;
+ long _Fract lf;
+ unsigned short _Fract usf;
+ unsigned _Fract uf;
+ unsigned long _Fract ulf;
+
+ // Same type
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[SA2:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i16 [[SA]], [[SA2]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
+ sa = sa + sa;
+
+ // To larger scale and larger width
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[A:%[0-9]+]] = load i32, i32* %a, align 4
+ // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i32
+ // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i32 [[EXT_SA]], 8
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i32 [[SA]], [[A]]
+ // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
+ a = sa + a;
+
+ // To same scale and smaller width
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[SF:%[0-9]+]] = load i8, i8* %sf, align 1
+ // CHECK-NEXT: [[EXT_SF:%[a-z0-9]+]] = sext i8 [[SF]] to i16
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i16 [[SA]], [[EXT_SF]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
+ sa = sa + sf;
+
+ // To smaller scale and same width.
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[F:%[0-9]+]] = load i16, i16* %f, align 2
+ // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i24
+ // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i24 [[EXT_SA]], 8
+ // CHECK-NEXT: [[EXT_F:%[a-z0-9]+]] = sext i16 [[F]] to i24
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i24 [[SA]], [[EXT_F]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i24 [[SUM]], 8
+ // CHECK-NEXT: [[TRUNC_RES:%[a-z0-9]+]] = trunc i24 [[RES]] to i16
+ // CHECK-NEXT: store i16 [[TRUNC_RES]], i16* %sa, align 2
+ sa = sa + f;
+
+ // To smaller scale and smaller width
+ // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
+ // CHECK-NEXT: [[SF:%[0-9]+]] = load i8, i8* %sf, align 1
+ // CHECK-NEXT: [[EXT_SF:%[a-z0-9]+]] = sext i8 [[SF]] to i32
+ // CHECK-NEXT: [[SF:%[a-z0-9]+]] = shl i32 [[EXT_SF]], 8
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i32 [[A]], [[SF]]
+ // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
+ a = a + sf;
+
+ // To larger scale and same width
+ // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
+ // CHECK-NEXT: [[LF:%[0-9]+]] = load i32, i32* %lf, align 4
+ // CHECK-NEXT: [[EXT_A:%[a-z0-9]+]] = sext i32 [[A]] to i48
+ // CHECK-NEXT: [[A:%[a-z0-9]+]] = shl i48 [[EXT_A]], 16
+ // CHECK-NEXT: [[EXT_LF:%[a-z0-9]+]] = sext i32 [[LF]] to i48
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i48 [[A]], [[EXT_LF]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i48 [[SUM]], 16
+ // CHECK-NEXT: [[TRUNC_RES:%[a-z0-9]+]] = trunc i48 [[RES]] to i32
+ // CHECK-NEXT: store i32 [[TRUNC_RES]], i32* %a, align 4
+ a = a + lf;
+
+ // With corresponding unsigned type
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // SIGNED-NEXT: [[USA_SHR:%[a-z0-9]+]] = lshr i16 [[USA]], 1
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = add i16 [[SA]], [[USA_SHR]]
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = add i16 [[SA]], [[USA]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
+ sa = sa + usa;
+
+ // With unsigned of larger scale
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[USA:%[0-9]+]] = load i32, i32* %ua, align 4
+ // SIGNED-NEXT: [[USA_SHR:%[a-z0-9]+]] = lshr i32 [[USA]], 1
+ // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i32
+ // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i32 [[EXT_SA]], 8
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = add i32 [[SA]], [[USA_SHR]]
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = add i32 [[SA]], [[USA]]
+ // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
+ a = sa + ua;
+
+ // With unsigned of smaller width
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[USF:%[0-9]+]] = load i8, i8* %usf, align 1
+ // SIGNED-NEXT: [[USF_SHR:%[a-z0-9]+]] = lshr i8 [[USF]], 1
+ // SIGNED-NEXT: [[EXT_USF:%[a-z0-9]+]] = sext i8 [[USF_SHR]] to i16
+ // UNSIGNED-NEXT: [[EXT_USF:%[a-z0-9]+]] = sext i8 [[USF]] to i16
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i16 [[SA]], [[EXT_USF]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
+ sa = sa + usf;
+
+ // With unsigned of larger width and smaller scale
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[ULF:%[0-9]+]] = load i32, i32* %ulf, align 4
+ // SIGNED-NEXT: [[ULF_SHR:%[a-z0-9]+]] = lshr i32 [[ULF]], 1
+ // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i40
+ // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i40 [[EXT_SA]], 24
+ // SIGNED-NEXT: [[EXT_ULF:%[a-z0-9]+]] = sext i32 [[ULF_SHR]] to i40
+ // UNSIGNED-NEXT: [[EXT_ULF:%[a-z0-9]+]] = sext i32 [[ULF]] to i40
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i40 [[SA]], [[EXT_ULF]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i40 [[SUM]], 24
+ // CHECK-NEXT: [[RES_TRUNC:%[a-z0-9]+]] = trunc i40 [[RES]] to i16
+ // CHECK-NEXT: store i16 [[RES_TRUNC]], i16* %sa, align 2
+ sa = sa + ulf;
+
+ // Chained additions of the same signed type should result in the same
+ // semantics width.
+ // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
+ // CHECK-NEXT: [[B:%[0-9]+]] = load i32, i32* %b, align 4
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i32 [[A]], [[B]]
+ // CHECK-NEXT: [[C:%[0-9]+]] = load i32, i32* %c, align 4
+ // CHECK-NEXT: [[SUM2:%[0-9]+]] = add i32 [[SUM]], [[C]]
+ // CHECK-NEXT: [[D:%[0-9]+]] = load i32, i32* %d, align 4
+ // CHECK-NEXT: [[SUM3:%[0-9]+]] = add i32 [[SUM2]], [[D]]
+ // CHECK-NEXT: store i32 [[SUM3]], i32* %a, align 4
+ a = a + b + c + d;
+}
+
+void UnsignedAddition() {
+ // CHECK-LABEL: UnsignedAddition
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ unsigned short _Fract usf;
+ unsigned _Fract uf;
+ unsigned long _Fract ulf;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[USA2:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i16 [[USA]], [[USA2]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %usa, align 2
+ usa = usa + usa;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
+ // CHECK-NEXT: [[EXT_USA:%[a-z0-9]+]] = zext i16 [[USA]] to i32
+ // CHECK-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[EXT_USA]], 8
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i32 [[USA]], [[UA]]
+ // CHECK-NEXT: store i32 [[SUM]], i32* %ua, align 4
+ ua = usa + ua;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[USF:%[0-9]+]] = load i8, i8* %usf, align 1
+ // CHECK-NEXT: [[EXT_USF:%[a-z0-9]+]] = zext i8 [[USF]] to i16
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i16 [[USA]], [[EXT_USF]]
+ // CHECK-NEXT: store i16 [[SUM]], i16* %usa, align 2
+ usa = usa + usf;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[UF:%[0-9]+]] = load i16, i16* %uf, align 2
+ // CHECK-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i24
+ // CHECK-NEXT: [[USA:%[a-z0-9]+]] = shl i24 [[USA_EXT]], 8
+ // CHECK-NEXT: [[UF_EXT:%[a-z0-9]+]] = zext i16 [[UF]] to i24
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i24 [[USA]], [[UF_EXT]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = lshr i24 [[SUM]], 8
+ // CHECK-NEXT: [[RES_TRUNC:%[a-z0-9]+]] = trunc i24 [[RES]] to i16
+ // CHECK-NEXT: store i16 [[RES_TRUNC]], i16* %usa, align 2
+ usa = usa + uf;
+}
+
+void IntAddition() {
+ // CHECK-LABEL: IntAddition
+ short _Accum sa;
+ _Accum a;
+ unsigned short _Accum usa;
+ _Sat short _Accum sa_sat;
+ int i;
+ unsigned int ui;
+ long _Fract lf;
+ _Bool b;
+
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+ // CHECK-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i39
+ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
+ // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i39 [[SA_EXT]], [[I]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
+ // CHECK-NEXT: store i16 [[RES]], i16* %sa, align 2
+ sa = sa + i;
+
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[UI:%[0-9]+]] = load i32, i32* %ui, align 4
+ // CHECK-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i40
+ // CHECK-NEXT: [[UI_EXT:%[a-z0-9]+]] = zext i32 [[UI]] to i40
+ // CHECK-NEXT: [[UI:%[a-z0-9]+]] = shl i40 [[UI_EXT]], 7
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i40 [[SA_EXT]], [[UI]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
+ // CHECK-NEXT: store i16 [[RES]], i16* %sa, align 2
+ sa = sa + ui;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+ // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i40
+ // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i40
+ // SIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = add i40 [[USA_EXT]], [[I]]
+ // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
+ // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i39
+ // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
+ // UNSIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = add i39 [[USA_EXT]], [[I]]
+ // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
+ // CHECK-NEXT: store i16 [[RES]], i16* %usa, align 2
+ usa = usa + i;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+ // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i40
+ // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
+ // SIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = add i40 [[USA_EXT]], [[I]]
+ // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
+ // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i39
+ // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
+ // UNSIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = add i39 [[USA_EXT]], [[I]]
+ // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
+ // CHECK-NEXT: store i16 [[RES]], i16* %usa, align 2
+ usa = usa + ui;
+
+ // CHECK: [[LF:%[0-9]+]] = load i32, i32* %lf, align 4
+ // CHECK-NEXT: [[UI:%[0-9]+]] = load i32, i32* %ui, align 4
+ // CHECK-NEXT: [[LF_EXT:%[a-z0-9]+]] = sext i32 [[LF]] to i64
+ // CHECK-NEXT: [[UI_EXT:%[a-z0-9]+]] = zext i32 [[UI]] to i64
+ // CHECK-NEXT: [[UI:%[a-z0-9]+]] = shl i64 [[UI_EXT]], 31
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i64 [[LF_EXT]], [[UI]]
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i64 [[SUM]] to i32
+ // CHECK-NEXT: store i32 [[RES]], i32* %lf, align 4
+ lf = lf + ui;
+
+ // CHECK: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
+ // CHECK-NEXT: [[BOOL:%[0-9]+]] = load i8, i8* %b, align 1
+ // CHECK-NEXT: [[AS_BOOL:%[a-z0-9]+]] = trunc i8 [[BOOL]] to i1
+ // CHECK-NEXT: [[BOOL_EXT:%[a-z0-9]+]] = zext i1 [[AS_BOOL]] to i32
+ // CHECK-NEXT: [[ACCUM_EXT:%[a-z0-9]+]] = sext i32 [[ACCUM]] to i47
+ // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = sext i32 [[BOOL_EXT]] to i47
+ // CHECK-NEXT: [[BOOL_EXT:%[a-z0-9]+]] = shl i47 [[BOOL]], 15
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = add i47 [[ACCUM_EXT]], [[BOOL_EXT]]
+ // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i47 [[SUM]] to i32
+ // CHECK-NEXT: store i32 [[RESULT]], i32* %a, align 4
+ a = a + b;
+}
+
+void SaturatedAddition() {
+ // CHECK-LABEL: SaturatedAddition
+ short _Accum sa;
+ _Accum a;
+ long _Accum la;
+ unsigned short _Accum usa;
+ unsigned _Accum ua;
+ unsigned long _Accum ula;
+
+ _Sat short _Accum sa_sat;
+ _Sat _Accum a_sat;
+ _Sat long _Accum la_sat;
+ _Sat unsigned short _Accum usa_sat;
+ _Sat unsigned _Accum ua_sat;
+ _Sat unsigned long _Accum ula_sat;
+ _Sat unsigned _Fract uf_sat;
+
+ int i;
+ unsigned int ui;
+
+ // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
+ // CHECK-NEXT: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.sadd.sat.i16(i16 [[SA]], i16
+ // [[SA_SAT]])
+ // CHECK-NEXT: store i16 [[SUM]], i16* %sa_sat, align 2
+ sa_sat = sa + sa_sat;
+
+ // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
+ // CHECK-NEXT: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.uadd.sat.i16(i16 [[USA]], i16 [[USA_SAT]])
+ // SIGNED-NEXT: store i16 [[SUM]], i16* %usa_sat, align 2
+ // UNSIGNED-NEXT: [[USA_TRUNC:%[a-z0-9]+]] = trunc i16 [[USA]] to i15
+ // UNSIGNED-NEXT: [[USA_SAT_TRUNC:%[a-z0-9]+]] = trunc i16 [[USA_SAT]] to i15
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i15 @llvm.uadd.sat.i15(i15 [[USA_TRUNC]], i15 [[USA_SAT_TRUNC]])
+ // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
+ // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %usa_sat, align 2
+ usa_sat = usa + usa_sat;
+
+ // CHECK: [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
+ // CHECK-NEXT: [[USA:%[0-9]+]] = load i16, i16* %usa_sat, align 2
+ // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i32
+ // SIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[USA_EXT]], 8
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i32 @llvm.uadd.sat.i32(i32 [[UA]], i32 [[USA]])
+ // SIGNED-NEXT: store i32 [[SUM]], i32* %ua_sat, align 4
+ // UNSIGNED-NEXT: [[UA_TRUNC:%[a-z0-9]+]] = trunc i32 [[UA]] to i31
+ // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i31
+ // UNSIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i31 [[USA_EXT]], 8
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i31 @llvm.uadd.sat.i31(i31 [[UA_TRUNC]], i31 [[USA]])
+ // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i31 [[SUM]] to i32
+ // UNSIGNED-NEXT: store i32 [[SUM_EXT]], i32* %ua_sat, align 4
+ ua_sat = ua + usa_sat;
+
+ // CHECK: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
+ // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
+ // CHECK-NEXT: [[SA_SAT_EXT:%[a-z0-9]+]] = sext i16 [[SA_SAT]] to i39
+ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
+ // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.sadd.sat.i39(i39 [[SA_SAT_EXT]], i39 [[I]])
+ // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]]
+ // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RES]], -32768
+ // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[RES]]
+ // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i39 [[RES2]] to i16
+ // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
+ sa_sat = sa_sat + i;
+
+ // CHECK: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
+ // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
+ // CHECK-NEXT: [[SA_SAT_EXT:%[a-z0-9]+]] = sext i16 [[SA_SAT]] to i40
+ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
+ // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 7
+ // CHECK-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.sadd.sat.i40(i40 [[SA_SAT_EXT]], i40 [[I]])
+ // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 32767
+ // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 32767, i40 [[SUM]]
+ // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RES]], -32768
+ // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 -32768, i40 [[RES]]
+ // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i40 [[RES2]] to i16
+ // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
+ sa_sat = sa_sat + ui;
+
+ // CHECK: [[UF_SAT:%[0-9]+]] = load i16, i16* %uf_sat, align 2
+ // CHECK-NEXT: [[UF_SAT2:%[0-9]+]] = load i16, i16* %uf_sat, align 2
+ // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.uadd.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]])
+ // SIGNED-NEXT: store i16 [[SUM]], i16* %uf_sat, align 2
+ // UNSIGNED-NEXT: [[UF_SAT_TRUNC:%[a-z0-9]+]] = trunc i16 [[UF_SAT]] to i15
+ // UNSIGNED-NEXT: [[UF_SAT_TRUNC2:%[a-z0-9]+]] = trunc i16 [[UF_SAT2]] to i15
+ // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i15 @llvm.uadd.sat.i15(i15 [[UF_SAT_TRUNC]], i15 [[UF_SAT_TRUNC2]])
+ // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
+ // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %uf_sat, align 2
+ uf_sat = uf_sat + uf_sat;
+}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -1229,6 +1229,99 @@
return ComplexType;
}
+/// Return the rank of a given fixed point or integer type. The value itself
+/// doesn't matter, but the values must be increasing with proper increasing
+/// rank as described in N1169 4.1.1.
+static unsigned GetFixedPointRank(QualType Ty) {
+ if (Ty->isIntegerType())
+ return 0;
+
+ const auto *BTy = Ty->getAs<BuiltinType>();
+ switch (BTy->getKind()) {
+ case BuiltinType::ShortFract:
+ case BuiltinType::UShortFract:
+ case BuiltinType::SatShortFract:
+ case BuiltinType::SatUShortFract:
+ return 1;
+ case BuiltinType::Fract:
+ case BuiltinType::UFract:
+ case BuiltinType::SatFract:
+ case BuiltinType::SatUFract:
+ return 2;
+ case BuiltinType::LongFract:
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatLongFract:
+ case BuiltinType::SatULongFract:
+ return 3;
+ case BuiltinType::ShortAccum:
+ case BuiltinType::UShortAccum:
+ case BuiltinType::SatShortAccum:
+ case BuiltinType::SatUShortAccum:
+ return 4;
+ case BuiltinType::Accum:
+ case BuiltinType::UAccum:
+ case BuiltinType::SatAccum:
+ case BuiltinType::SatUAccum:
+ return 5;
+ case BuiltinType::LongAccum:
+ case BuiltinType::ULongAccum:
+ case BuiltinType::SatLongAccum:
+ case BuiltinType::SatULongAccum:
+ return 6;
+ default:
+ llvm_unreachable("Unexpected fixed point or integer type");
+ }
+}
+
+/// handleFixedPointConversion - Fixed point operations between fixed
+/// point types and integers or other fixed point types do not fall under
+/// usual arithmetic conversion since these conversions could result in loss
+/// of precsision (N1169 4.1.4). These operations should be calculated with
+/// the full precision of their result type (N1169 4.1.6.2.1).
+static QualType handleFixedPointConversion(Sema &S, ExprResult &LHSExpr,
+ ExprResult &RHSExpr, QualType LHSTy,
+ QualType RHSTy) {
+ assert((LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) &&
+ "Expected at least one of the operands to be a fixed point type");
+ assert((LHSTy->isFixedPointOrIntegerType() ||
+ RHSTy->isFixedPointOrIntegerType()) &&
+ "Special fixed point arithmetic operation conversions are only "
+ "applied to ints or other fixed point types");
+
+ // If one operand has signed fixed-point type and the other operand has
+ // unsigned fixed-point type, then the unsigned fixed-point operand is
+ // converted to its corresponding signed fixed-point type and the resulting
+ // type is the type of the converted operand.
+ if (RHSTy->isSignedFixedPointType() && LHSTy->isUnsignedFixedPointType()) {
+ QualType ResultTy = S.Context.getCorrespondingSignedFixedPointType(LHSTy);
+ LHSExpr = S.ImpCastExprToType(LHSExpr.get(), ResultTy, CK_FixedPointCast);
+ LHSTy = ResultTy;
+ } else if (RHSTy->isUnsignedFixedPointType() &&
+ LHSTy->isSignedFixedPointType()) {
+ QualType ResultTy = S.Context.getCorrespondingSignedFixedPointType(RHSTy);
+ RHSExpr = S.ImpCastExprToType(RHSExpr.get(), ResultTy, CK_FixedPointCast);
+ RHSTy = ResultTy;
+ }
+
+ // The result type is the type with the highest rank, whereby a fixed-point
+ // conversion rank is always greater than an integer conversion rank; if the
+ // type of either of the operands is a saturating fixedpoint type, the result
+ // type shall be the saturating fixed-point type corresponding to the type
+ // with the highest rank; the resulting value is converted (taking into
+ // account rounding and overflow) to the precision of the resulting type.
+ // Same ranks between signed and unsigned types are resolved earlier, so both
+ // types are either signed or both unsigned at this point.
+ unsigned LHSTyRank = GetFixedPointRank(LHSTy);
+ unsigned RHSTyRank = GetFixedPointRank(RHSTy);
+
+ QualType ResultTy = LHSTyRank > RHSTyRank ? LHSTy : RHSTy;
+
+ if (LHSTy->isSaturatedFixedPointType() || RHSTy->isSaturatedFixedPointType())
+ ResultTy = S.Context.getCorrespondingSaturatedType(ResultTy);
+
+ return ResultTy;
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
@@ -1301,12 +1394,14 @@
return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
IsCompAssign);
+ if (LHSType->isFixedPointType() || RHSType->isFixedPointType())
+ return handleFixedPointConversion(*this, LHS, RHS, LHSType, RHSType);
+
// Finally, we have two differing integer types.
return handleIntegerConversion<doIntegralCast, doIntegralCast>
(*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
}
-
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -125,6 +125,13 @@
return CFP->isZero();
return true;
}
+
+ /// Check if either operand is a fixed point type, in which case, this
+ /// operation did not follow usual arithmetic conversion and both operands may
+ /// not be the same.
+ bool isFixedPointBinOp() const {
+ return isa<BinaryOperator>(E) && Ty->isFixedPointType();
+ }
};
static bool MustVisitNullValue(const Expr *E) {
@@ -347,6 +354,9 @@
Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy,
SourceLocation Loc);
+ Value *EmitFixedPointConversion(Value *Src, FixedPointSemantics &SrcFixedSema,
+ FixedPointSemantics &DstFixedSema,
+ SourceLocation Loc);
/// Emit a conversion from the specified complex type to the specified
/// destination type, where the destination type is an LLVM scalar type.
@@ -725,6 +735,9 @@
return Builder.CreateOr(Ops.LHS, Ops.RHS, "or");
}
+ // Helper functions for fixed point binary operations.
+ Value *EmitFixedPointAdd(const BinOpInfo &Ops);
+
BinOpInfo EmitBinOps(const BinaryOperator *E);
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
@@ -1419,10 +1432,6 @@
Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
QualType DstTy,
SourceLocation Loc) {
- using llvm::APInt;
- using llvm::ConstantInt;
- using llvm::Value;
-
assert(SrcTy->isFixedPointType());
assert(DstTy->isFixedPointType());
@@ -1430,6 +1439,16 @@
CGF.getContext().getFixedPointSemantics(SrcTy);
FixedPointSemantics DstFPSema =
CGF.getContext().getFixedPointSemantics(DstTy);
+ return EmitFixedPointConversion(Src, SrcFPSema, DstFPSema, Loc);
+}
+
+Value *ScalarExprEmitter::EmitFixedPointConversion(
+ Value *Src, FixedPointSemantics &SrcFPSema, FixedPointSemantics &DstFPSema,
+ SourceLocation Loc) {
+ using llvm::APInt;
+ using llvm::ConstantInt;
+ using llvm::Value;
+
unsigned SrcWidth = SrcFPSema.getWidth();
unsigned DstWidth = DstFPSema.getWidth();
unsigned SrcScale = SrcFPSema.getScale();
@@ -1458,7 +1477,8 @@
} else {
// Adjust the number of fractional bits.
if (DstScale > SrcScale) {
- ResultWidth = SrcWidth + DstScale - SrcScale;
+ // Compare to DstWidth to prevent resizing twice.
+ ResultWidth = std::max(SrcWidth + DstScale - SrcScale, DstWidth);
llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth);
Result = Builder.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize");
Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
@@ -1489,7 +1509,8 @@
}
// Resize the integer part to get the final destination size.
- Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
+ if (ResultWidth != DstWidth)
+ Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
}
return Result;
}
@@ -3334,9 +3355,59 @@
return propagateFMFlags(V, op);
}
+ if (op.isFixedPointBinOp())
+ return EmitFixedPointAdd(op);
+
return Builder.CreateAdd(op.LHS, op.RHS, "add");
}
+/// The resulting value must be calculated with exact precision, so the operands
+/// may not be the same type.
+Value *ScalarExprEmitter::EmitFixedPointAdd(const BinOpInfo &op) {
+ using llvm::APSInt;
+ using llvm::ConstantInt;
+
+ const auto *BinOp = dyn_cast<BinaryOperator>(op.E);
+ assert(BinOp && "Expected the operator to be a binary operator");
+ assert(BinOp->getOpcode() == BO_Add && "Expected operation to be addition");
+
+ // The result is a fixed point type and at least one of the operands is fixed
+ // point while the other is either fixed point or an int. This resulting type
+ // should be determined by Sema::handleFixedPointConversions().
+ QualType ResultTy = op.Ty;
+ QualType LHSTy = BinOp->getLHS()->getType();
+ QualType RHSTy = BinOp->getRHS()->getType();
+ ASTContext &Ctx = CGF.getContext();
+ Value *LHS = op.LHS;
+ Value *RHS = op.RHS;
+
+ auto LHSFixedSema = Ctx.getFixedPointSemantics(LHSTy);
+ auto RHSFixedSema = Ctx.getFixedPointSemantics(RHSTy);
+ auto ResultFixedSema = Ctx.getFixedPointSemantics(ResultTy);
+ auto CommonFixedSema = LHSFixedSema.getCommonSemantics(RHSFixedSema);
+
+ // Convert the operands to the full precision type.
+ Value *FullLHS = EmitFixedPointConversion(LHS, LHSFixedSema, CommonFixedSema,
+ BinOp->getExprLoc());
+ Value *FullRHS = EmitFixedPointConversion(RHS, RHSFixedSema, CommonFixedSema,
+ BinOp->getExprLoc());
+
+ // Perform the actual addition.
+ Value *Result;
+ if (CommonFixedSema.isSaturated()) {
+ llvm::Intrinsic::ID IID = CommonFixedSema.isSigned()
+ ? llvm::Intrinsic::sadd_sat
+ : llvm::Intrinsic::uadd_sat;
+ Result = Builder.CreateBinaryIntrinsic(IID, FullLHS, FullRHS);
+ } else {
+ Result = Builder.CreateAdd(FullLHS, FullRHS);
+ }
+
+ // Convert to the result type.
+ return EmitFixedPointConversion(Result, CommonFixedSema, ResultFixedSema,
+ BinOp->getExprLoc());
+}
+
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// The LHS is always a pointer if either side is.
if (!op.LHS->getType()->isPointerTy()) {
Index: clang/lib/Basic/FixedPoint.cpp
===================================================================
--- clang/lib/Basic/FixedPoint.cpp
+++ clang/lib/Basic/FixedPoint.cpp
@@ -112,4 +112,29 @@
return APFixedPoint(Val, Sema);
}
+FixedPointSemantics FixedPointSemantics::getCommonSemantics(
+ const FixedPointSemantics &Other) const {
+ unsigned CommonScale = std::max(getScale(), Other.getScale());
+ unsigned CommonWidth =
+ std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
+
+ bool ResultIsSigned = isSigned() || Other.isSigned();
+ bool ResultIsSaturated = isSaturated() || Other.isSaturated();
+ bool ResultHasUnsignedPadding = false;
+ if (!ResultIsSigned) {
+ // Both are unsigned.
+ ResultHasUnsignedPadding = hasUnsignedPadding() &&
+ Other.hasUnsignedPadding() && !ResultIsSaturated;
+ }
+
+ // If the result is signed, add an extra bit for the sign. Otherwise, if it is
+ // unsigned and has unsigned padding, we only need to add the extra padding
+ // bit back if we are not saturating.
+ if (ResultIsSigned || ResultHasUnsignedPadding)
+ CommonWidth++;
+
+ return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
+ ResultIsSaturated, ResultHasUnsignedPadding);
+}
+
} // namespace clang
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -10488,7 +10488,13 @@
}
FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const {
- assert(Ty->isFixedPointType());
+ assert(Ty->isFixedPointType() ||
+ Ty->isIntegerType() && "Can only get the fixed point semantics for a "
+ "fixed point or integer type.");
+ if (Ty->isIntegerType())
+ return FixedPointSemantics::GetIntegerSemantics(getIntWidth(Ty),
+ Ty->isSignedIntegerType());
+
bool isSigned = Ty->isSignedFixedPointType();
return FixedPointSemantics(
static_cast<unsigned>(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned,
@@ -10505,3 +10511,38 @@
assert(Ty->isFixedPointType());
return APFixedPoint::getMin(getFixedPointSemantics(Ty));
}
+
+QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
+ assert(Ty->isUnsignedFixedPointType() &&
+ "Expected unsigned fixed point type");
+ const auto *BTy = Ty->getAs<BuiltinType>();
+
+ switch (BTy->getKind()) {
+ case BuiltinType::UShortAccum:
+ return ShortAccumTy;
+ case BuiltinType::UAccum:
+ return AccumTy;
+ case BuiltinType::ULongAccum:
+ return LongAccumTy;
+ case BuiltinType::SatUShortAccum:
+ return SatShortAccumTy;
+ case BuiltinType::SatUAccum:
+ return SatAccumTy;
+ case BuiltinType::SatULongAccum:
+ return SatLongAccumTy;
+ case BuiltinType::UShortFract:
+ return ShortFractTy;
+ case BuiltinType::UFract:
+ return FractTy;
+ case BuiltinType::ULongFract:
+ return LongFractTy;
+ case BuiltinType::SatUShortFract:
+ return SatShortFractTy;
+ case BuiltinType::SatUFract:
+ return SatFractTy;
+ case BuiltinType::SatULongFract:
+ return SatLongFractTy;
+ default:
+ llvm_unreachable("Unexpected unsigned fixed point type");
+ }
+}
Index: clang/include/clang/Basic/FixedPoint.h
===================================================================
--- clang/include/clang/Basic/FixedPoint.h
+++ clang/include/clang/Basic/FixedPoint.h
@@ -18,6 +18,7 @@
#define LLVM_CLANG_BASIC_FIXEDPOINT_H
#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
@@ -36,6 +37,8 @@
: Width(Width), Scale(Scale), IsSigned(IsSigned),
IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) {
assert(Width >= Scale && "Not enough room for the scale");
+ assert(!(IsSigned && HasUnsignedPadding) &&
+ "Cannot have unsigned padding on a signed type.");
}
unsigned getWidth() const { return Width; }
@@ -46,6 +49,9 @@
void setSaturated(bool Saturated) { IsSaturated = Saturated; }
+ /// Return the number of integral bits represented by these semantics. These
+ /// are separate from the fractional bits and do not include the sign or
+ /// padding bit.
unsigned getIntegralBits() const {
if (IsSigned || (!IsSigned && HasUnsignedPadding))
return Width - Scale - 1;
@@ -53,6 +59,21 @@
return Width - Scale;
}
+ /// Return the FixedPointSemantics that allows for calculating the full
+ /// precision semantic between this one and another one. The semantics will
+ /// not be saturated since the entire result is able to be stored in these
+ /// semantics.
+ FixedPointSemantics
+ getCommonSemantics(const FixedPointSemantics &Other) const;
+
+ /// Return the FixedPointSemantics for an integer type.
+ static FixedPointSemantics GetIntegerSemantics(unsigned Width,
+ bool IsSigned) {
+ return FixedPointSemantics(Width, /*Scale=*/0, IsSigned,
+ /*IsSaturated=*/false,
+ /*HasUnsignedPadding=*/false);
+ }
+
private:
unsigned Width;
unsigned Scale;
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -2275,6 +2275,9 @@
/// ISO/IEC JTC1 SC22 WG14 N1169.
bool isFixedPointType() const;
+ /// Return true if this is a fixed point or integer type.
+ bool isFixedPointOrIntegerType() const;
+
/// Return true if this is a saturated fixed point type according to
/// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned.
bool isSaturatedFixedPointType() const;
@@ -6582,6 +6585,10 @@
return false;
}
+inline bool Type::isFixedPointOrIntegerType() const {
+ return isFixedPointType() || isIntegerType();
+}
+
inline bool Type::isSaturatedFixedPointType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
return BT->getKind() >= BuiltinType::SatShortAccum &&
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2623,6 +2623,12 @@
// corresponding saturated type for a given fixed point type.
QualType getCorrespondingSaturatedType(QualType Ty) const;
+ // This method accepts fixed point types and returns the corresponding signed
+ // type. Unlike getCorrespondingUnsignedType(), this only accepts unsigned
+ // fixed point types because there are unsigned integer types like bool and
+ // char8_t that don't have signed equivalents.
+ QualType getCorrespondingSignedFixedPointType(QualType Ty) const;
+
//===--------------------------------------------------------------------===//
// Integer Values
//===--------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits