summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
authorJames Molloy <james.molloy@arm.com>2015-03-24 11:15:23 +0000
committerJames Molloy <james.molloy@arm.com>2015-03-24 11:15:23 +0000
commit408df5160ca4e51d01d32c7c3e11b34c8150718a (patch)
tree2324021cf8679324be8590c763becf7d2d94ff31 /llvm/test
parent7cb18bf537ed319eaa06f12ed39f85594bed641a (diff)
downloadbcm5719-llvm-408df5160ca4e51d01d32c7c3e11b34c8150718a.tar.gz
bcm5719-llvm-408df5160ca4e51d01d32c7c3e11b34c8150718a.zip
"float2int": Add a new pass to demote from float to int where possible.
It is possible to have code that converts from integer to float, performs operations then converts back, and the result is provably the same as if integers were used. This can come from different sources, but the most obvious is a helper function that uses floats but the arguments given at an inlined callsites are integers. This pass considers all integers requiring a bitwidth less than or equal to the bitwidth of the mantissa of a floating point type (23 for floats, 52 for doubles) as exactly representable in floating point. To reduce the risk of harming efficient code, the pass only attempts to perform complete removal of inttofp/fptoint operations, not just move them around. llvm-svn: 233062
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/Transforms/Float2Int/basic.ll227
-rw-r--r--llvm/test/Transforms/Float2Int/toolarge.ll16
2 files changed, 243 insertions, 0 deletions
diff --git a/llvm/test/Transforms/Float2Int/basic.ll b/llvm/test/Transforms/Float2Int/basic.ll
new file mode 100644
index 00000000000..e03ffb4524e
--- /dev/null
+++ b/llvm/test/Transforms/Float2Int/basic.ll
@@ -0,0 +1,227 @@
+; RUN: opt < %s -float2int -S | FileCheck %s
+
+;
+; Positive tests
+;
+
+; CHECK-LABEL: @simple1
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = add i32 %1, 1
+; CHECK: %3 = trunc i32 %2 to i16
+; CHECK: ret i16 %3
+define i16 @simple1(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fadd float %1, 1.0
+ %3 = fptoui float %2 to i16
+ ret i16 %3
+}
+
+; CHECK-LABEL: @simple2
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = sub i32 %1, 1
+; CHECK: %3 = trunc i32 %2 to i8
+; CHECK: ret i8 %3
+define i8 @simple2(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fsub float %1, 1.0
+ %3 = fptoui float %2 to i8
+ ret i8 %3
+}
+
+; CHECK-LABEL: @simple3
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = sub i32 %1, 1
+; CHECK: ret i32 %2
+define i32 @simple3(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fsub float %1, 1.0
+ %3 = fptoui float %2 to i32
+ ret i32 %3
+}
+
+; CHECK-LABEL: @cmp
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = zext i8 %b to i32
+; CHECK: %3 = icmp slt i32 %1, %2
+; CHECK: ret i1 %3
+define i1 @cmp(i8 %a, i8 %b) {
+ %1 = uitofp i8 %a to float
+ %2 = uitofp i8 %b to float
+ %3 = fcmp ult float %1, %2
+ ret i1 %3
+}
+
+; CHECK-LABEL: @simple4
+; CHECK: %1 = zext i32 %a to i64
+; CHECK: %2 = add i64 %1, 1
+; CHECK: %3 = trunc i64 %2 to i32
+; CHECK: ret i32 %3
+define i32 @simple4(i32 %a) {
+ %1 = uitofp i32 %a to double
+ %2 = fadd double %1, 1.0
+ %3 = fptoui double %2 to i32
+ ret i32 %3
+}
+
+; CHECK-LABEL: @simple5
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = zext i8 %b to i32
+; CHECK: %3 = add i32 %1, 1
+; CHECK: %4 = mul i32 %3, %2
+; CHECK: ret i32 %4
+define i32 @simple5(i8 %a, i8 %b) {
+ %1 = uitofp i8 %a to float
+ %2 = uitofp i8 %b to float
+ %3 = fadd float %1, 1.0
+ %4 = fmul float %3, %2
+ %5 = fptoui float %4 to i32
+ ret i32 %5
+}
+
+; The two chains don't interact - failure of one shouldn't
+; cause failure of the other.
+
+; CHECK-LABEL: @multi1
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = zext i8 %b to i32
+; CHECK: %fc = uitofp i8 %c to float
+; CHECK: %x1 = add i32 %1, %2
+; CHECK: %z = fadd float %fc, %d
+; CHECK: %w = fptoui float %z to i32
+; CHECK: %r = add i32 %x1, %w
+; CHECK: ret i32 %r
+define i32 @multi1(i8 %a, i8 %b, i8 %c, float %d) {
+ %fa = uitofp i8 %a to float
+ %fb = uitofp i8 %b to float
+ %fc = uitofp i8 %c to float
+ %x = fadd float %fa, %fb
+ %y = fptoui float %x to i32
+ %z = fadd float %fc, %d
+ %w = fptoui float %z to i32
+ %r = add i32 %y, %w
+ ret i32 %r
+}
+
+; CHECK-LABEL: @simple_negzero
+; CHECK: %1 = zext i8 %a to i32
+; CHECK: %2 = add i32 %1, 0
+; CHECK: %3 = trunc i32 %2 to i16
+; CHECK: ret i16 %3
+define i16 @simple_negzero(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fadd fast float %1, -0.0
+ %3 = fptoui float %2 to i16
+ ret i16 %3
+}
+
+;
+; Negative tests
+;
+
+; CHECK-LABEL: @neg_multi1
+; CHECK: %fa = uitofp i8 %a to float
+; CHECK: %fc = uitofp i8 %c to float
+; CHECK: %x = fadd float %fa, %fc
+; CHECK: %y = fptoui float %x to i32
+; CHECK: %z = fadd float %fc, %d
+; CHECK: %w = fptoui float %z to i32
+; CHECK: %r = add i32 %y, %w
+; CHECK: ret i32 %r
+; The two chains intersect, which means because one fails, no
+; transform can occur.
+define i32 @neg_multi1(i8 %a, i8 %b, i8 %c, float %d) {
+ %fa = uitofp i8 %a to float
+ %fc = uitofp i8 %c to float
+ %x = fadd float %fa, %fc
+ %y = fptoui float %x to i32
+ %z = fadd float %fc, %d
+ %w = fptoui float %z to i32
+ %r = add i32 %y, %w
+ ret i32 %r
+}
+
+; CHECK-LABEL: @neg_muld
+; CHECK: %fa = uitofp i32 %a to double
+; CHECK: %fb = uitofp i32 %b to double
+; CHECK: %mul = fmul double %fa, %fb
+; CHECK: %r = fptoui double %mul to i64
+; CHECK: ret i64 %r
+; The i32 * i32 = i64, which has 64 bits, which is greater than the 52 bits
+; that can be exactly represented in a double.
+define i64 @neg_muld(i32 %a, i32 %b) {
+ %fa = uitofp i32 %a to double
+ %fb = uitofp i32 %b to double
+ %mul = fmul double %fa, %fb
+ %r = fptoui double %mul to i64
+ ret i64 %r
+}
+
+; CHECK-LABEL: @neg_mulf
+; CHECK: %fa = uitofp i16 %a to float
+; CHECK: %fb = uitofp i16 %b to float
+; CHECK: %mul = fmul float %fa, %fb
+; CHECK: %r = fptoui float %mul to i32
+; CHECK: ret i32 %r
+; The i16 * i16 = i32, which can't be represented in a float, but can in a
+; double. This should fail, as the written code uses floats, not doubles so
+; the original result may be inaccurate.
+define i32 @neg_mulf(i16 %a, i16 %b) {
+ %fa = uitofp i16 %a to float
+ %fb = uitofp i16 %b to float
+ %mul = fmul float %fa, %fb
+ %r = fptoui float %mul to i32
+ ret i32 %r
+}
+
+; CHECK-LABEL: @neg_cmp
+; CHECK: %1 = uitofp i8 %a to float
+; CHECK: %2 = uitofp i8 %b to float
+; CHECK: %3 = fcmp false float %1, %2
+; CHECK: ret i1 %3
+; "false" doesn't have an icmp equivalent.
+define i1 @neg_cmp(i8 %a, i8 %b) {
+ %1 = uitofp i8 %a to float
+ %2 = uitofp i8 %b to float
+ %3 = fcmp false float %1, %2
+ ret i1 %3
+}
+
+; CHECK-LABEL: @neg_div
+; CHECK: %1 = uitofp i8 %a to float
+; CHECK: %2 = fdiv float %1, 1.0
+; CHECK: %3 = fptoui float %2 to i16
+; CHECK: ret i16 %3
+; Division isn't a supported operator.
+define i16 @neg_div(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fdiv float %1, 1.0
+ %3 = fptoui float %2 to i16
+ ret i16 %3
+}
+
+; CHECK-LABEL: @neg_remainder
+; CHECK: %1 = uitofp i8 %a to float
+; CHECK: %2 = fadd float %1, 1.2
+; CHECK: %3 = fptoui float %2 to i16
+; CHECK: ret i16 %3
+; 1.2 is not an integer.
+define i16 @neg_remainder(i8 %a) {
+ %1 = uitofp i8 %a to float
+ %2 = fadd float %1, 1.25
+ %3 = fptoui float %2 to i16
+ ret i16 %3
+}
+
+; CHECK-LABEL: @neg_toolarge
+; CHECK: %1 = uitofp i80 %a to fp128
+; CHECK: %2 = fadd fp128 %1, %1
+; CHECK: %3 = fptoui fp128 %2 to i80
+; CHECK: ret i80 %3
+; i80 > i64, which is the largest bitwidth handleable by default.
+define i80 @neg_toolarge(i80 %a) {
+ %1 = uitofp i80 %a to fp128
+ %2 = fadd fp128 %1, %1
+ %3 = fptoui fp128 %2 to i80
+ ret i80 %3
+}
+
diff --git a/llvm/test/Transforms/Float2Int/toolarge.ll b/llvm/test/Transforms/Float2Int/toolarge.ll
new file mode 100644
index 00000000000..b5d77815768
--- /dev/null
+++ b/llvm/test/Transforms/Float2Int/toolarge.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -float2int -float2int-max-integer-bw=256 -S | FileCheck %s
+
+; CHECK-LABEL: @neg_toolarge
+; CHECK: %1 = uitofp i80 %a to fp128
+; CHECK: %2 = fadd fp128 %1, %1
+; CHECK: %3 = fptoui fp128 %2 to i80
+; CHECK: ret i80 %3
+; fp128 has a 112-bit mantissa, which can hold an i80. But we only support
+; up to i64, so it should fail (even though the max integer bitwidth is 256).
+define i80 @neg_toolarge(i80 %a) {
+ %1 = uitofp i80 %a to fp128
+ %2 = fadd fp128 %1, %1
+ %3 = fptoui fp128 %2 to i80
+ ret i80 %3
+}
+
OpenPOWER on IntegriCloud