// 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);
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<CGBuilderTy> 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;
}
unsigned int u;
signed char c;
+float fl;
+
// CHECK-LABEL: @add_shfa(
// CHECK-NEXT: entry:
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* @a, 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 += a;
+}
+
+// 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.
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:
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:
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:
_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
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;
+}
--- /dev/null
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -ffixed-point -triple arm64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -triple arm64-unknown-linux-gnu -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
+short _Fract sf;
+long _Fract lf;
+
+short _Accum sa;
+long _Accum la;
+
+unsigned short _Accum usa;
+unsigned long _Accum ula;
+
+_Sat short _Fract sf_sat;
+_Sat long _Fract lf_sat;
+
+_Sat short _Accum sa_sat;
+_Sat long _Accum la_sat;
+
+_Sat unsigned short _Accum usa_sat;
+_Sat unsigned long _Accum ula_sat;
+
+_Float16 h;
+
+
+// CHECK-LABEL: @half_fix1(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// CHECK-NEXT: [[TMP2:%.*]] = fptosi half [[TMP1]] to i8
+// CHECK-NEXT: store i8 [[TMP2]], i8* @sf, align 1
+// CHECK-NEXT: ret void
+//
+void half_fix1() {
+ sf = h;
+}
+
+// CHECK-LABEL: @half_fix2(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// CHECK-NEXT: [[TMP3:%.*]] = fptosi float [[TMP2]] to i32
+// CHECK-NEXT: store i32 [[TMP3]], i32* @lf, align 4
+// CHECK-NEXT: ret void
+//
+void half_fix2() {
+ lf = h;
+}
+
+// CHECK-LABEL: @half_fix3(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// CHECK-NEXT: [[TMP2:%.*]] = fptosi half [[TMP1]] to i16
+// CHECK-NEXT: store i16 [[TMP2]], i16* @sa, align 2
+// CHECK-NEXT: ret void
+//
+void half_fix3() {
+ sa = h;
+}
+
+// CHECK-LABEL: @half_fix4(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// CHECK-NEXT: [[TMP3:%.*]] = fptosi float [[TMP2]] to i64
+// CHECK-NEXT: store i64 [[TMP3]], i64* @la, align 8
+// CHECK-NEXT: ret void
+//
+void half_fix4() {
+ la = h;
+}
+
+// SIGNED-LABEL: @half_fix5(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// SIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 2.560000e+02
+// SIGNED-NEXT: [[TMP3:%.*]] = fptoui float [[TMP2]] to i16
+// SIGNED-NEXT: store i16 [[TMP3]], i16* @usa, align 2
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @half_fix5(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// UNSIGNED-NEXT: [[TMP2:%.*]] = fptosi half [[TMP1]] to i16
+// UNSIGNED-NEXT: store i16 [[TMP2]], i16* @usa, align 2
+// UNSIGNED-NEXT: ret void
+//
+void half_fix5() {
+ usa = h;
+}
+
+// SIGNED-LABEL: @half_fix6(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// SIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41F0000000000000
+// SIGNED-NEXT: [[TMP3:%.*]] = fptoui float [[TMP2]] to i64
+// SIGNED-NEXT: store i64 [[TMP3]], i64* @ula, align 8
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @half_fix6(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// UNSIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// UNSIGNED-NEXT: [[TMP3:%.*]] = fptosi float [[TMP2]] to i64
+// UNSIGNED-NEXT: store i64 [[TMP3]], i64* @ula, align 8
+// UNSIGNED-NEXT: ret void
+//
+void half_fix6() {
+ ula = h;
+}
+
+
+// CHECK-LABEL: @half_sat1(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.fptosi.sat.i8.f16(half [[TMP1]])
+// CHECK-NEXT: store i8 [[TMP2]], i8* @sf_sat, align 1
+// CHECK-NEXT: ret void
+//
+void half_sat1() {
+ sf_sat = h;
+}
+
+// CHECK-LABEL: @half_sat2(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// CHECK-NEXT: [[TMP3:%.*]] = call i32 @llvm.fptosi.sat.i32.f32(float [[TMP2]])
+// CHECK-NEXT: store i32 [[TMP3]], i32* @lf_sat, align 4
+// CHECK-NEXT: ret void
+//
+void half_sat2() {
+ lf_sat = h;
+}
+
+// CHECK-LABEL: @half_sat3(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.fptosi.sat.i16.f16(half [[TMP1]])
+// CHECK-NEXT: store i16 [[TMP2]], i16* @sa_sat, align 2
+// CHECK-NEXT: ret void
+//
+void half_sat3() {
+ sa_sat = h;
+}
+
+// CHECK-LABEL: @half_sat4(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// CHECK-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.fptosi.sat.i64.f32(float [[TMP2]])
+// CHECK-NEXT: store i64 [[TMP3]], i64* @la_sat, align 8
+// CHECK-NEXT: ret void
+//
+void half_sat4() {
+ la_sat = h;
+}
+
+// SIGNED-LABEL: @half_sat5(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// SIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 2.560000e+02
+// SIGNED-NEXT: [[TMP3:%.*]] = call i16 @llvm.fptoui.sat.i16.f32(float [[TMP2]])
+// SIGNED-NEXT: store i16 [[TMP3]], i16* @usa_sat, align 2
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @half_sat5(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// UNSIGNED-NEXT: [[TMP1:%.*]] = fmul half [[TMP0]], 0xH5800
+// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.fptosi.sat.i16.f16(half [[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* @usa_sat, align 2
+// UNSIGNED-NEXT: ret void
+//
+void half_sat5() {
+ usa_sat = h;
+}
+
+// SIGNED-LABEL: @half_sat6(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// SIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41F0000000000000
+// SIGNED-NEXT: [[TMP3:%.*]] = call i64 @llvm.fptoui.sat.i64.f32(float [[TMP2]])
+// SIGNED-NEXT: store i64 [[TMP3]], i64* @ula_sat, align 8
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @half_sat6(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load half, half* @h, align 2
+// UNSIGNED-NEXT: [[TMP1:%.*]] = fpext half [[TMP0]] to float
+// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x41E0000000000000
+// UNSIGNED-NEXT: [[TMP3:%.*]] = call i64 @llvm.fptosi.sat.i64.f32(float [[TMP2]])
+// UNSIGNED-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
+// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP4]], i64 0, i64 [[TMP3]]
+// UNSIGNED-NEXT: store i64 [[SATMIN]], i64* @ula_sat, align 8
+// UNSIGNED-NEXT: ret void
+//
+void half_sat6() {
+ ula_sat = h;
+}
+
+
+// CHECK-LABEL: @fix_half1(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* @sf, align 1
+// CHECK-NEXT: [[TMP1:%.*]] = sitofp i8 [[TMP0]] to half
+// CHECK-NEXT: [[TMP2:%.*]] = fmul half [[TMP1]], 0xH2000
+// CHECK-NEXT: store half [[TMP2]], half* @h, align 2
+// CHECK-NEXT: ret void
+//
+void fix_half1() {
+ h = sf;
+}
+
+// CHECK-LABEL: @fix_half2(
+// 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: [[TMP3:%.*]] = fptrunc float [[TMP2]] to half
+// CHECK-NEXT: store half [[TMP3]], half* @h, align 2
+// CHECK-NEXT: ret void
+//
+void fix_half2() {
+ h = lf;
+}
+
+// CHECK-LABEL: @fix_half3(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP0:%.*]] = load i16, i16* @sa, align 2
+// CHECK-NEXT: [[TMP1:%.*]] = sitofp i16 [[TMP0]] to half
+// CHECK-NEXT: [[TMP2:%.*]] = fmul half [[TMP1]], 0xH2000
+// CHECK-NEXT: store half [[TMP2]], half* @h, align 2
+// CHECK-NEXT: ret void
+//
+void fix_half3() {
+ h = sa;
+}
+
+// CHECK-LABEL: @fix_half4(
+// 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: [[TMP3:%.*]] = fptrunc float [[TMP2]] to half
+// CHECK-NEXT: store half [[TMP3]], half* @h, align 2
+// CHECK-NEXT: ret void
+//
+void fix_half4() {
+ h = la;
+}
+
+// SIGNED-LABEL: @fix_half5(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2
+// SIGNED-NEXT: [[TMP1:%.*]] = uitofp i16 [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 3.906250e-03
+// SIGNED-NEXT: [[TMP3:%.*]] = fptrunc float [[TMP2]] to half
+// SIGNED-NEXT: store half [[TMP3]], half* @h, align 2
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @fix_half5(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2
+// UNSIGNED-NEXT: [[TMP1:%.*]] = uitofp i16 [[TMP0]] to half
+// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul half [[TMP1]], 0xH2000
+// UNSIGNED-NEXT: store half [[TMP2]], half* @h, align 2
+// UNSIGNED-NEXT: ret void
+//
+void fix_half5() {
+ h = usa;
+}
+
+// SIGNED-LABEL: @fix_half6(
+// SIGNED-NEXT: entry:
+// SIGNED-NEXT: [[TMP0:%.*]] = load i64, i64* @ula, align 8
+// SIGNED-NEXT: [[TMP1:%.*]] = uitofp i64 [[TMP0]] to float
+// SIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3DF0000000000000
+// SIGNED-NEXT: [[TMP3:%.*]] = fptrunc float [[TMP2]] to half
+// SIGNED-NEXT: store half [[TMP3]], half* @h, align 2
+// SIGNED-NEXT: ret void
+//
+// UNSIGNED-LABEL: @fix_half6(
+// UNSIGNED-NEXT: entry:
+// UNSIGNED-NEXT: [[TMP0:%.*]] = load i64, i64* @ula, align 8
+// UNSIGNED-NEXT: [[TMP1:%.*]] = uitofp i64 [[TMP0]] to float
+// UNSIGNED-NEXT: [[TMP2:%.*]] = fmul float [[TMP1]], 0x3E00000000000000
+// UNSIGNED-NEXT: [[TMP3:%.*]] = fptrunc float [[TMP2]] to half
+// UNSIGNED-NEXT: store half [[TMP3]], half* @h, align 2
+// UNSIGNED-NEXT: ret void
+//
+void fix_half6() {
+ h = ula;
+}
C.isSigned(), C.isSaturated(), BothPadded);
}
+ /// Given a floating point type and a fixed-point semantic, return a floating
+ /// point type which can accommodate the fixed-point semantic. This is either
+ /// \p Ty, or a floating point type with a larger exponent than Ty.
+ Type *getAccommodatingFloatType(Type *Ty, const FixedPointSemantics &Sema) {
+ const fltSemantics *FloatSema = &Ty->getFltSemantics();
+ while (!Sema.fitsInFloatSemantics(*FloatSema))
+ FloatSema = APFixedPoint::promoteFloatSemantics(FloatSema);
+ return Type::getFloatingPointTy(Ty->getContext(), *FloatSema);
+ }
+
public:
FixedPointBuilder(IRBuilderTy &Builder) : B(Builder) {}
DstSema, false);
}
+ Value *CreateFixedToFloating(Value *Src, const FixedPointSemantics &SrcSema,
+ Type *DstTy) {
+ Value *Result;
+ Type *OpTy = getAccommodatingFloatType(DstTy, SrcSema);
+ // 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, OpTy)
+ : B.CreateUIToFP(Src, OpTy);
+ // Rescale the integral-in-floating point by the scaling factor. This is
+ // lossless, except for overflow to infinity which is unlikely.
+ Result = B.CreateFMul(Result,
+ ConstantFP::get(OpTy, std::pow(2, -(int)SrcSema.getScale())));
+ if (OpTy != DstTy)
+ Result = B.CreateFPTrunc(Result, DstTy);
+ return Result;
+ }
+
+ Value *CreateFloatingToFixed(Value *Src, const FixedPointSemantics &DstSema) {
+ bool UseSigned = DstSema.isSigned() || DstSema.hasUnsignedPadding();
+ Value *Result = Src;
+ Type *OpTy = getAccommodatingFloatType(Src->getType(), DstSema);
+ if (OpTy != Src->getType())
+ Result = B.CreateFPExt(Result, OpTy);
+ // Rescale the floating point value so that its significant bits (for the
+ // purposes of the conversion) are in the integral range.
+ Result = B.CreateFMul(Result,
+ ConstantFP::get(OpTy, 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, OpTy}, {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