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 @@ -1219,13 +1219,14 @@ // padding is enabled because overflow into this bit is undefined // behavior. return Builder.CreateIsNotNull(Src, "tobool"); - if (DstType->isFixedPointType() || DstType->isIntegerType()) + if (DstType->isFixedPointType() || DstType->isIntegerType() || + DstType->isRealFloatingType()) return EmitFixedPointConversion(Src, SrcType, DstType, Loc); llvm_unreachable( "Unhandled scalar conversion from a fixed point type to another type."); } else if (DstType->isFixedPointType()) { - if (SrcType->isIntegerType()) + if (SrcType->isIntegerType() || SrcType->isRealFloatingType()) // This also includes converting booleans and enums to fixed point types. return EmitFixedPointConversion(Src, SrcType, DstType, Loc); @@ -1441,19 +1442,29 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy, SourceLocation Loc) { - auto SrcFPSema = CGF.getContext().getFixedPointSemantics(SrcTy); - auto DstFPSema = CGF.getContext().getFixedPointSemantics(DstTy); llvm::FixedPointBuilder FPBuilder(Builder); llvm::Value *Result; - if (DstTy->isIntegerType()) - Result = FPBuilder.CreateFixedToInteger(Src, SrcFPSema, - DstFPSema.getWidth(), - DstFPSema.isSigned()); - else if (SrcTy->isIntegerType()) - Result = FPBuilder.CreateIntegerToFixed(Src, SrcFPSema.isSigned(), - DstFPSema); - else - Result = FPBuilder.CreateFixedToFixed(Src, SrcFPSema, DstFPSema); + if (SrcTy->isRealFloatingType()) + Result = FPBuilder.CreateFloatingToFixed(Src, + CGF.getContext().getFixedPointSemantics(DstTy)); + else if (DstTy->isRealFloatingType()) + Result = FPBuilder.CreateFixedToFloating(Src, + CGF.getContext().getFixedPointSemantics(SrcTy), + ConvertType(DstTy)); + else { + auto SrcFPSema = CGF.getContext().getFixedPointSemantics(SrcTy); + auto DstFPSema = CGF.getContext().getFixedPointSemantics(DstTy); + + if (DstTy->isIntegerType()) + Result = FPBuilder.CreateFixedToInteger(Src, SrcFPSema, + DstFPSema.getWidth(), + DstFPSema.isSigned()); + else if (SrcTy->isIntegerType()) + Result = FPBuilder.CreateIntegerToFixed(Src, SrcFPSema.isSigned(), + DstFPSema); + else + Result = FPBuilder.CreateFixedToFixed(Src, SrcFPSema, DstFPSema); + } return Result; } 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 @@ -16,6 +16,8 @@ unsigned int u; signed char c; +float fl; + // CHECK-LABEL: @add_shfa( // CHECK-NEXT: entry: @@ -358,6 +360,66 @@ sshf += suf; } +// CHECK-LABEL: @add_afl( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float +// CHECK-NEXT: [[TMP3:%.*]] = fmul float [[TMP2]], 0x3F00000000000000 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP3]], [[TMP0]] +// CHECK-NEXT: [[TMP4:%.*]] = fmul float [[ADD]], 3.276800e+04 +// CHECK-NEXT: [[TMP5:%.*]] = fptosi float [[TMP4]] to i32 +// CHECK-NEXT: store i32 [[TMP5]], i32* @a, align 4 +// CHECK-NEXT: ret void +// +void add_afl() { + a += fl; +} + +// CHECK-LABEL: @add_fla( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @sa, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i32 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3F00000000000000 +// CHECK-NEXT: [[TMP3:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP3]], [[TMP2]] +// CHECK-NEXT: store float [[ADD]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void add_fla() { + fl += sa; +} + +// CHECK-LABEL: @add_safl( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @sa, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float +// CHECK-NEXT: [[TMP3:%.*]] = fmul float [[TMP2]], 0x3F00000000000000 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP3]], [[TMP0]] +// CHECK-NEXT: [[TMP4:%.*]] = fmul float [[ADD]], 3.276800e+04 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.fptosi.sat.i32.f32(float [[TMP4]]) +// CHECK-NEXT: store i32 [[TMP5]], i32* @sa, align 4 +// CHECK-NEXT: ret void +// +void add_safl() { + sa += fl; +} + +// CHECK-LABEL: @add_flsa( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @sa, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i32 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3F00000000000000 +// CHECK-NEXT: [[TMP3:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP3]], [[TMP2]] +// CHECK-NEXT: store float [[ADD]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void add_flsa() { + fl += sa; +} + // Subtraction, multiplication and division should work about the same, so // just make sure we can do them. @@ -429,6 +491,22 @@ c -= sa; } +// CHECK-LABEL: @sub_afl( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float +// CHECK-NEXT: [[TMP3:%.*]] = fmul float [[TMP2]], 0x3F00000000000000 +// CHECK-NEXT: [[SUB:%.*]] = fsub float [[TMP3]], [[TMP0]] +// CHECK-NEXT: [[TMP4:%.*]] = fmul float [[SUB]], 3.276800e+04 +// CHECK-NEXT: [[TMP5:%.*]] = fptosi float [[TMP4]] to i32 +// CHECK-NEXT: store i32 [[TMP5]], i32* @a, align 4 +// CHECK-NEXT: ret void +// +void sub_afl() { + a -= fl; +} + // SIGNED-LABEL: @mul_auf( // SIGNED-NEXT: entry: @@ -498,6 +576,22 @@ c *= sa; } +// CHECK-LABEL: @mul_afl( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float +// CHECK-NEXT: [[TMP3:%.*]] = fmul float [[TMP2]], 0x3F00000000000000 +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP3]], [[TMP0]] +// CHECK-NEXT: [[TMP4:%.*]] = fmul float [[MUL]], 3.276800e+04 +// CHECK-NEXT: [[TMP5:%.*]] = fptosi float [[TMP4]] to i32 +// CHECK-NEXT: store i32 [[TMP5]], i32* @a, align 4 +// CHECK-NEXT: ret void +// +void mul_afl() { + a *= fl; +} + // SIGNED-LABEL: @div_auf( // SIGNED-NEXT: entry: @@ -567,6 +661,22 @@ c /= sa; } +// CHECK-LABEL: @div_afl( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP2:%.*]] = sitofp i32 [[TMP1]] to float +// CHECK-NEXT: [[TMP3:%.*]] = fmul float [[TMP2]], 0x3F00000000000000 +// CHECK-NEXT: [[DIV:%.*]] = fdiv float [[TMP3]], [[TMP0]] +// CHECK-NEXT: [[TMP4:%.*]] = fmul float [[DIV]], 3.276800e+04 +// CHECK-NEXT: [[TMP5:%.*]] = fptosi float [[TMP4]] to i32 +// CHECK-NEXT: store i32 [[TMP5]], i32* @a, align 4 +// CHECK-NEXT: ret void +// +void div_afl() { + a /= fl; +} + // CHECK-LABEL: @shft_ai( // CHECK-NEXT: entry: diff --git a/clang/test/Frontend/fixed_point_conversions.c b/clang/test/Frontend/fixed_point_conversions.c --- a/clang/test/Frontend/fixed_point_conversions.c +++ b/clang/test/Frontend/fixed_point_conversions.c @@ -26,11 +26,15 @@ _Sat short _Fract sat_sf; _Sat _Fract sat_f; _Sat long _Fract sat_lf; +_Sat unsigned _Fract sat_uf; short s; int i; unsigned int ui; +float fl; +double d; + // CHECK-LABEL: @fix_same1( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 @@ -695,3 +699,298 @@ void int_sat4() { sat_usa = ui; } + + +// CHECK-LABEL: @float_fix1( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 1.280000e+02 +// CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i16 +// CHECK-NEXT: store i16 [[TMP2]], i16* @sa, align 2 +// CHECK-NEXT: ret void +// +void float_fix1() { + sa = fl; +} + +// CHECK-LABEL: @float_fix2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i32 +// CHECK-NEXT: store i32 [[TMP2]], i32* @a, align 4 +// CHECK-NEXT: ret void +// +void float_fix2() { + a = fl; +} + +// CHECK-LABEL: @float_fix3( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 0x41E0000000000000 +// CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i64 +// CHECK-NEXT: store i64 [[TMP2]], i64* @la, align 8 +// CHECK-NEXT: ret void +// +void float_fix3() { + la = fl; +} + +// CHECK-LABEL: @float_fix4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 1.280000e+02 +// CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i8 +// CHECK-NEXT: store i8 [[TMP2]], i8* @sf, align 1 +// CHECK-NEXT: ret void +// +void float_fix4() { + sf = fl; +} + +// CHECK-LABEL: @float_fix5( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 0x41E0000000000000 +// CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i32 +// CHECK-NEXT: store i32 [[TMP2]], i32* @lf, align 4 +// CHECK-NEXT: ret void +// +void float_fix5() { + lf = fl; +} + +// SIGNED-LABEL: @float_fix6( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// SIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 6.553600e+04 +// SIGNED-NEXT: [[TMP2:%.*]] = fptoui float [[TMP1]] to i32 +// SIGNED-NEXT: store i32 [[TMP2]], i32* @ua, align 4 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @float_fix6( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// UNSIGNED-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i32 +// UNSIGNED-NEXT: store i32 [[TMP2]], i32* @ua, align 4 +// UNSIGNED-NEXT: ret void +// +void float_fix6() { + ua = fl; +} + +// SIGNED-LABEL: @float_fix7( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// SIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 6.553600e+04 +// SIGNED-NEXT: [[TMP2:%.*]] = fptoui float [[TMP1]] to i16 +// SIGNED-NEXT: store i16 [[TMP2]], i16* @uf, align 2 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @float_fix7( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// UNSIGNED-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i16 +// UNSIGNED-NEXT: store i16 [[TMP2]], i16* @uf, align 2 +// UNSIGNED-NEXT: ret void +// +void float_fix7() { + uf = fl; +} + + +// CHECK-LABEL: @fix_float1( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* @sa, align 2 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i16 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 7.812500e-03 +// CHECK-NEXT: store float [[TMP2]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void fix_float1() { + fl = sa; +} + +// CHECK-LABEL: @fix_float2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i32 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3F00000000000000 +// CHECK-NEXT: store float [[TMP2]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void fix_float2() { + fl = a; +} + +// CHECK-LABEL: @fix_float3( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* @la, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i64 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3E00000000000000 +// CHECK-NEXT: store float [[TMP2]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void fix_float3() { + fl = la; +} + +// CHECK-LABEL: @fix_float4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* @sf, align 1 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i8 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 7.812500e-03 +// CHECK-NEXT: store float [[TMP2]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void fix_float4() { + fl = sf; +} + +// CHECK-LABEL: @fix_float5( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @lf, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = sitofp i32 [[TMP0]] to float +// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3E00000000000000 +// CHECK-NEXT: store float [[TMP2]], float* @fl, align 4 +// CHECK-NEXT: ret void +// +void fix_float5() { + fl = lf; +} + +// SIGNED-LABEL: @fix_float6( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 +// SIGNED-NEXT: [[TMP1:%.*]] = uitofp i32 [[TMP0]] to float +// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3EF0000000000000 +// SIGNED-NEXT: store float [[TMP2]], float* @fl, align 4 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @fix_float6( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 +// UNSIGNED-NEXT: [[TMP1:%.*]] = uitofp i32 [[TMP0]] to float +// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3F00000000000000 +// UNSIGNED-NEXT: store float [[TMP2]], float* @fl, align 4 +// UNSIGNED-NEXT: ret void +// +void fix_float6() { + fl = ua; +} + +// SIGNED-LABEL: @fix_float7( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf, align 2 +// SIGNED-NEXT: [[TMP1:%.*]] = uitofp i16 [[TMP0]] to float +// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3EF0000000000000 +// SIGNED-NEXT: store float [[TMP2]], float* @fl, align 4 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @fix_float7( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf, align 2 +// UNSIGNED-NEXT: [[TMP1:%.*]] = uitofp i16 [[TMP0]] to float +// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3F00000000000000 +// UNSIGNED-NEXT: store float [[TMP2]], float* @fl, align 4 +// UNSIGNED-NEXT: ret void +// +void fix_float7() { + fl = uf; +} + + +// CHECK-LABEL: @float_sat1( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 1.280000e+02 +// CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.fptosi.sat.i16.f32(float [[TMP1]]) +// CHECK-NEXT: store i16 [[TMP2]], i16* @sat_sa, align 2 +// CHECK-NEXT: ret void +// +void float_sat1() { + sat_sa = fl; +} + +// CHECK-LABEL: @float_sat2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.fptosi.sat.i32.f32(float [[TMP1]]) +// CHECK-NEXT: store i32 [[TMP2]], i32* @sat_a, align 4 +// CHECK-NEXT: ret void +// +void float_sat2() { + sat_a = fl; +} + +// CHECK-LABEL: @float_sat3( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 0x41E0000000000000 +// CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.fptosi.sat.i64.f32(float [[TMP1]]) +// CHECK-NEXT: store i64 [[TMP2]], i64* @sat_la, align 8 +// CHECK-NEXT: ret void +// +void float_sat3() { + sat_la = fl; +} + +// CHECK-LABEL: @float_sat4( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 1.280000e+02 +// CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.fptosi.sat.i8.f32(float [[TMP1]]) +// CHECK-NEXT: store i8 [[TMP2]], i8* @sat_sf, align 1 +// CHECK-NEXT: ret void +// +void float_sat4() { + sat_sf = fl; +} + +// SIGNED-LABEL: @float_sat5( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// SIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 6.553600e+04 +// SIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.fptoui.sat.i32.f32(float [[TMP1]]) +// SIGNED-NEXT: store i32 [[TMP2]], i32* @sat_ua, align 4 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @float_sat5( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.fptosi.sat.i32.f32(float [[TMP1]]) +// UNSIGNED-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP3]], i32 0, i32 [[TMP2]] +// UNSIGNED-NEXT: store i32 [[SATMIN]], i32* @sat_ua, align 4 +// UNSIGNED-NEXT: ret void +// +void float_sat5() { + sat_ua = fl; +} + +// SIGNED-LABEL: @float_sat6( +// SIGNED-NEXT: entry: +// SIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// SIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 6.553600e+04 +// SIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.fptoui.sat.i16.f32(float [[TMP1]]) +// SIGNED-NEXT: store i16 [[TMP2]], i16* @sat_uf, align 2 +// SIGNED-NEXT: ret void +// +// UNSIGNED-LABEL: @float_sat6( +// UNSIGNED-NEXT: entry: +// UNSIGNED-NEXT: [[TMP0:%.*]] = load float, float* @fl, align 4 +// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], 3.276800e+04 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.fptosi.sat.i16.f32(float [[TMP1]]) +// UNSIGNED-NEXT: [[TMP3:%.*]] = icmp slt i16 [[TMP2]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP3]], i16 0, i16 [[TMP2]] +// UNSIGNED-NEXT: store i16 [[SATMIN]], i16* @sat_uf, align 2 +// UNSIGNED-NEXT: ret void +// +void float_sat6() { + sat_uf = fl; +} diff --git a/llvm/include/llvm/IR/FixedPointBuilder.h b/llvm/include/llvm/IR/FixedPointBuilder.h --- a/llvm/include/llvm/IR/FixedPointBuilder.h +++ b/llvm/include/llvm/IR/FixedPointBuilder.h @@ -159,6 +159,48 @@ DstSema, false); } + Value *CreateFixedToFloating(Value *Src, const FixedPointSemantics &SrcSema, + Type *DstTy) { + Value *Result; + // Convert the raw fixed-point value directly to floating point. If the + // value is too large to fit, it will be rounded, not truncated. + Result = SrcSema.isSigned() ? B.CreateSIToFP(Src, DstTy) + : B.CreateUIToFP(Src, DstTy); + // Rescale the integral-in-floating point by the scaling factor. This is + // lossless, except for overflow to infinity which is unlikely. + return B.CreateFMul(Result, + ConstantFP::get(DstTy, std::pow(2, -(int)SrcSema.getScale()))); + } + + Value *CreateFloatingToFixed(Value *Src, const FixedPointSemantics &DstSema) { + bool UseSigned = DstSema.isSigned() || DstSema.hasUnsignedPadding(); + Value *Result; + // Rescale the floating point value so that its significant bits (for the + // purposes of the conversion) are in the integral range. + Result = B.CreateFMul(Src, + ConstantFP::get(Src->getType(), std::pow(2, DstSema.getScale()))); + + Type *ResultTy = B.getIntNTy(DstSema.getWidth()); + if (DstSema.isSaturated()) { + Intrinsic::ID IID = + UseSigned ? Intrinsic::fptosi_sat : Intrinsic::fptoui_sat; + Result = B.CreateIntrinsic(IID, {ResultTy, Src->getType()}, {Result}); + } else { + Result = UseSigned ? B.CreateFPToSI(Result, ResultTy) + : B.CreateFPToUI(Result, ResultTy); + } + + // When saturating unsigned-with-padding using signed operations, we may + // get negative values. Emit an extra clamp to zero. + if (DstSema.isSaturated() && DstSema.hasUnsignedPadding()) { + Constant *Zero = Constant::getNullValue(Result->getType()); + Result = + B.CreateSelect(B.CreateICmpSLT(Result, Zero), Zero, Result, "satmin"); + } + + return Result; + } + /// Add two fixed-point values and return the result in their common semantic. /// \p LHS - The left hand side /// \p LHSSema - The semantic of the left hand side