[clang] 577f8b1 - [Fixed Point] Add codegen for fixed-point shifts.

Bevin Hansson via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 24 05:38:11 PDT 2020


Author: Bevin Hansson
Date: 2020-08-24T14:37:16+02:00
New Revision: 577f8b157a03055821341146ed0617e3b103fdaf

URL: https://github.com/llvm/llvm-project/commit/577f8b157a03055821341146ed0617e3b103fdaf
DIFF: https://github.com/llvm/llvm-project/commit/577f8b157a03055821341146ed0617e3b103fdaf.diff

LOG: [Fixed Point] Add codegen for fixed-point shifts.

This patch adds codegen to Clang for fixed-point shift
operations.

Reviewed By: leonardchan

Differential Revision: https://reviews.llvm.org/D83294

Added: 
    clang/test/Frontend/fixed_point_shift_const.c

Modified: 
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/test/Frontend/fixed_point_compound.c
    clang/test/Frontend/fixed_point_shift.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index b3857b3eeb06..d0ec50f4e011 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3535,6 +3535,14 @@ Value *ScalarExprEmitter::EmitFixedPointBinOp(const BinOpInfo &op) {
   case BO_Div:
     Result = FPBuilder.CreateDiv(LHS, LHSFixedSema, RHS, RHSFixedSema);
     break;
+  case BO_ShlAssign:
+  case BO_Shl:
+    Result = FPBuilder.CreateShl(LHS, LHSFixedSema, RHS);
+    break;
+  case BO_ShrAssign:
+  case BO_Shr:
+    Result = FPBuilder.CreateShr(LHS, LHSFixedSema, RHS);
+    break;
   case BO_LT:
     return FPBuilder.CreateLT(LHS, LHSFixedSema, RHS, RHSFixedSema);
   case BO_GT:
@@ -3550,13 +3558,9 @@ Value *ScalarExprEmitter::EmitFixedPointBinOp(const BinOpInfo &op) {
     return FPBuilder.CreateEQ(LHS, LHSFixedSema, RHS, RHSFixedSema);
   case BO_NE:
     return FPBuilder.CreateNE(LHS, LHSFixedSema, RHS, RHSFixedSema);
-  case BO_Shl:
-  case BO_Shr:
   case BO_Cmp:
   case BO_LAnd:
   case BO_LOr:
-  case BO_ShlAssign:
-  case BO_ShrAssign:
     llvm_unreachable("Found unimplemented fixed point binary operation");
   case BO_PtrMemD:
   case BO_PtrMemI:
@@ -3573,8 +3577,12 @@ Value *ScalarExprEmitter::EmitFixedPointBinOp(const BinOpInfo &op) {
     llvm_unreachable("Found unsupported binary operation for fixed point types.");
   }
 
+  bool IsShift = BinaryOperator::isShiftOp(op.Opcode) ||
+                 BinaryOperator::isShiftAssignOp(op.Opcode);
   // Convert to the result type.
-  return FPBuilder.CreateFixedToFixed(Result, CommonFixedSema, ResultFixedSema);
+  return FPBuilder.CreateFixedToFixed(Result, IsShift ? LHSFixedSema
+                                                      : CommonFixedSema,
+                                      ResultFixedSema);
 }
 
 Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
@@ -3701,6 +3709,10 @@ Value *ScalarExprEmitter::ConstrainShiftValue(Value *LHS, Value *RHS,
 }
 
 Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
+  // TODO: This misses out on the sanitizer check below.
+  if (Ops.isFixedPointOp())
+    return EmitFixedPointBinOp(Ops);
+
   // LLVM requires the LHS and RHS to be the same type: promote or truncate the
   // RHS to the same size as the LHS.
   Value *RHS = Ops.RHS;
@@ -3768,6 +3780,10 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
 }
 
 Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
+  // TODO: This misses out on the sanitizer check below.
+  if (Ops.isFixedPointOp())
+    return EmitFixedPointBinOp(Ops);
+
   // LLVM requires the LHS and RHS to be the same type: promote or truncate the
   // RHS to the same size as the LHS.
   Value *RHS = Ops.RHS;

diff  --git a/clang/test/Frontend/fixed_point_compound.c b/clang/test/Frontend/fixed_point_compound.c
index 4a44d0ae95a2..897ba2e22636 100644
--- a/clang/test/Frontend/fixed_point_compound.c
+++ b/clang/test/Frontend/fixed_point_compound.c
@@ -567,3 +567,50 @@ void div_csa() {
   c /= sa;
 }
 
+
+// CHECK-LABEL: @shft_ai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @a, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP1]], [[TMP0]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a, align 4
+// CHECK-NEXT:    ret void
+//
+void shft_ai() {
+  a <<= i;
+}
+
+// SIGNED-LABEL: @shft_sufi(
+// SIGNED-NEXT:  entry:
+// SIGNED-NEXT:    [[TMP0:%.*]] = load i32, i32* @i, align 4
+// SIGNED-NEXT:    [[TMP1:%.*]] = load i16, i16* @suf, align 2
+// SIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP0]] to i16
+// SIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.ushl.sat.i16(i16 [[TMP1]], i16 [[TMP2]])
+// SIGNED-NEXT:    store i16 [[TMP3]], i16* @suf, align 2
+// SIGNED-NEXT:    ret void
+//
+// UNSIGNED-LABEL: @shft_sufi(
+// UNSIGNED-NEXT:  entry:
+// UNSIGNED-NEXT:    [[TMP0:%.*]] = load i32, i32* @i, align 4
+// UNSIGNED-NEXT:    [[TMP1:%.*]] = load i16, i16* @suf, align 2
+// UNSIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP0]] to i16
+// UNSIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.sshl.sat.i16(i16 [[TMP1]], i16 [[TMP2]])
+// UNSIGNED-NEXT:    store i16 [[TMP3]], i16* @suf, align 2
+// UNSIGNED-NEXT:    ret void
+//
+void shft_sufi() {
+  suf <<= i;
+}
+
+// CHECK-LABEL: @shft_ulai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i64, i64* @ula, align 8
+// CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP0]] to i64
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i64 [[TMP1]], [[TMP2]]
+// CHECK-NEXT:    store i64 [[TMP3]], i64* @ula, align 8
+// CHECK-NEXT:    ret void
+//
+void shft_ulai() {
+  ula >>= i;
+}

diff  --git a/clang/test/Frontend/fixed_point_shift.c b/clang/test/Frontend/fixed_point_shift.c
index cbd4f38ab8b0..a3d758798dfa 100644
--- a/clang/test/Frontend/fixed_point_shift.c
+++ b/clang/test/Frontend/fixed_point_shift.c
@@ -1,37 +1,580 @@
-// 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
-
-short _Accum sa_const1 = 1.0hk << 2;       // CHECK-DAG: @sa_const1 = {{.*}}global i16 512
-short _Accum sa_const2 = 0.5hk << 2;       // CHECK-DAG: @sa_const2 = {{.*}}global i16 256
-short _Accum sa_const3 = 10.0hk >> 3;      // CHECK-DAG: @sa_const3 = {{.*}}global i16 160
-short _Accum sa_const4 = 0.0546875hk << 8; // CHECK-DAG: @sa_const4 = {{.*}}global i16 1792
-short _Accum sa_const5 = -1.0hk << 2;      // CHECK-DAG: @sa_const5 = {{.*}}global i16 -512
-short _Accum sa_const6 = -255.0hk >> 8;    // CHECK-DAG: @sa_const6 = {{.*}}global i16 -128
-
-_Fract f_const1 = -1.0r >> 5;              // CHECK-DAG: @f_const1 = {{.*}}global i16 -1024
-_Fract f_const2 = 0.0052490234375r >> 3;   // CHECK-DAG: @f_const2 = {{.*}}global i16 21
-_Fract f_const3 = -0.0001r << 5;           // CHECK-DAG: @f_const3 = {{.*}}global i16 -96
-_Fract f_const4 = -0.75r >> 15;            // CHECK-DAG: @f_const4 = {{.*}}global i16 -1
-_Fract f_const5 = 0.078216552734375r << 3; // CHECK-DAG: @f_const5 = {{.*}}global i16 20504
-
-unsigned _Fract uf_const1 = 0.375ur >> 13;
-// SIGNED-DAG:   @uf_const1 = {{.*}}global i16 3
-// UNSIGNED-DAG: @uf_const1 = {{.*}}global i16 1
-unsigned _Fract uf_const2 = 0.0546875ur << 3;
-// SIGNED-DAG:   @uf_const2 = {{.*}}global i16 28672
-// UNSIGNED-DAG: @uf_const2 = {{.*}}global i16 14336
-
-_Sat short _Accum ssa_const1 = (_Sat short _Accum)31.875hk << 4; // CHECK-DAG: @ssa_const1 = {{.*}}global i16 32767
-_Sat short _Accum ssa_const2 = (_Sat short _Accum) - 1.0hk << 8; // CHECK-DAG: @ssa_const2 = {{.*}}global i16 -32768
-_Sat short _Accum ssa_const3 = (_Sat short _Accum)128.0hk << 8;  // CHECK-DAG: @ssa_const3 = {{.*}}global i16 32767
-_Sat short _Fract ssf_const1 = (_Sat short _Fract) - 0.5hr << 3; // CHECK-DAG: @ssf_const1 = {{.*}}global i8 -128
-
-_Sat unsigned _Fract suf_const1 = (_Sat unsigned _Fract)0.5r << 1;
-// SIGNED-DAG:   @suf_const1 = {{.*}}global i16 -1
-// UNSIGNED-DAG: @suf_const1 = {{.*}}global i16 32767
-_Sat unsigned _Fract suf_const2 = (_Sat unsigned _Fract)0.25r << 1;
-// SIGNED-DAG:   @suf_const2 = {{.*}}global i16 -32768
-// UNSIGNED-DAG: @suf_const2 = {{.*}}global i16 16384
-_Sat unsigned _Accum sua_const2 = (_Sat unsigned _Accum)128.0uk << 10;
-// SIGNED-DAG:   @sua_const2 = {{.*}}global i32 -1
-// UNSIGNED-DAG: @sua_const2 = {{.*}}global i32 2147483647
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
+short _Accum sa;
+_Accum a;
+long _Accum la;
+
+short _Fract sf;
+_Fract f;
+long _Fract lf;
+
+unsigned short _Accum usa;
+unsigned _Accum ua;
+unsigned long _Accum ula;
+
+unsigned short _Fract usf;
+unsigned _Fract uf;
+unsigned long _Fract ulf;
+
+_Sat short _Accum sa_sat;
+_Sat _Accum a_sat;
+
+_Sat short _Fract sf_sat;
+_Sat _Fract f_sat;
+
+_Sat unsigned short _Accum usa_sat;
+_Sat unsigned _Accum ua_sat;
+
+_Sat unsigned short _Fract usf_sat;
+_Sat unsigned _Fract uf_sat;
+
+int i;
+unsigned u;
+
+
+// CHECK-LABEL: @sleft_sasai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @sa, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @sa, align 2
+// CHECK-NEXT:    ret void
+//
+void sleft_sasai() {
+  sa = sa << i;
+}
+
+// CHECK-LABEL: @sleft_aai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a, align 4
+// CHECK-NEXT:    ret void
+//
+void sleft_aai() {
+  a = a << i;
+}
+
+// CHECK-LABEL: @sleft_lalai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* @la, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i64 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i64 [[TMP3]], i64* @la, align 8
+// CHECK-NEXT:    ret void
+//
+void sleft_lalai() {
+  la = la << i;
+}
+
+// CHECK-LABEL: @sleft_sfsfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* @sf, align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i8 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i8 [[TMP3]], i8* @sf, align 1
+// CHECK-NEXT:    ret void
+//
+void sleft_sfsfi() {
+  sf = sf << i;
+}
+
+// CHECK-LABEL: @sleft_ffi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @f, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @f, align 2
+// CHECK-NEXT:    ret void
+//
+void sleft_ffi() {
+  f = f << i;
+}
+
+// CHECK-LABEL: @sleft_lflfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @lf, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @lf, align 4
+// CHECK-NEXT:    ret void
+//
+void sleft_lflfi() {
+  lf = lf << i;
+}
+
+// CHECK-LABEL: @sleft_aau(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a, align 4
+// CHECK-NEXT:    ret void
+//
+void sleft_aau() {
+  a = a << u;
+}
+
+// CHECK-LABEL: @sleft_ffu(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @f, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @f, align 2
+// CHECK-NEXT:    ret void
+//
+void sleft_ffu() {
+  f = f << u;
+}
+
+
+// CHECK-LABEL: @uleft_usausai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @usa, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @usa, align 2
+// CHECK-NEXT:    ret void
+//
+void uleft_usausai() {
+  usa = usa << i;
+}
+
+// CHECK-LABEL: @uleft_uauai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ua, align 4
+// CHECK-NEXT:    ret void
+//
+void uleft_uauai() {
+  ua = ua << i;
+}
+
+// CHECK-LABEL: @uleft_ulaulai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* @ula, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i64 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i64 [[TMP3]], i64* @ula, align 8
+// CHECK-NEXT:    ret void
+//
+void uleft_ulaulai() {
+  ula = ula << i;
+}
+
+// CHECK-LABEL: @uleft_usfusfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* @usf, align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i8 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i8 [[TMP3]], i8* @usf, align 1
+// CHECK-NEXT:    ret void
+//
+void uleft_usfusfi() {
+  usf = usf << i;
+}
+
+// CHECK-LABEL: @uleft_ufufi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @uf, align 2
+// CHECK-NEXT:    ret void
+//
+void uleft_ufufi() {
+  uf = uf << i;
+}
+
+// CHECK-LABEL: @uleft_ulfulfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ulf, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ulf, align 4
+// CHECK-NEXT:    ret void
+//
+void uleft_ulfulfi() {
+  ulf = ulf << i;
+}
+
+// CHECK-LABEL: @uleft_uauau(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = shl i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ua, align 4
+// CHECK-NEXT:    ret void
+//
+void uleft_uauau() {
+  ua = ua << u;
+}
+
+// CHECK-LABEL: @uleft_ufufu(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = shl i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @uf, align 2
+// CHECK-NEXT:    ret void
+//
+void uleft_ufufu() {
+  uf = uf << u;
+}
+
+
+// CHECK-LABEL: @sright_sasai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @sa, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = ashr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @sa, align 2
+// CHECK-NEXT:    ret void
+//
+void sright_sasai() {
+  sa = sa >> i;
+}
+
+// CHECK-LABEL: @sright_aai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = ashr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a, align 4
+// CHECK-NEXT:    ret void
+//
+void sright_aai() {
+  a = a >> i;
+}
+
+// CHECK-LABEL: @sright_lalai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* @la, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// CHECK-NEXT:    [[TMP3:%.*]] = ashr i64 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i64 [[TMP3]], i64* @la, align 8
+// CHECK-NEXT:    ret void
+//
+void sright_lalai() {
+  la = la >> i;
+}
+
+// CHECK-LABEL: @sright_sfsfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* @sf, align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// CHECK-NEXT:    [[TMP3:%.*]] = ashr i8 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i8 [[TMP3]], i8* @sf, align 1
+// CHECK-NEXT:    ret void
+//
+void sright_sfsfi() {
+  sf = sf >> i;
+}
+
+// CHECK-LABEL: @sright_ffi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @f, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = ashr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @f, align 2
+// CHECK-NEXT:    ret void
+//
+void sright_ffi() {
+  f = f >> i;
+}
+
+// CHECK-LABEL: @sright_lflfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @lf, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = ashr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @lf, align 4
+// CHECK-NEXT:    ret void
+//
+void sright_lflfi() {
+  lf = lf >> i;
+}
+
+// CHECK-LABEL: @sright_aau(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = ashr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a, align 4
+// CHECK-NEXT:    ret void
+//
+void sright_aau() {
+  a = a >> u;
+}
+
+// CHECK-LABEL: @sright_ffu(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @f, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = ashr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @f, align 2
+// CHECK-NEXT:    ret void
+//
+void sright_ffu() {
+  f = f >> u;
+}
+
+
+// CHECK-LABEL: @uright_usausai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @usa, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @usa, align 2
+// CHECK-NEXT:    ret void
+//
+void uright_usausai() {
+  usa = usa >> i;
+}
+
+// CHECK-LABEL: @uright_uauai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ua, align 4
+// CHECK-NEXT:    ret void
+//
+void uright_uauai() {
+  ua = ua >> i;
+}
+
+// CHECK-LABEL: @uright_ulaulai(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, i64* @ula, align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i64 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i64 [[TMP3]], i64* @ula, align 8
+// CHECK-NEXT:    ret void
+//
+void uright_ulaulai() {
+  ula = ula >> i;
+}
+
+// CHECK-LABEL: @uright_usfusfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* @usf, align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i8 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i8 [[TMP3]], i8* @usf, align 1
+// CHECK-NEXT:    ret void
+//
+void uright_usfusfi() {
+  usf = usf >> i;
+}
+
+// CHECK-LABEL: @uright_ufufi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @uf, align 2
+// CHECK-NEXT:    ret void
+//
+void uright_ufufi() {
+  uf = uf >> i;
+}
+
+// CHECK-LABEL: @uright_ulfulfi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ulf, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ulf, align 4
+// CHECK-NEXT:    ret void
+//
+void uright_ulfulfi() {
+  ulf = ulf >> i;
+}
+
+// CHECK-LABEL: @uright_uauau(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @ua, align 4
+// CHECK-NEXT:    ret void
+//
+void uright_uauau() {
+  ua = ua >> u;
+}
+
+// CHECK-LABEL: @uright_ufufu(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @u, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = lshr i16 [[TMP0]], [[TMP2]]
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @uf, align 2
+// CHECK-NEXT:    ret void
+//
+void uright_ufufu() {
+  uf = uf >> u;
+}
+
+
+// CHECK-LABEL: @satleft_sassasi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @sa_sat, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = call i16 @llvm.sshl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @sa_sat, align 2
+// CHECK-NEXT:    ret void
+//
+void satleft_sassasi() {
+  sa_sat = sa_sat << i;
+}
+
+// CHECK-LABEL: @satleft_asasi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @a_sat, align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT:    store i32 [[TMP2]], i32* @a_sat, align 4
+// CHECK-NEXT:    ret void
+//
+void satleft_asasi() {
+  a_sat = a_sat << i;
+}
+
+// CHECK-LABEL: @satleft_sfssfsi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* @sf_sat, align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// CHECK-NEXT:    [[TMP3:%.*]] = call i8 @llvm.sshl.sat.i8(i8 [[TMP0]], i8 [[TMP2]])
+// CHECK-NEXT:    store i8 [[TMP3]], i8* @sf_sat, align 1
+// CHECK-NEXT:    ret void
+//
+void satleft_sfssfsi() {
+  sf_sat = sf_sat << i;
+}
+
+// CHECK-LABEL: @satleft_fsfsi(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @f_sat, align 2
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// CHECK-NEXT:    [[TMP3:%.*]] = call i16 @llvm.sshl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// CHECK-NEXT:    store i16 [[TMP3]], i16* @f_sat, align 2
+// CHECK-NEXT:    ret void
+//
+void satleft_fsfsi() {
+  f_sat = f_sat << i;
+}
+
+// SIGNED-LABEL: @satleft_usasusasi(
+// SIGNED-NEXT:  entry:
+// SIGNED-NEXT:    [[TMP0:%.*]] = load i16, i16* @usa_sat, align 2
+// SIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// SIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// SIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.ushl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// SIGNED-NEXT:    store i16 [[TMP3]], i16* @usa_sat, align 2
+// SIGNED-NEXT:    ret void
+//
+// UNSIGNED-LABEL: @satleft_usasusasi(
+// UNSIGNED-NEXT:  entry:
+// UNSIGNED-NEXT:    [[TMP0:%.*]] = load i16, i16* @usa_sat, align 2
+// UNSIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// UNSIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// UNSIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.sshl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// UNSIGNED-NEXT:    store i16 [[TMP3]], i16* @usa_sat, align 2
+// UNSIGNED-NEXT:    ret void
+//
+void satleft_usasusasi() {
+  usa_sat = usa_sat << i;
+}
+
+// SIGNED-LABEL: @satleft_uasuasi(
+// SIGNED-NEXT:  entry:
+// SIGNED-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua_sat, align 4
+// SIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// SIGNED-NEXT:    [[TMP2:%.*]] = call i32 @llvm.ushl.sat.i32(i32 [[TMP0]], i32 [[TMP1]])
+// SIGNED-NEXT:    store i32 [[TMP2]], i32* @ua_sat, align 4
+// SIGNED-NEXT:    ret void
+//
+// UNSIGNED-LABEL: @satleft_uasuasi(
+// UNSIGNED-NEXT:  entry:
+// UNSIGNED-NEXT:    [[TMP0:%.*]] = load i32, i32* @ua_sat, align 4
+// UNSIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// UNSIGNED-NEXT:    [[TMP2:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[TMP0]], i32 [[TMP1]])
+// UNSIGNED-NEXT:    store i32 [[TMP2]], i32* @ua_sat, align 4
+// UNSIGNED-NEXT:    ret void
+//
+void satleft_uasuasi() {
+  ua_sat = ua_sat << i;
+}
+
+// SIGNED-LABEL: @satleft_usfsusfsi(
+// SIGNED-NEXT:  entry:
+// SIGNED-NEXT:    [[TMP0:%.*]] = load i8, i8* @usf_sat, align 1
+// SIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// SIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// SIGNED-NEXT:    [[TMP3:%.*]] = call i8 @llvm.ushl.sat.i8(i8 [[TMP0]], i8 [[TMP2]])
+// SIGNED-NEXT:    store i8 [[TMP3]], i8* @usf_sat, align 1
+// SIGNED-NEXT:    ret void
+//
+// UNSIGNED-LABEL: @satleft_usfsusfsi(
+// UNSIGNED-NEXT:  entry:
+// UNSIGNED-NEXT:    [[TMP0:%.*]] = load i8, i8* @usf_sat, align 1
+// UNSIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// UNSIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
+// UNSIGNED-NEXT:    [[TMP3:%.*]] = call i8 @llvm.sshl.sat.i8(i8 [[TMP0]], i8 [[TMP2]])
+// UNSIGNED-NEXT:    store i8 [[TMP3]], i8* @usf_sat, align 1
+// UNSIGNED-NEXT:    ret void
+//
+void satleft_usfsusfsi() {
+  usf_sat = usf_sat << i;
+}
+
+// SIGNED-LABEL: @satleft_ufsufsi(
+// SIGNED-NEXT:  entry:
+// SIGNED-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2
+// SIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// SIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// SIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.ushl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// SIGNED-NEXT:    store i16 [[TMP3]], i16* @uf_sat, align 2
+// SIGNED-NEXT:    ret void
+//
+// UNSIGNED-LABEL: @satleft_ufsufsi(
+// UNSIGNED-NEXT:  entry:
+// UNSIGNED-NEXT:    [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2
+// UNSIGNED-NEXT:    [[TMP1:%.*]] = load i32, i32* @i, align 4
+// UNSIGNED-NEXT:    [[TMP2:%.*]] = trunc i32 [[TMP1]] to i16
+// UNSIGNED-NEXT:    [[TMP3:%.*]] = call i16 @llvm.sshl.sat.i16(i16 [[TMP0]], i16 [[TMP2]])
+// UNSIGNED-NEXT:    store i16 [[TMP3]], i16* @uf_sat, align 2
+// UNSIGNED-NEXT:    ret void
+//
+void satleft_ufsufsi() {
+  uf_sat = uf_sat << i;
+}

diff  --git a/clang/test/Frontend/fixed_point_shift_const.c b/clang/test/Frontend/fixed_point_shift_const.c
new file mode 100644
index 000000000000..10860efd188b
--- /dev/null
+++ b/clang/test/Frontend/fixed_point_shift_const.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
+short _Accum sa_const1 = 1.0hk << 2;
+// CHECK-DAG: @sa_const1 = {{.*}}global i16 512
+short _Accum sa_const2 = 0.5hk << 2;
+// CHECK-DAG: @sa_const2 = {{.*}}global i16 256
+short _Accum sa_const3 = 10.0hk >> 3;
+// CHECK-DAG: @sa_const3 = {{.*}}global i16 160
+short _Accum sa_const4 = 0.0546875hk << 8;
+// CHECK-DAG: @sa_const4 = {{.*}}global i16 1792
+short _Accum sa_const5 = -1.0hk << 2;
+// CHECK-DAG: @sa_const5 = {{.*}}global i16 -512
+short _Accum sa_const6 = -255.0hk >> 8;
+// CHECK-DAG: @sa_const6 = {{.*}}global i16 -128
+
+_Fract f_const1 = -1.0r >> 5;
+// CHECK-DAG: @f_const1 = {{.*}}global i16 -1024
+_Fract f_const2 = 0.0052490234375r >> 3;
+// CHECK-DAG: @f_const2 = {{.*}}global i16 21
+_Fract f_const3 = -0.0001r << 5;
+// CHECK-DAG: @f_const3 = {{.*}}global i16 -96
+_Fract f_const4 = -0.75r >> 15;
+// CHECK-DAG: @f_const4 = {{.*}}global i16 -1
+_Fract f_const5 = 0.078216552734375r << 3;
+// CHECK-DAG: @f_const5 = {{.*}}global i16 20504
+
+unsigned _Fract uf_const1 = 0.375ur >> 13;
+// SIGNED-DAG:   @uf_const1 = {{.*}}global i16 3
+// UNSIGNED-DAG: @uf_const1 = {{.*}}global i16 1
+unsigned _Fract uf_const2 = 0.0546875ur << 3;
+// SIGNED-DAG:   @uf_const2 = {{.*}}global i16 28672
+// UNSIGNED-DAG: @uf_const2 = {{.*}}global i16 14336
+
+_Sat short _Accum ssa_const1 = (_Sat short _Accum)31.875hk << 4;
+// CHECK-DAG: @ssa_const1 = {{.*}}global i16 32767
+_Sat short _Accum ssa_const2 = (_Sat short _Accum) - 1.0hk << 8;
+// CHECK-DAG: @ssa_const2 = {{.*}}global i16 -32768
+_Sat short _Accum ssa_const3 = (_Sat short _Accum)128.0hk << 8;
+// CHECK-DAG: @ssa_const3 = {{.*}}global i16 32767
+_Sat short _Fract ssf_const1 = (_Sat short _Fract) - 0.5hr << 3;
+// CHECK-DAG: @ssf_const1 = {{.*}}global i8 -128
+
+_Sat unsigned _Fract suf_const1 = (_Sat unsigned _Fract)0.5r << 1;
+// SIGNED-DAG:   @suf_const1 = {{.*}}global i16 -1
+// UNSIGNED-DAG: @suf_const1 = {{.*}}global i16 32767
+_Sat unsigned _Fract suf_const2 = (_Sat unsigned _Fract)0.25r << 1;
+// SIGNED-DAG:   @suf_const2 = {{.*}}global i16 -32768
+// UNSIGNED-DAG: @suf_const2 = {{.*}}global i16 16384
+_Sat unsigned _Accum sua_const2 = (_Sat unsigned _Accum)128.0uk << 10;
+// SIGNED-DAG:   @sua_const2 = {{.*}}global i32 -1
+// UNSIGNED-DAG: @sua_const2 = {{.*}}global i32 2147483647


        


More information about the cfe-commits mailing list