[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