summaryrefslogtreecommitdiff
path: root/test/Transforms
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2014-04-13 18:23:41 +0000
committerSerge Pavlov <sepavloff@gmail.com>2014-04-13 18:23:41 +0000
commitea0ea637737b70162e0dddeabdc7ebdb2f631760 (patch)
tree50ce90da9838877775e0dac414caec33dbd73828 /test/Transforms
parent6a34916fbf37318e4fc6b371115394c2791a9c80 (diff)
downloadllvm-ea0ea637737b70162e0dddeabdc7ebdb2f631760.tar.gz
llvm-ea0ea637737b70162e0dddeabdc7ebdb2f631760.tar.bz2
llvm-ea0ea637737b70162e0dddeabdc7ebdb2f631760.tar.xz
Recognize test for overflow in integer multiplication.
If multiplication involves zero-extended arguments and the result is compared as in the patterns: %mul32 = trunc i64 %mul64 to i32 %zext = zext i32 %mul32 to i64 %overflow = icmp ne i64 %mul64, %zext or %overflow = icmp ugt i64 %mul64 , 0xffffffff then the multiplication may be replaced by call to umul.with.overflow. This change fixes PR4917 and PR4918. Differential Revision: http://llvm-reviews.chandlerc.com/D2814 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206137 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms')
-rw-r--r--test/Transforms/InstCombine/overflow-mul.ll164
1 files changed, 164 insertions, 0 deletions
diff --git a/test/Transforms/InstCombine/overflow-mul.ll b/test/Transforms/InstCombine/overflow-mul.ll
new file mode 100644
index 0000000000..04019ae7bc
--- /dev/null
+++ b/test/Transforms/InstCombine/overflow-mul.ll
@@ -0,0 +1,164 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+; return mul(zext x, zext y) > MAX
+define i32 @pr4917_1(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_1(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+; CHECK-NOT: zext i32
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %overflow = icmp ugt i64 %mul64, 4294967295
+; CHECK: extractvalue { i32, i1 } [[MUL]], 1
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+
+; return mul(zext x, zext y) >= MAX+1
+define i32 @pr4917_1a(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_1a(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+; CHECK-NOT: zext i32
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %overflow = icmp uge i64 %mul64, 4294967296
+; CHECK: extractvalue { i32, i1 } [[MUL]], 1
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+
+; mul(zext x, zext y) > MAX
+; mul(x, y) is used
+define i32 @pr4917_2(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_2(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+; CHECK-NOT: zext i32
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %overflow = icmp ugt i64 %mul64, 4294967295
+; CHECK-DAG: [[VAL:%.*]] = extractvalue { i32, i1 } [[MUL]], 0
+ %mul32 = trunc i64 %mul64 to i32
+; CHECK-DAG: [[OVFL:%.*]] = extractvalue { i32, i1 } [[MUL]], 1
+ %retval = select i1 %overflow, i32 %mul32, i32 111
+; CHECK: select i1 [[OVFL]], i32 [[VAL]]
+ ret i32 %retval
+}
+
+; return mul(zext x, zext y) > MAX
+; mul is used in non-truncate
+define i64 @pr4917_3(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_3(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+ %mul64 = mul i64 %l, %r
+; CHECK-NOT: umul.with.overflow.i32
+ %overflow = icmp ugt i64 %mul64, 4294967295
+ %retval = select i1 %overflow, i64 %mul64, i64 111
+ ret i64 %retval
+}
+
+; return mul(zext x, zext y) <= MAX
+define i32 @pr4917_4(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_4(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+; CHECK-NOT: zext i32
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %overflow = icmp ule i64 %mul64, 4294967295
+; CHECK: extractvalue { i32, i1 } [[MUL]], 1
+; CHECK: xor
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+
+; return mul(zext x, zext y) < MAX+1
+define i32 @pr4917_4a(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4917_4a(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+; CHECK-NOT: zext i32
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %overflow = icmp ult i64 %mul64, 4294967296
+; CHECK: extractvalue { i32, i1 } [[MUL]], 1
+; CHECK: xor
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+
+; operands of mul are of different size
+define i32 @pr4917_5(i32 %x, i8 %y) nounwind {
+; CHECK-LABEL: @pr4917_5(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i8 %y to i64
+; CHECK: [[Y:%.*]] = zext i8 %y to i32
+ %mul64 = mul i64 %l, %r
+ %overflow = icmp ugt i64 %mul64, 4294967295
+ %mul32 = trunc i64 %mul64 to i32
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 [[Y]])
+; CHECK-DAG: [[VAL:%.*]] = extractvalue { i32, i1 } [[MUL]], 0
+; CHECK-DAG: [[OVFL:%.*]] = extractvalue { i32, i1 } [[MUL]], 1
+ %retval = select i1 %overflow, i32 %mul32, i32 111
+; CHECK: select i1 [[OVFL]], i32 [[VAL]]
+ ret i32 %retval
+}
+
+; mul(zext x, zext y) != zext trunc mul
+define i32 @pr4918_1(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4918_1(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %part32 = trunc i64 %mul64 to i32
+ %part64 = zext i32 %part32 to i64
+ %overflow = icmp ne i64 %mul64, %part64
+; CHECK: [[OVFL:%.*]] = extractvalue { i32, i1 } [[MUL:%.*]], 1
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+
+; mul(zext x, zext y) == zext trunc mul
+define i32 @pr4918_2(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4918_2(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %part32 = trunc i64 %mul64 to i32
+ %part64 = zext i32 %part32 to i64
+ %overflow = icmp eq i64 %mul64, %part64
+; CHECK: extractvalue { i32, i1 } [[MUL]]
+ %retval = zext i1 %overflow to i32
+; CHECK: xor
+ ret i32 %retval
+}
+
+; zext trunc mul != mul(zext x, zext y)
+define i32 @pr4918_3(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: @pr4918_3(
+entry:
+ %l = zext i32 %x to i64
+ %r = zext i32 %y to i64
+ %mul64 = mul i64 %l, %r
+; CHECK: [[MUL:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
+ %part32 = trunc i64 %mul64 to i32
+ %part64 = zext i32 %part32 to i64
+ %overflow = icmp ne i64 %part64, %mul64
+; CHECK: extractvalue { i32, i1 } [[MUL]], 1
+ %retval = zext i1 %overflow to i32
+ ret i32 %retval
+}
+