leonardchan created this revision.
leonardchan added reviewers: rjmccall, ebevhan, bjope.
leonardchan added a project: clang.

When converting to a saturating fixed point type, compare against the source 
value instead of our container value. This allows us to not create a container, 
and save up to 2 instructions from extending/truncating to this container size.

These can be seen in conversions between fixed point types of the same width, 
but different scale or different sign.


Repository:
  rC Clang

https://reviews.llvm.org/D57553

Files:
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/test/Frontend/fixed_point_add.c
  clang/test/Frontend/fixed_point_conversions.c
  clang/test/Frontend/fixed_point_sub.c

Index: clang/test/Frontend/fixed_point_sub.c
===================================================================
--- clang/test/Frontend/fixed_point_sub.c
+++ clang/test/Frontend/fixed_point_sub.c
@@ -332,11 +332,11 @@
   // 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.ssub.sat.i39(i39 [[SA_SAT_EXT]], i39 [[I]])
+  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
   // 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: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], -32768
+  // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
   sa_sat = sa_sat - i;
 
@@ -346,11 +346,11 @@
   // 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.ssub.sat.i40(i40 [[SA_SAT_EXT]], i40 [[I]])
+  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
   // 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: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], -32768
+  // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
   sa_sat = sa_sat - ui;
 
@@ -371,20 +371,20 @@
   // SIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i40
   // SIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i40 [[I_RESIZE]], 8
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.usub.sat.i40(i40 [[USA_SAT_RESIZE]], i40 [[I_UPSCALE]])
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
   // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 65535
-  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[SUM]]
-  // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RESULT]], 0
-  // SIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[RESULT]]
-  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i40 [[RESULT2]] to i16
+  // SIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RES]]
+  // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], 0
+  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]]
   // UNSIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i39
   // UNSIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i39
   // UNSIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i39 [[I_RESIZE]], 7
   // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.usub.sat.i39(i39 [[USA_SAT_RESIZE]], i39 [[I_UPSCALE]])
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
   // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767
-  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]]
-  // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RESULT]], 0
-  // UNSIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[RESULT]]
-  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i39 [[RESULT2]] to i16
+  // UNSIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], 0
+  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RESULT]], i16* %usa_sat, align 2
   usa_sat = usa_sat - i;
 }
Index: clang/test/Frontend/fixed_point_conversions.c
===================================================================
--- clang/test/Frontend/fixed_point_conversions.c
+++ clang/test/Frontend/fixed_point_conversions.c
@@ -155,75 +155,76 @@
   sat_sa = sat_a;
   // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
   // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
+  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
+  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388352
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]]
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -8388608
+  // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RESULT2]]
+  // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_sa, align 2
 
   // Accum to Fract, decreasing scale
   sat_sf = sat_a;
   // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
   // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8
-  // DEFAULT-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
+  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8
+  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 32512
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i8 127, i8 [[RESULT]]
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -32768
+  // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i8 -128, i8 [[RESULT2]]
+  // DEFAULT-NEXT: store i8 [[RESULT3]], i8* %sat_sf, align 1
 
   // Accum to Fract, same scale
   sat_f = a;
   // DEFAULT:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
+  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
   // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]]
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], -32768
+  // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RESULT2]]
+  // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_f, align 2
 
-  // Accum to Fract, increasing scale
+  // Accum to Fract, increasing scale, same size
   sat_lf = sat_a;
   // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48
-  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[ACCUM]], 16
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32
-  // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_lf, align 4
+  // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = shl i32 [[OLD_ACCUM]], 16
+  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 32767
+  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 2147483647, i32 [[FRACT]]
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -32768
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -2147483648, i32 [[RESULT]]
+  // DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_lf, align 4
+
+  sat_a = sat_lf;
+  // DEFAULT:      [[OLD_FRACT:%[0-9a-z]+]] = load i32, i32* %sat_lf, align 4
+  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_FRACT]], 16
+  // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
 
   // Signed to unsigned, decreasing scale
   _Sat _Accum sat_a2;
   sat_usa = sat_a2;
   // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
   // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7
-  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535
-  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
+  // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
+  // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388480
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RESULT]]
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0
+  // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RESULT2]]
+  // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_usa, align 2
   // SAME:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
   // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
-  // SAME-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
-  // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
-  // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
-  // SAME-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
-  // SAME-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
-  // SAME-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
-
-  // Signed to unsigned, increasing scale
+  // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
+  // SAME-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388352
+  // SAME-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]]
+  // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0
+  // SAME-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RESULT2]]
+  // SAME-NEXT: store i16 [[RESULT3]], i16* %sat_usa, align 2
+
+  // Signed to unsigned, increasing scale, same size
   sat_ua = sat_a;
   // DEFAULT:      [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
-  // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33
-  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[ACCUM_EXT]], 1
-  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0
-  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
-  // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32
-  // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_ua, align 4
+  // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[OLD_ACCUM]], 1
+  // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0
+  // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
+  // DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_ua, align 4
   // SAME:      [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
   // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
   // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
@@ -250,13 +251,13 @@
   // DEFAULT:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
   // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
   // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
-  // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+  // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i8 [[FRACT]], 0
   // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
   // DEFAULT-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
   // SAME:      [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
   // SAME-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
   // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
-  // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
+  // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i8 [[FRACT]], 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
 }
Index: clang/test/Frontend/fixed_point_add.c
===================================================================
--- clang/test/Frontend/fixed_point_add.c
+++ clang/test/Frontend/fixed_point_add.c
@@ -375,11 +375,11 @@
   // 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: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
   // 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: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], -32768
+  // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
   sa_sat = sa_sat + i;
 
@@ -389,11 +389,11 @@
   // 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: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
   // 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: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], -32768
+  // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
   sa_sat = sa_sat + ui;
 
@@ -414,20 +414,20 @@
   // SIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i40
   // SIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i40 [[I_RESIZE]], 8
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.uadd.sat.i40(i40 [[USA_SAT_RESIZE]], i40 [[I_UPSCALE]])
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
   // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 65535
-  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[SUM]]
-  // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RESULT]], 0
-  // SIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[RESULT]]
-  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i40 [[RESULT2]] to i16
+  // SIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RES]]
+  // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], 0
+  // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]]
   // UNSIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i39
   // UNSIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i39
   // UNSIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i39 [[I_RESIZE]], 7
   // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.uadd.sat.i39(i39 [[USA_SAT_RESIZE]], i39 [[I_UPSCALE]])
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
   // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767
-  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]]
-  // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RESULT]], 0
-  // UNSIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[RESULT]]
-  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i39 [[RESULT2]] to i16
+  // UNSIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]]
+  // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], 0
+  // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]]
   // CHECK-NEXT: store i16 [[RESULT]], i16* %usa_sat, align 2
   usa_sat = usa_sat + i;
 }
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -1452,7 +1452,6 @@
   using llvm::ConstantInt;
   using llvm::Value;
 
-  unsigned SrcWidth = SrcFPSema.getWidth();
   unsigned DstWidth = DstFPSema.getWidth();
   unsigned SrcScale = SrcFPSema.getScale();
   unsigned DstScale = DstFPSema.getScale();
@@ -1462,58 +1461,56 @@
   llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth);
 
   Value *Result = Src;
-  unsigned ResultWidth = SrcWidth;
 
-  if (!DstFPSema.isSaturated()) {
-    // Downscale.
-    if (DstScale < SrcScale)
-      Result = SrcIsSigned ?
-          Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
-          Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
+  // Downscale.
+  if (DstScale < SrcScale)
+    Result = SrcIsSigned
+                 ? Builder.CreateAShr(Result, SrcScale - DstScale, "downscale")
+                 : Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
 
-    // Resize.
-    Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
+  // Resize.
+  Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
 
-    // Upscale.
-    if (DstScale > SrcScale)
-      Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
-  } else {
-    // Adjust the number of fractional bits.
-    if (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");
-    } else if (DstScale < SrcScale) {
-      Result = SrcIsSigned ?
-          Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") :
-          Builder.CreateLShr(Result, SrcScale - DstScale, "downscale");
-    }
+  // Upscale.
+  if (DstScale > SrcScale)
+    Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale");
 
+  if (DstFPSema.isSaturated()) {
     // Handle saturation.
+    unsigned ResultWidth = Result->getType()->getIntegerBitWidth();
+
     bool LessIntBits = DstFPSema.getIntegralBits() < SrcFPSema.getIntegralBits();
     if (LessIntBits) {
-      Value *Max = ConstantInt::get(
-          CGF.getLLVMContext(),
-          APFixedPoint::getMax(DstFPSema).getValue().extOrTrunc(ResultWidth));
-      Value *TooHigh = SrcIsSigned ? Builder.CreateICmpSGT(Result, Max)
-                                   : Builder.CreateICmpUGT(Result, Max);
-      Result = Builder.CreateSelect(TooHigh, Max, Result, "satmax");
+      APFixedPoint FXMax = APFixedPoint::getMax(DstFPSema);
+
+      // This never overflows since the max is always positive and the semantics
+      // we convert to have more integral bits.
+      Value *MaxCmp = ConstantInt::get(CGF.getLLVMContext(),
+                                       FXMax.convert(SrcFPSema).getValue());
+
+      Value *Max = ConstantInt::get(CGF.getLLVMContext(),
+                                    FXMax.getValue().extOrTrunc(ResultWidth));
+      Value *TooHigh = SrcIsSigned ? Builder.CreateICmpSGT(Src, MaxCmp)
+                                   : Builder.CreateICmpUGT(Src, MaxCmp);
+      Result = Builder.CreateSelect(TooHigh, Max, Result);
     }
+
     // Cannot overflow min to dest type if src is unsigned since all fixed
     // point types can cover the unsigned min of 0.
     if (SrcIsSigned && (LessIntBits || !DstIsSigned)) {
-      Value *Min = ConstantInt::get(
-          CGF.getLLVMContext(),
-          APFixedPoint::getMin(DstFPSema).getValue().extOrTrunc(ResultWidth));
-      Value *TooLow = Builder.CreateICmpSLT(Result, Min);
-      Result = Builder.CreateSelect(TooLow, Min, Result, "satmin");
+      APFixedPoint FXMin = APFixedPoint::getMin(DstFPSema);
+
+      // This never overflows since the min can always for in the range of
+      // values of the semantics we convert to.
+      Value *MinCmp = ConstantInt::get(CGF.getLLVMContext(),
+                                       FXMin.convert(SrcFPSema).getValue());
+
+      Value *Min = ConstantInt::get(CGF.getLLVMContext(),
+                                    FXMin.getValue().extOrTrunc(ResultWidth));
+      Value *TooLow = SrcIsSigned ? Builder.CreateICmpSLT(Src, MinCmp)
+                                  : Builder.CreateICmpULT(Src, MinCmp);
+      Result = Builder.CreateSelect(TooLow, Min, Result);
     }
-
-    // Resize the integer part to get the final destination size.
-    if (ResultWidth != DstWidth)
-      Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
   }
   return Result;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to