ebevhan created this revision.
ebevhan added reviewers: leonardchan, rjmccall, bjope.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The design of unsigned fixed-point with padding did not really
work as originally intended downstream.

The issue with the design is that the concept of the unsigned
padding bit disappears in the transition to IR. On the LLVM
level, there is no padding bit and anything goes with the
operations. This has the unfortunate effect of generating
invalid operations during ISel for operations that a target
should be perfectly capable of selecting for.

For example, for an unsigned saturating _Fract division of
width 16, we emit IR for an i15 udiv.fix.sat. In the legalization
of this operation in ISel, the operand and result are promoted
to i16, and to preserve the saturating behavior, the LHS is
shifted left by 1.

However... This means that we now have a division operation
with a significant value in the LHS MSB. If the target could
select this, there would be no meaning to the padding bit.
Considering that ISel will always promote this due to type
illegality, there's no way around the production of illegal
operations.

This patch changes CodeGen to emit signed operations when
emitting code for unsigned with padding. At least for us
downstream, being able to reuse the signed instructions is
the one of the points of having the padding bit, so this
design seems to align better.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82663

Files:
  clang/include/clang/Basic/FixedPoint.h
  clang/lib/Basic/FixedPoint.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/test/Frontend/fixed_point_add.c
  clang/test/Frontend/fixed_point_comparisons.c
  clang/test/Frontend/fixed_point_div.c
  clang/test/Frontend/fixed_point_mul.c
  clang/test/Frontend/fixed_point_sub.c
  clang/test/Frontend/fixed_point_unary.c

Index: clang/test/Frontend/fixed_point_unary.c
===================================================================
--- clang/test/Frontend/fixed_point_unary.c
+++ clang/test/Frontend/fixed_point_unary.c
@@ -68,28 +68,28 @@
 // CHECK:         [[TMP18:%.*]] = load i32, i32* @sua, align 4
 // SIGNED-NEXT:   [[TMP19:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[TMP18]], i32 65536)
 // SIGNED-NEXT:   store i32 [[TMP19]], i32* @sua, align 4
-// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP18]] to i31
-// UNSIGNED-NEXT: [[TMP19:%.*]] = call i31 @llvm.uadd.sat.i31(i31 [[RESIZE]], i31 32768)
-// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[TMP19]] to i32
-// UNSIGNED-NEXT: store i32 [[RESIZE1]], i32* @sua, align 4
+// UNSIGNED-NEXT: [[TMP19:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[TMP18]], i32 32768)
+// UNSIGNED-NEXT: [[TMP20:%.*]] = icmp slt i32 [[TMP19]], 0
+// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP20]], i32 0, i32 [[TMP19]]
+// UNSIGNED-NEXT: store i32 [[SATMIN]], i32* @sua, align 4
   sua++;
 
 // CHECK:         [[TMP20:%.*]] = load i16, i16* @susa, align 2
 // SIGNED-NEXT:   [[TMP21:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[TMP20]], i16 256)
 // SIGNED-NEXT:   store i16 [[TMP21]], i16* @susa, align 2
-// UNSIGNED-NEXT: [[RESIZE2:%.*]] = trunc i16 [[TMP20]] to i15
-// UNSIGNED-NEXT: [[TMP21:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE2]], i15 128)
-// UNSIGNED-NEXT: [[RESIZE3:%.*]] = zext i15 [[TMP21]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE3]], i16* @susa, align 2
+// UNSIGNED-NEXT: [[TMP22:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP20]], i16 128)
+// UNSIGNED-NEXT: [[TMP23:%.*]] = icmp slt i16 [[TMP22]], 0
+// UNSIGNED-NEXT: [[SATMIN1:%.*]] = select i1 [[TMP23]], i16 0, i16 [[TMP22]]
+// UNSIGNED-NEXT: store i16 [[SATMIN1]], i16* @susa, align 2
   susa++;
 
 // CHECK:         [[TMP22:%.*]] = load i16, i16* @suf, align 2
 // SIGNED-NEXT:   [[TMP23:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[TMP22]], i16 -1)
 // SIGNED-NEXT:   store i16 [[TMP23]], i16* @suf, align 2
-// UNSIGNED-NEXT: [[RESIZE4:%.*]] = trunc i16 [[TMP22]] to i15
-// UNSIGNED-NEXT: [[TMP23:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE4]], i15 -1)
-// UNSIGNED-NEXT: [[RESIZE5:%.*]] = zext i15 [[TMP23]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE5]], i16* @suf, align 2
+// UNSIGNED-NEXT: [[TMP25:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP22]], i16 32767)
+// UNSIGNED-NEXT: [[TMP26:%.*]] = icmp slt i16 [[TMP25]], 0
+// UNSIGNED-NEXT: [[SATMIN2:%.*]] = select i1 [[TMP26]], i16 0, i16 [[TMP25]]
+// UNSIGNED-NEXT: store i16 [[SATMIN2]], i16* @suf, align 2
   suf++;
 }
 
@@ -146,28 +146,28 @@
 // CHECK:         [[TMP18:%.*]] = load i32, i32* @sua, align 4
 // SIGNED-NEXT:   [[TMP19:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[TMP18]], i32 65536)
 // SIGNED-NEXT:   store i32 [[TMP19]], i32* @sua, align 4
-// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP18]] to i31
-// UNSIGNED-NEXT: [[TMP19:%.*]] = call i31 @llvm.usub.sat.i31(i31 [[RESIZE]], i31 32768)
-// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[TMP19]] to i32
-// UNSIGNED-NEXT: store i32 [[RESIZE1]], i32* @sua, align 4
+// UNSIGNED-NEXT: [[TMP19:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[TMP18]], i32 32768)
+// UNSIGNED-NEXT: [[TMP20:%.*]] = icmp slt i32 [[TMP19]], 0
+// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP20]], i32 0, i32 [[TMP19]]
+// UNSIGNED-NEXT: store i32 [[SATMIN]], i32* @sua, align 4
   sua--;
 
 // CHECK:         [[TMP20:%.*]] = load i16, i16* @susa, align 2
 // SIGNED-NEXT:   [[TMP21:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[TMP20]], i16 256)
 // SIGNED-NEXT:   store i16 [[TMP21]], i16* @susa, align 2
-// UNSIGNED-NEXT: [[RESIZE2:%.*]] = trunc i16 [[TMP20]] to i15
-// UNSIGNED-NEXT: [[TMP21:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE2]], i15 128)
-// UNSIGNED-NEXT: [[RESIZE3:%.*]] = zext i15 [[TMP21]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE3]], i16* @susa, align 2
+// UNSIGNED-NEXT: [[TMP22:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP20]], i16 128)
+// UNSIGNED-NEXT: [[TMP23:%.*]] = icmp slt i16 [[TMP22]], 0
+// UNSIGNED-NEXT: [[SATMIN1:%.*]] = select i1 [[TMP23]], i16 0, i16 [[TMP22]]
+// UNSIGNED-NEXT: store i16 [[SATMIN1]], i16* @susa, align 2
   susa--;
 
 // CHECK:         [[TMP22:%.*]] = load i16, i16* @suf, align 2
 // SIGNED-NEXT:   [[TMP23:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[TMP22]], i16 -1)
 // SIGNED-NEXT:   store i16 [[TMP23]], i16* @suf, align 2
-// UNSIGNED-NEXT: [[RESIZE4:%.*]] = trunc i16 [[TMP22]] to i15
-// UNSIGNED-NEXT: [[TMP23:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE4]], i15 -1)
-// UNSIGNED-NEXT: [[RESIZE5:%.*]] = zext i15 [[TMP23]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE5]], i16* @suf, align 2
+// UNSIGNED-NEXT: [[TMP25:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP22]], i16 32767)
+// UNSIGNED-NEXT: [[TMP26:%.*]] = icmp slt i16 [[TMP25]], 0
+// UNSIGNED-NEXT: [[SATMIN2:%.*]] = select i1 [[TMP26]], i16 0, i16 [[TMP25]]
+// UNSIGNED-NEXT: store i16 [[SATMIN2]], i16* @suf, align 2
   suf--;
 }
 
@@ -206,19 +206,19 @@
 // CHECK:         [[TMP12:%.*]] = load i16, i16* @susa, align 2
 // SIGNED-NEXT:   [[TMP13:%.*]] = call i16 @llvm.usub.sat.i16(i16 0, i16 [[TMP12]])
 // SIGNED-NEXT:   store i16 [[TMP13]], i16* @susa, align 2
-// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP12]] to i15
-// UNSIGNED-NEXT: [[TMP13:%.*]] = call i15 @llvm.usub.sat.i15(i15 0, i15 [[RESIZE]])
-// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP13]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @susa, align 2
+// UNSIGNED-NEXT: [[TMP13:%.*]] = call i16 @llvm.ssub.sat.i16(i16 0, i16 [[TMP12]])
+// UNSIGNED-NEXT: [[TMP14:%.*]] = icmp slt i16 [[TMP13]], 0
+// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP14]], i16 0, i16 [[TMP13]]
+// UNSIGNED-NEXT: store i16 [[SATMIN]], i16* @susa, align 2
   susa = -susa;
 
 // CHECK:         [[TMP14:%.*]] = load i16, i16* @suf, align 2
 // SIGNED-NEXT:   [[TMP15:%.*]] = call i16 @llvm.usub.sat.i16(i16 0, i16 [[TMP14]])
 // SIGNED-NEXT:   store i16 [[TMP15]], i16* @suf, align 2
-// UNSIGNED-NEXT: [[RESIZE2:%.*]] = trunc i16 [[TMP14]] to i15
-// UNSIGNED-NEXT: [[TMP15:%.*]] = call i15 @llvm.usub.sat.i15(i15 0, i15 [[RESIZE2]])
-// UNSIGNED-NEXT: [[RESIZE3:%.*]] = zext i15 [[TMP15]] to i16
-// UNSIGNED-NEXT: store i16 [[RESIZE3]], i16* @suf, align 2
+// UNSIGNED-NEXT: [[TMP16:%.*]] = call i16 @llvm.ssub.sat.i16(i16 0, i16 [[TMP14]])
+// UNSIGNED-NEXT: [[TMP17:%.*]] = icmp slt i16 [[TMP16]], 0
+// UNSIGNED-NEXT: [[SATMIN1:%.*]] = select i1 [[TMP17]], i16 0, i16 [[TMP16]]
+// UNSIGNED-NEXT: store i16 [[SATMIN1]], i16* @suf, align 2
   suf = -suf;
 }
 
Index: clang/test/Frontend/fixed_point_sub.c
===================================================================
--- clang/test/Frontend/fixed_point_sub.c
+++ clang/test/Frontend/fixed_point_sub.c
@@ -233,7 +233,8 @@
   // 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]+]] = sub i24 [[USA]], [[UF_EXT]]
-  // CHECK-NEXT: [[RES:%[a-z0-9]+]] = lshr i24 [[SUM]], 8
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = lshr i24 [[SUM]], 8
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = ashr 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;
@@ -354,11 +355,10 @@
   // CHECK-NEXT: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.usub.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.usub.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
+  // UNSIGNED-NEXT: [[SUM:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[USA]], i16 [[USA_SAT]])
+  // UNSIGNED-NEXT: [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT: store i16 [[SATMIN]], i16* %usa_sat, align 2
   usa_sat = usa - usa_sat;
 
   // CHECK:      [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
@@ -367,12 +367,12 @@
   // SIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[USA_EXT]], 8
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i32 @llvm.usub.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.usub.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
+  // UNSIGNED-NEXT:    [[RESIZE:%.*]] = zext i16 [[USA]] to i32
+  // UNSIGNED-NEXT:    [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8
+  // UNSIGNED-NEXT:    [[TMP9:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[UA]], i32 [[UPSCALE]])
+  // UNSIGNED-NEXT:    [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
+  // UNSIGNED-NEXT:    [[SATMIN1:%.*]] = select i1 [[TMP10]], i32 0, i32 [[TMP9]]
+  // UNSIGNED-NEXT:    store i32 [[SATMIN1]], i32* %ua_sat, align 4
   ua_sat = ua - usa_sat;
 
   // CHECK:      [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
@@ -407,11 +407,10 @@
   // CHECK-NEXT: [[UF_SAT2:%[0-9]+]] = load i16, i16* %uf_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.usub.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.usub.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
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]])
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT:    store i16 [[SATMIN]], i16* %uf_sat, align 2
   uf_sat = uf_sat - uf_sat;
 
   // CHECK:      [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
Index: clang/test/Frontend/fixed_point_mul.c
===================================================================
--- clang/test/Frontend/fixed_point_mul.c
+++ clang/test/Frontend/fixed_point_mul.c
@@ -207,7 +207,7 @@
   // CHECK:         [[TMP0:%.*]] = load i16, i16* %usa, align 2
   // CHECK-NEXT:    [[TMP1:%.*]] = load i16, i16* %usa, align 2
   // SIGNED-NEXT:   [[TMP2:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 8)
-  // UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7)
+  // UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7)
   // CHECK-NEXT:    store i16 [[TMP2]], i16* %usa, align 2
   usa = usa * usa;
 
@@ -216,7 +216,7 @@
   // CHECK-NEXT:    [[RESIZE:%.*]] = zext i16 [[TMP3]] to i32
   // CHECK-NEXT:    [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8
   // SIGNED-NEXT:   [[TMP5:%.*]] = call i32 @llvm.umul.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 16)
-  // UNSIGNED-NEXT: [[TMP5:%.*]] = call i32 @llvm.umul.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 15)
+  // UNSIGNED-NEXT: [[TMP5:%.*]] = call i32 @llvm.smul.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 15)
   // CHECK-NEXT:    store i32 [[TMP5]], i32* %ua, align 4
   ua = usa * ua;
 
@@ -224,7 +224,7 @@
   // CHECK-NEXT:    [[TMP7:%.*]] = load i8, i8* %usf, align 1
   // CHECK-NEXT:    [[RESIZE1:%.*]] = zext i8 [[TMP7]] to i16
   // SIGNED-NEXT:   [[TMP8:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 8)
-  // UNSIGNED-NEXT: [[TMP8:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 7)
+  // UNSIGNED-NEXT: [[TMP8:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 7)
   // CHECK-NEXT:    store i16 [[TMP8]], i16* %usa, align 2
   usa = usa * usf;
 
@@ -234,8 +234,9 @@
   // CHECK-NEXT:    [[UPSCALE3:%.*]] = shl i24 [[RESIZE2]], 8
   // CHECK-NEXT:    [[RESIZE4:%.*]] = zext i16 [[TMP10]] to i24
   // SIGNED-NEXT:   [[TMP11:%.*]] = call i24 @llvm.umul.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 16)
-  // UNSIGNED-NEXT: [[TMP11:%.*]] = call i24 @llvm.umul.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 15)
-  // CHECK-NEXT:    [[DOWNSCALE:%.*]] = lshr i24 [[TMP11]], 8
+  // SIGNED-NEXT:   [[DOWNSCALE:%.*]] = lshr i24 [[TMP11]], 8
+  // UNSIGNED-NEXT: [[TMP11:%.*]] = call i24 @llvm.smul.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 15)
+  // UNSIGNED-NEXT: [[DOWNSCALE:%.*]] = ashr i24 [[TMP11]], 8
   // CHECK-NEXT:    [[RESIZE5:%.*]] = trunc i24 [[DOWNSCALE]] to i16
   // CHECK-NEXT:    store i16 [[RESIZE5]], i16* %usa, align 2
   usa = usa * uf;
@@ -389,25 +390,22 @@
   // CHECK-NEXT: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.umul.fix.sat.i16(i16 [[USA]], i16 [[USA_SAT]], i32 8)
   // 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.umul.fix.sat.i15(i15 [[USA_TRUNC]], i15 [[USA_SAT_TRUNC]], i32 7)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
-  // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %usa_sat, align 2
+  // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.smul.fix.sat.i16(i16 [[USA]], i16 [[USA_SAT]], i32 7)
+  // UNSIGNED-NEXT: [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT: store i16 [[SATMIN]], 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
+  // CHECK:       [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
+  // CHECK-NEXT:  [[USA:%[0-9]+]] = load i16, i16* %usa_sat, align 2
+  // CHECK-NEXT:  [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i32
+  // CHECK-NEXT:  [[USA:%[a-z0-9]+]] = shl i32 [[USA_EXT]], 8
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i32 @llvm.umul.fix.sat.i32(i32 [[UA]], i32 [[USA]], i32 16)
   // 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.umul.fix.sat.i31(i31 [[UA_TRUNC]], i31 [[USA]], i32 15)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i31 [[SUM]] to i32
-  // UNSIGNED-NEXT: store i32 [[SUM_EXT]], i32* %ua_sat, align 4
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i32 @llvm.smul.fix.sat.i32(i32 [[UA]], i32 [[USA]], i32 15)
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i32 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i32 0, i32 [[SUM]]
+  // UNSIGNED-NEXT:    store i32 [[SATMIN]], i32* %ua_sat, align 4
   ua_sat = ua * usa_sat;
 
   // CHECK:      [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
@@ -442,11 +440,10 @@
   // CHECK-NEXT: [[UF_SAT2:%[0-9]+]] = load i16, i16* %uf_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.umul.fix.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]], i32 16)
   // 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.umul.fix.sat.i15(i15 [[UF_SAT_TRUNC]], i15 [[UF_SAT_TRUNC2]], i32 15)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
-  // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %uf_sat, align 2
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i16 @llvm.smul.fix.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]], i32 15)
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT:    store i16 [[SATMIN]], i16* %uf_sat, align 2
   uf_sat = uf_sat * uf_sat;
 
   // CHECK:      [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
Index: clang/test/Frontend/fixed_point_div.c
===================================================================
--- clang/test/Frontend/fixed_point_div.c
+++ clang/test/Frontend/fixed_point_div.c
@@ -228,7 +228,7 @@
   // CHECK:         [[TMP0:%.*]] = load i16, i16* %usa, align 2
   // CHECK-NEXT:    [[TMP1:%.*]] = load i16, i16* %usa, align 2
   // SIGNED-NEXT:   [[TMP2:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 8)
-  // UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7)
+  // UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7)
   // CHECK-NEXT:    store i16 [[TMP2]], i16* %usa, align 2
   usa = usa / usa;
 
@@ -237,7 +237,7 @@
   // CHECK-NEXT:    [[RESIZE:%.*]] = zext i16 [[TMP3]] to i32
   // CHECK-NEXT:    [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8
   // SIGNED-NEXT:   [[TMP5:%.*]] = call i32 @llvm.udiv.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 16)
-  // UNSIGNED-NEXT: [[TMP5:%.*]] = call i32 @llvm.udiv.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 15)
+  // UNSIGNED-NEXT: [[TMP5:%.*]] = call i32 @llvm.sdiv.fix.i32(i32 [[UPSCALE]], i32 [[TMP4]], i32 15)
   // CHECK-NEXT:    store i32 [[TMP5]], i32* %ua, align 4
   ua = usa / ua;
 
@@ -245,7 +245,7 @@
   // CHECK-NEXT:    [[TMP7:%.*]] = load i8, i8* %usf, align 1
   // CHECK-NEXT:    [[RESIZE1:%.*]] = zext i8 [[TMP7]] to i16
   // SIGNED-NEXT:   [[TMP8:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 8)
-  // UNSIGNED-NEXT: [[TMP8:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 7)
+  // UNSIGNED-NEXT: [[TMP8:%.*]] = call i16 @llvm.sdiv.fix.i16(i16 [[TMP6]], i16 [[RESIZE1]], i32 7)
   // CHECK-NEXT:    store i16 [[TMP8]], i16* %usa, align 2
   usa = usa / usf;
 
@@ -255,8 +255,9 @@
   // CHECK-NEXT:    [[UPSCALE3:%.*]] = shl i24 [[RESIZE2]], 8
   // CHECK-NEXT:    [[RESIZE4:%.*]] = zext i16 [[TMP10]] to i24
   // SIGNED-NEXT:   [[TMP11:%.*]] = call i24 @llvm.udiv.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 16)
-  // UNSIGNED-NEXT: [[TMP11:%.*]] = call i24 @llvm.udiv.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 15)
-  // CHECK-NEXT:    [[DOWNSCALE:%.*]] = lshr i24 [[TMP11]], 8
+  // SIGNED-NEXT:   [[DOWNSCALE:%.*]] = lshr i24 [[TMP11]], 8
+  // UNSIGNED-NEXT: [[TMP11:%.*]] = call i24 @llvm.sdiv.fix.i24(i24 [[UPSCALE3]], i24 [[RESIZE4]], i32 15)
+  // UNSIGNED-NEXT: [[DOWNSCALE:%.*]] = ashr i24 [[TMP11]], 8
   // CHECK-NEXT:    [[RESIZE5:%.*]] = trunc i24 [[DOWNSCALE]] to i16
   // CHECK-NEXT:    store i16 [[RESIZE5]], i16* %usa, align 2
   usa = usa / uf;
@@ -410,11 +411,10 @@
   // CHECK-NEXT: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.udiv.fix.sat.i16(i16 [[USA]], i16 [[USA_SAT]], i32 8)
   // 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.udiv.fix.sat.i15(i15 [[USA_TRUNC]], i15 [[USA_SAT_TRUNC]], i32 7)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
-  // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %usa_sat, align 2
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i16 @llvm.sdiv.fix.sat.i16(i16 [[USA]], i16 [[USA_SAT]], i32 7)
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT:    store i16 [[SATMIN]], i16* %usa_sat, align 2
   usa_sat = usa / usa_sat;
 
   // CHECK:      [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
@@ -423,12 +423,12 @@
   // SIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[USA_EXT]], 8
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i32 @llvm.udiv.fix.sat.i32(i32 [[UA]], i32 [[USA]], i32 16)
   // 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.udiv.fix.sat.i31(i31 [[UA_TRUNC]], i31 [[USA]], i32 15)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i31 [[SUM]] to i32
-  // UNSIGNED-NEXT: store i32 [[SUM_EXT]], i32* %ua_sat, align 4
+  // UNSIGNED-NEXT:    [[USA_EXT:%.*]] = zext i16 [[USA]] to i32
+  // UNSIGNED-NEXT:    [[USA:%.*]] = shl i32 [[USA_EXT]], 8
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i32 @llvm.sdiv.fix.sat.i32(i32 [[UA]], i32 [[USA]], i32 15)
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i32 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i32 0, i32 [[SUM]]
+  // UNSIGNED-NEXT:    store i32 [[SATMIN]], i32* %ua_sat, align 4
   ua_sat = ua / usa_sat;
 
   // CHECK:      [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
@@ -463,11 +463,10 @@
   // CHECK-NEXT: [[UF_SAT2:%[0-9]+]] = load i16, i16* %uf_sat, align 2
   // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.udiv.fix.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]], i32 16)
   // 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.udiv.fix.sat.i15(i15 [[UF_SAT_TRUNC]], i15 [[UF_SAT_TRUNC2]], i32 15)
-  // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
-  // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %uf_sat, align 2
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i16 @llvm.sdiv.fix.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]], i32 15)
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT:    store i16 [[SATMIN]], i16* %uf_sat, align 2
   uf_sat = uf_sat / uf_sat;
 
   // CHECK:      [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
Index: clang/test/Frontend/fixed_point_comparisons.c
===================================================================
--- clang/test/Frontend/fixed_point_comparisons.c
+++ clang/test/Frontend/fixed_point_comparisons.c
@@ -108,28 +108,32 @@
   // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
   // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
   // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
-  // CHECK-NEXT: {{.*}} = icmp ugt i32 [[UPSCALE_A]], [[A2]]
+  // SIGNED-NEXT: {{.*}} = icmp ugt i32 [[UPSCALE_A]], [[A2]]
+  // UNSIGNED-NEXT: {{.*}} = icmp sgt i32 [[UPSCALE_A]], [[A2]]
 
   usa >= ua;
   // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
   // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
   // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
   // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
-  // CHECK-NEXT: {{.*}} = icmp uge i32 [[UPSCALE_A]], [[A2]]
+  // SIGNED-NEXT: {{.*}} = icmp uge i32 [[UPSCALE_A]], [[A2]]
+  // UNSIGNED-NEXT: {{.*}} = icmp sge i32 [[UPSCALE_A]], [[A2]]
 
   usa < ua;
   // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
   // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
   // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
   // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
-  // CHECK-NEXT: {{.*}} = icmp ult i32 [[UPSCALE_A]], [[A2]]
+  // SIGNED-NEXT: {{.*}} = icmp ult i32 [[UPSCALE_A]], [[A2]]
+  // UNSIGNED-NEXT: {{.*}} = icmp slt i32 [[UPSCALE_A]], [[A2]]
 
   usa <= ua;
   // CHECK:      [[A:%[0-9]+]] = load i16, i16* %usa, align 2
   // CHECK-NEXT: [[A2:%[0-9]+]] = load i32, i32* %ua, align 4
   // CHECK-NEXT: [[RESIZE_A:%[a-z0-9]+]] = zext i16 [[A]] to i32
   // CHECK-NEXT: [[UPSCALE_A:%[a-z0-9]+]] = shl i32 [[RESIZE_A]], 8
-  // CHECK-NEXT: {{.*}} = icmp ule i32 [[UPSCALE_A]], [[A2]]
+  // SIGNED-NEXT: {{.*}} = icmp ule i32 [[UPSCALE_A]], [[A2]]
+  // UNSIGNED-NEXT: {{.*}} = icmp sle i32 [[UPSCALE_A]], [[A2]]
 }
 
 void TestIntComparisons() {
Index: clang/test/Frontend/fixed_point_add.c
===================================================================
--- clang/test/Frontend/fixed_point_add.c
+++ clang/test/Frontend/fixed_point_add.c
@@ -227,7 +227,8 @@
   // 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
+  // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = lshr i24 [[SUM]], 8
+  // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = ashr 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;
@@ -348,11 +349,10 @@
   // 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
+  // UNSIGNED-NEXT: [[SUM:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[USA]], i16 [[USA_SAT]])
+  // UNSIGNED-NEXT: [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT: store i16 [[SATMIN]], i16* %usa_sat, align 2
   usa_sat = usa + usa_sat;
 
   // CHECK:      [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
@@ -361,12 +361,12 @@
   // 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
+  // UNSIGNED-NEXT:    [[RESIZE:%.*]] = zext i16 [[USA]] to i32
+  // UNSIGNED-NEXT:    [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8
+  // UNSIGNED-NEXT:    [[TMP9:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[UA]], i32 [[UPSCALE]])
+  // UNSIGNED-NEXT:    [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
+  // UNSIGNED-NEXT:    [[SATMIN1:%.*]] = select i1 [[TMP10]], i32 0, i32 [[TMP9]]
+  // UNSIGNED-NEXT:    store i32 [[SATMIN1]], i32* %ua_sat, align 4
   ua_sat = ua + usa_sat;
 
   // CHECK:      [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
@@ -401,11 +401,10 @@
   // 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
+  // UNSIGNED-NEXT:    [[SUM:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]])
+  // UNSIGNED-NEXT:    [[USE_MIN:%.*]] = icmp slt i16 [[SUM]], 0
+  // UNSIGNED-NEXT:    [[SATMIN:%.*]] = select i1 [[USE_MIN]], i16 0, i16 [[SUM]]
+  // UNSIGNED-NEXT:    store i16 [[SATMIN]], i16* %uf_sat, align 2
   uf_sat = uf_sat + uf_sat;
 
   // CHECK:      [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -3595,7 +3595,7 @@
   auto LHSFixedSema = Ctx.getFixedPointSemantics(LHSTy);
   auto RHSFixedSema = Ctx.getFixedPointSemantics(RHSTy);
   auto ResultFixedSema = Ctx.getFixedPointSemantics(ResultTy);
-  auto CommonFixedSema = LHSFixedSema.getCommonSemantics(RHSFixedSema);
+  auto CommonFixedSema = LHSFixedSema.getCommonSemantics(RHSFixedSema, true);
 
   // Convert the operands to the full precision type.
   Value *FullLHS = EmitFixedPointConversion(LHS, LHSFixedSema, CommonFixedSema,
Index: clang/lib/Basic/FixedPoint.cpp
===================================================================
--- clang/lib/Basic/FixedPoint.cpp
+++ clang/lib/Basic/FixedPoint.cpp
@@ -124,8 +124,9 @@
   return APFixedPoint(Val, Sema);
 }
 
-FixedPointSemantics FixedPointSemantics::getCommonSemantics(
-    const FixedPointSemantics &Other) const {
+FixedPointSemantics
+FixedPointSemantics::getCommonSemantics(const FixedPointSemantics &Other,
+                                        bool UnsignedPaddingIsSigned) const {
   unsigned CommonScale = std::max(getScale(), Other.getScale());
   unsigned CommonWidth =
       std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
@@ -139,6 +140,23 @@
                                Other.hasUnsignedPadding() && !ResultIsSaturated;
   }
 
+  // For codegen purposes, make unsigned with padding semantics signed instead.
+  // This means that we will generate signed operations. The result from these
+  // operations is defined, since ending up with a negative result is undefined
+  // for nonsaturating semantics, and for saturating semantics we will
+  // perform a clamp-to-zero in the last conversion to result semantics (since
+  // we are going from saturating signed to saturating unsigned).
+  //
+  // This codegen is beneficial for targets which want to use unsigned padding,
+  // since such targets likely do not have native instructions which can
+  // implement the wider scale of unpadded unsigned and would prefer to reuse
+  // their signed operations for this.
+  if (UnsignedPaddingIsSigned && hasUnsignedPadding() &&
+      Other.hasUnsignedPadding()) {
+    ResultIsSigned = true;
+    ResultHasUnsignedPadding = false;
+  }
+
   // 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.
Index: clang/include/clang/Basic/FixedPoint.h
===================================================================
--- clang/include/clang/Basic/FixedPoint.h
+++ clang/include/clang/Basic/FixedPoint.h
@@ -63,8 +63,12 @@
   /// precision semantic that can precisely represent the precision and ranges
   /// of both input values. This does not compute the resulting semantics for a
   /// given binary operation.
+  /// Is UnsignedPaddingIsSigned is true, unsigned semantics which would
+  /// otherwise have been unsigned will be signed instead. This is for codegen
+  /// purposes.
   FixedPointSemantics
-  getCommonSemantics(const FixedPointSemantics &Other) const;
+  getCommonSemantics(const FixedPointSemantics &Other,
+                     bool UnsignedPaddingIsSigned = false) const;
 
   /// Return the FixedPointSemantics for an integer type.
   static FixedPointSemantics GetIntegerSemantics(unsigned Width,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to