diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3535,6 +3535,14 @@ 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 @@ 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 @@ 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::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::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 --- a/clang/test/Frontend/fixed_point_compound.c +++ b/clang/test/Frontend/fixed_point_compound.c @@ -567,3 +567,50 @@ 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 --- 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 --- /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