summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/Reassociate
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/Reassociate')
-rw-r--r--llvm/test/Transforms/Reassociate/2002-05-15-AgressiveSubMove.ll10
-rw-r--r--llvm/test/Transforms/Reassociate/2002-05-15-MissedTree.ll11
-rw-r--r--llvm/test/Transforms/Reassociate/2002-05-15-SubReassociate.ll31
-rw-r--r--llvm/test/Transforms/Reassociate/2002-07-09-DominanceProblem.ll10
-rw-r--r--llvm/test/Transforms/Reassociate/2003-08-12-InfiniteLoop.ll9
-rw-r--r--llvm/test/Transforms/Reassociate/2005-09-01-ArrayOutOfBounds.ll24
-rw-r--r--llvm/test/Transforms/Reassociate/2006-04-27-ReassociateVector.ll12
-rw-r--r--llvm/test/Transforms/Reassociate/2011-01-26-UseAfterFree.ll33
-rw-r--r--llvm/test/Transforms/Reassociate/2012-05-08-UndefLeak.ll85
-rw-r--r--llvm/test/Transforms/Reassociate/2012-06-08-InfiniteLoop.ll21
-rw-r--r--llvm/test/Transforms/Reassociate/absorption.ll27
-rw-r--r--llvm/test/Transforms/Reassociate/add_across_block_crash.ll30
-rw-r--r--llvm/test/Transforms/Reassociate/basictest.ll297
-rw-r--r--llvm/test/Transforms/Reassociate/binop-identity.ll71
-rw-r--r--llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll185
-rw-r--r--llvm/test/Transforms/Reassociate/commute.ll19
-rw-r--r--llvm/test/Transforms/Reassociate/crash.ll174
-rw-r--r--llvm/test/Transforms/Reassociate/crash2.ll28
-rw-r--r--llvm/test/Transforms/Reassociate/deadcode.ll37
-rw-r--r--llvm/test/Transforms/Reassociate/erase_inst_made_change.ll29
-rw-r--r--llvm/test/Transforms/Reassociate/factorize-again.ll45
-rw-r--r--llvm/test/Transforms/Reassociate/fast-AgressiveSubMove.ll40
-rw-r--r--llvm/test/Transforms/Reassociate/fast-ArrayOutOfBounds.ll65
-rw-r--r--llvm/test/Transforms/Reassociate/fast-MissedTree.ll39
-rw-r--r--llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll400
-rw-r--r--llvm/test/Transforms/Reassociate/fast-SubReassociate.ll119
-rw-r--r--llvm/test/Transforms/Reassociate/fast-basictest.ll606
-rw-r--r--llvm/test/Transforms/Reassociate/fast-fp-commute.ll46
-rw-r--r--llvm/test/Transforms/Reassociate/fast-mightymul.ll35
-rw-r--r--llvm/test/Transforms/Reassociate/fast-multistep.ll35
-rw-r--r--llvm/test/Transforms/Reassociate/fp-commute.ll19
-rw-r--r--llvm/test/Transforms/Reassociate/fp-expr.ll39
-rw-r--r--llvm/test/Transforms/Reassociate/infloop-deadphi.ll28
-rw-r--r--llvm/test/Transforms/Reassociate/inverses.ll62
-rw-r--r--llvm/test/Transforms/Reassociate/keep-debug-loc.ll48
-rw-r--r--llvm/test/Transforms/Reassociate/long-chains.ll37
-rw-r--r--llvm/test/Transforms/Reassociate/looptest.ll52
-rw-r--r--llvm/test/Transforms/Reassociate/matching-binops.ll359
-rw-r--r--llvm/test/Transforms/Reassociate/mightymul.ll35
-rw-r--r--llvm/test/Transforms/Reassociate/min_int.ll13
-rw-r--r--llvm/test/Transforms/Reassociate/mixed-fast-nonfast-fp.ll42
-rw-r--r--llvm/test/Transforms/Reassociate/mulfactor.ll128
-rw-r--r--llvm/test/Transforms/Reassociate/multistep.ll35
-rw-r--r--llvm/test/Transforms/Reassociate/negation.ll46
-rw-r--r--llvm/test/Transforms/Reassociate/negation1.ll16
-rw-r--r--llvm/test/Transforms/Reassociate/no-op.ll38
-rw-r--r--llvm/test/Transforms/Reassociate/optional-flags.ll29
-rw-r--r--llvm/test/Transforms/Reassociate/otherops.ll42
-rw-r--r--llvm/test/Transforms/Reassociate/pointer-collision-non-determinism.ll107
-rw-r--r--llvm/test/Transforms/Reassociate/pr12245.ll46
-rw-r--r--llvm/test/Transforms/Reassociate/pr21205.ll21
-rw-r--r--llvm/test/Transforms/Reassociate/pr28367.ll28
-rw-r--r--llvm/test/Transforms/Reassociate/propagate-flags.ll13
-rw-r--r--llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll37
-rw-r--r--llvm/test/Transforms/Reassociate/reassociate-deadinst.ll16
-rw-r--r--llvm/test/Transforms/Reassociate/reassociate_dbgvalue_discard.ll79
-rw-r--r--llvm/test/Transforms/Reassociate/repeats.ll252
-rw-r--r--llvm/test/Transforms/Reassociate/secondary.ll24
-rw-r--r--llvm/test/Transforms/Reassociate/shift-factor.ll16
-rw-r--r--llvm/test/Transforms/Reassociate/shifttest.ll12
-rw-r--r--llvm/test/Transforms/Reassociate/subtest.ll28
-rw-r--r--llvm/test/Transforms/Reassociate/vaarg_movable.ll28
-rw-r--r--llvm/test/Transforms/Reassociate/wrap-flags.ll45
-rw-r--r--llvm/test/Transforms/Reassociate/xor_reassoc.ll294
64 files changed, 4687 insertions, 0 deletions
diff --git a/llvm/test/Transforms/Reassociate/2002-05-15-AgressiveSubMove.ll b/llvm/test/Transforms/Reassociate/2002-05-15-AgressiveSubMove.ll
new file mode 100644
index 00000000000..24300352a62
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2002-05-15-AgressiveSubMove.ll
@@ -0,0 +1,10 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+define i32 @test1(i32 %A) {
+; CHECK-LABEL: test1
+; CHECK: ret i32 0
+ %X = add i32 %A, 1
+ %Y = add i32 %A, 1
+ %r = sub i32 %X, %Y
+ ret i32 %r
+}
diff --git a/llvm/test/Transforms/Reassociate/2002-05-15-MissedTree.ll b/llvm/test/Transforms/Reassociate/2002-05-15-MissedTree.ll
new file mode 100644
index 00000000000..5f3c9209aed
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2002-05-15-MissedTree.ll
@@ -0,0 +1,11 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+define i32 @test1(i32 %A, i32 %B) {
+; CHECK-LABEL: test1
+; CHECK: %Z = add i32 %B, %A
+; CHECK: ret i32 %Z
+ %W = add i32 %B, -5
+ %Y = add i32 %A, 5
+ %Z = add i32 %W, %Y
+ ret i32 %Z
+}
diff --git a/llvm/test/Transforms/Reassociate/2002-05-15-SubReassociate.ll b/llvm/test/Transforms/Reassociate/2002-05-15-SubReassociate.ll
new file mode 100644
index 00000000000..8039ddef44e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2002-05-15-SubReassociate.ll
@@ -0,0 +1,31 @@
+; RUN: opt < %s -reassociate -constprop -instcombine -dce -S | FileCheck %s
+
+; With sub reassociation, constant folding can eliminate all of the constants.
+define i32 @test1(i32 %A, i32 %B) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[Z:%.*]] = sub i32 %A, %B
+; CHECK-NEXT: ret i32 [[Z]]
+;
+ %W = add i32 5, %B
+ %X = add i32 -7, %A
+ %Y = sub i32 %X, %W
+ %Z = add i32 %Y, 12
+ ret i32 %Z
+}
+
+; With sub reassociation, constant folding can eliminate the two 12 constants.
+define i32 @test2(i32 %A, i32 %B, i32 %C, i32 %D) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[SUM:%.*]] = add i32 %B, %A
+; CHECK-NEXT: [[SUM1:%.*]] = add i32 [[SUM]], %C
+; CHECK-NEXT: [[Q:%.*]] = sub i32 %D, [[SUM1]]
+; CHECK-NEXT: ret i32 [[Q]]
+;
+ %M = add i32 %A, 12
+ %N = add i32 %M, %B
+ %O = add i32 %N, %C
+ %P = sub i32 %D, %O
+ %Q = add i32 %P, 12
+ ret i32 %Q
+}
+
diff --git a/llvm/test/Transforms/Reassociate/2002-07-09-DominanceProblem.ll b/llvm/test/Transforms/Reassociate/2002-07-09-DominanceProblem.ll
new file mode 100644
index 00000000000..bbb08f96985
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2002-07-09-DominanceProblem.ll
@@ -0,0 +1,10 @@
+; The reassociate pass is not preserving dominance properties correctly
+;
+; RUN: opt < %s -reassociate
+
+define i32 @compute_dist(i32 %i, i32 %j) {
+ %reg119 = sub i32 %j, %i ; <i32> [#uses=1]
+ ret i32 %reg119
+}
+
+
diff --git a/llvm/test/Transforms/Reassociate/2003-08-12-InfiniteLoop.ll b/llvm/test/Transforms/Reassociate/2003-08-12-InfiniteLoop.ll
new file mode 100644
index 00000000000..af7a821a4ba
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2003-08-12-InfiniteLoop.ll
@@ -0,0 +1,9 @@
+; RUN: opt < %s -reassociate -disable-output
+
+define i32 @test(i32 %A.1, i32 %B.1, i32 %C.1, i32 %D.1) {
+ %tmp.16 = and i32 %A.1, %B.1 ; <i32> [#uses=1]
+ %tmp.18 = and i32 %tmp.16, %C.1 ; <i32> [#uses=1]
+ %tmp.20 = and i32 %tmp.18, %D.1 ; <i32> [#uses=1]
+ ret i32 %tmp.20
+}
+
diff --git a/llvm/test/Transforms/Reassociate/2005-09-01-ArrayOutOfBounds.ll b/llvm/test/Transforms/Reassociate/2005-09-01-ArrayOutOfBounds.ll
new file mode 100644
index 00000000000..f6cef35b177
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2005-09-01-ArrayOutOfBounds.ll
@@ -0,0 +1,24 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+define i32 @f1(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %a4) {
+; CHECK-LABEL: f1
+; CHECK-NEXT: ret i32 0
+
+ %tmp.2 = add i32 %a4, %a3
+ %tmp.4 = add i32 %tmp.2, %a2
+ %tmp.6 = add i32 %tmp.4, %a1
+ %tmp.8 = add i32 %tmp.6, %a0
+ %tmp.11 = add i32 %a3, %a2
+ %tmp.13 = add i32 %tmp.11, %a1
+ %tmp.15 = add i32 %tmp.13, %a0
+ %tmp.18 = add i32 %a2, %a1
+ %tmp.20 = add i32 %tmp.18, %a0
+ %tmp.23 = add i32 %a1, %a0
+ %tmp.26 = sub i32 %tmp.8, %tmp.15
+ %tmp.28 = add i32 %tmp.26, %tmp.20
+ %tmp.30 = sub i32 %tmp.28, %tmp.23
+ %tmp.32 = sub i32 %tmp.30, %a4
+ %tmp.34 = sub i32 %tmp.32, %a2
+ %T = mul i32 %tmp.34, %tmp.34
+ ret i32 %T
+}
diff --git a/llvm/test/Transforms/Reassociate/2006-04-27-ReassociateVector.ll b/llvm/test/Transforms/Reassociate/2006-04-27-ReassociateVector.ll
new file mode 100644
index 00000000000..ea869842b18
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2006-04-27-ReassociateVector.ll
@@ -0,0 +1,12 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+define <4 x float> @test1() {
+; CHECK-LABEL: test1
+; CHECK-NEXT: %tmp1 = fsub <4 x float> zeroinitializer, zeroinitializer
+; CHECK-NEXT: %tmp2 = fmul <4 x float> %tmp1, zeroinitializer
+; CHECK-NEXT: ret <4 x float> %tmp2
+
+ %tmp1 = fsub <4 x float> zeroinitializer, zeroinitializer
+ %tmp2 = fmul <4 x float> zeroinitializer, %tmp1
+ ret <4 x float> %tmp2
+}
diff --git a/llvm/test/Transforms/Reassociate/2011-01-26-UseAfterFree.ll b/llvm/test/Transforms/Reassociate/2011-01-26-UseAfterFree.ll
new file mode 100644
index 00000000000..1c8f0d2ea21
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2011-01-26-UseAfterFree.ll
@@ -0,0 +1,33 @@
+; RUN: opt < %s -reassociate
+; PR9039
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+target triple = "i386-gnu-linux"
+
+define void @exp_averages_intraday__deviation() {
+entry:
+ %0 = load i32, i32* undef, align 4
+ %1 = shl i32 %0, 2
+ %2 = add nsw i32 undef, %1
+ %3 = add nsw i32 %2, undef
+ %4 = mul nsw i32 %0, 12
+ %5 = add nsw i32 %3, %4
+ %6 = add nsw i32 %5, %4
+ %7 = add nsw i32 %6, undef
+ br i1 false, label %"4", label %"12"
+
+"4": ; preds = %entry
+ br i1 undef, label %"5", label %"8"
+
+"5": ; preds = %"4"
+ unreachable
+
+"8": ; preds = %"4"
+ %8 = getelementptr inbounds i8, i8* undef, i32 %6
+ br i1 undef, label %"13", label %"12"
+
+"12": ; preds = %"8", %entry
+ ret void
+
+"13": ; preds = %"8"
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/2012-05-08-UndefLeak.ll b/llvm/test/Transforms/Reassociate/2012-05-08-UndefLeak.ll
new file mode 100644
index 00000000000..c563fe26c13
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2012-05-08-UndefLeak.ll
@@ -0,0 +1,85 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+; PR12169
+; PR12764
+; XFAIL: *
+; Transform disabled until PR13021 is fixed.
+
+define i64 @f(i64 %x0) {
+; CHECK-LABEL: @f(
+; CHECK-NEXT: mul i64 %x0, 208
+; CHECK-NEXT: add i64 %{{.*}}, 1617
+; CHECK-NEXT: ret i64
+ %t0 = add i64 %x0, 1
+ %t1 = add i64 %x0, 2
+ %t2 = add i64 %x0, 3
+ %t3 = add i64 %x0, 4
+ %t4 = add i64 %x0, 5
+ %t5 = add i64 %x0, 6
+ %t6 = add i64 %x0, 7
+ %t7 = add i64 %x0, 8
+ %t8 = add i64 %x0, 9
+ %t9 = add i64 %x0, 10
+ %t10 = add i64 %x0, 11
+ %t11 = add i64 %x0, 12
+ %t12 = add i64 %x0, 13
+ %t13 = add i64 %x0, 14
+ %t14 = add i64 %x0, 15
+ %t15 = add i64 %x0, 16
+ %t16 = add i64 %x0, 17
+ %t17 = add i64 %x0, 18
+ %t18 = add i64 %t17, %t0
+ %t19 = add i64 %t18, %t1
+ %t20 = add i64 %t19, %t2
+ %t21 = add i64 %t20, %t3
+ %t22 = add i64 %t21, %t4
+ %t23 = add i64 %t22, %t5
+ %t24 = add i64 %t23, %t6
+ %t25 = add i64 %t24, %t7
+ %t26 = add i64 %t25, %t8
+ %t27 = add i64 %t26, %t9
+ %t28 = add i64 %t27, %t10
+ %t29 = add i64 %t28, %t11
+ %t30 = add i64 %t29, %t12
+ %t31 = add i64 %t30, %t13
+ %t32 = add i64 %t31, %t14
+ %t33 = add i64 %t32, %t15
+ %t34 = add i64 %t33, %t16
+ %t35 = add i64 %t34, %x0
+ %t36 = add i64 %t0, %t1
+ %t37 = add i64 %t36, %t2
+ %t38 = add i64 %t37, %t3
+ %t39 = add i64 %t38, %t4
+ %t40 = add i64 %t39, %t5
+ %t41 = add i64 %t40, %t6
+ %t42 = add i64 %t41, %t7
+ %t43 = add i64 %t42, %t8
+ %t44 = add i64 %t43, %t9
+ %t45 = add i64 %t44, %t10
+ %t46 = add i64 %t45, %t11
+ %t47 = add i64 %t46, %t12
+ %t48 = add i64 %t47, %t13
+ %t49 = add i64 %t48, %t14
+ %t50 = add i64 %t49, %t15
+ %t51 = add i64 %t50, %t16
+ %t52 = add i64 %t51, %t17
+ %t53 = add i64 %t52, %t18
+ %t54 = add i64 %t53, %t19
+ %t55 = add i64 %t54, %t20
+ %t56 = add i64 %t55, %t21
+ %t57 = add i64 %t56, %t22
+ %t58 = add i64 %t57, %t23
+ %t59 = add i64 %t58, %t24
+ %t60 = add i64 %t59, %t25
+ %t61 = add i64 %t60, %t26
+ %t62 = add i64 %t61, %t27
+ %t63 = add i64 %t62, %t28
+ %t64 = add i64 %t63, %t29
+ %t65 = add i64 %t64, %t30
+ %t66 = add i64 %t65, %t31
+ %t67 = add i64 %t66, %t32
+ %t68 = add i64 %t67, %t33
+ %t69 = add i64 %t68, %t34
+ %t70 = add i64 %t69, %t35
+ %t71 = add i64 %t70, %x0
+ ret i64 %t71
+}
diff --git a/llvm/test/Transforms/Reassociate/2012-06-08-InfiniteLoop.ll b/llvm/test/Transforms/Reassociate/2012-06-08-InfiniteLoop.ll
new file mode 100644
index 00000000000..6e62a287e02
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/2012-06-08-InfiniteLoop.ll
@@ -0,0 +1,21 @@
+; RUN: opt < %s -reassociate -disable-output
+; PR13041
+
+define void @foo() {
+entry:
+ br label %while.cond
+
+while.cond: ; preds = %while.body, %entry
+ %b.0 = phi i32 [ undef, %entry ], [ %sub2, %while.body ]
+ %c.0 = phi i32 [ undef, %entry ], [ %sub3, %while.body ]
+ br i1 undef, label %while.end, label %while.body
+
+while.body: ; preds = %while.cond
+ %sub = sub nsw i32 0, %b.0
+ %sub2 = sub nsw i32 %sub, %c.0
+ %sub3 = sub nsw i32 0, %c.0
+ br label %while.cond
+
+while.end: ; preds = %while.cond
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/absorption.ll b/llvm/test/Transforms/Reassociate/absorption.ll
new file mode 100644
index 00000000000..744107c8424
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/absorption.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -reassociate < %s | FileCheck %s
+
+; Check that if constants combine to an absorbing value then the expression is
+; evaluated as the absorbing value.
+
+define i8 @or_all_ones(i8 %x) {
+; CHECK-LABEL: @or_all_ones(
+; CHECK-NEXT: ret i8 -1
+;
+ %tmp1 = or i8 %x, 127
+ %tmp2 = or i8 %tmp1, 128
+ ret i8 %tmp2
+}
+
+; TODO: fmul by 0.0 with nsz+nnan should have simplified to 0.0.
+
+define double @fmul_zero(double %x) {
+; CHECK-LABEL: @fmul_zero(
+; CHECK-NEXT: [[R:%.*]] = fmul fast double [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret double [[R]]
+;
+ %x4 = fmul fast double %x, 4.0
+ %r = fmul fast double %x4, 0.0
+ ret double %r
+}
+
diff --git a/llvm/test/Transforms/Reassociate/add_across_block_crash.ll b/llvm/test/Transforms/Reassociate/add_across_block_crash.ll
new file mode 100644
index 00000000000..8a753a2dfa0
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/add_across_block_crash.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; This test is to make sure while processing a block, uses of instructions
+; from a different basic block don't get added to be re-optimized
+
+define void @main() {
+; CHECK-LABEL: @main(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 undef, label %bb1, label %bb2
+; CHECK: bb1:
+; CHECK-NEXT: ret void
+; CHECK: bb2:
+; CHECK-NEXT: ret void
+;
+entry:
+ %0 = fadd fast float undef, undef
+ br i1 undef, label %bb1, label %bb2
+
+bb1:
+ %1 = fmul fast float undef, -2.000000e+00
+ %2 = fmul fast float %1, 2.000000e+00
+ %3 = fadd fast float %2, 2.000000e+00
+ %4 = fadd fast float %3, %0
+ %mul351 = fmul fast float %4, 5.000000e-01
+ ret void
+
+bb2:
+ ret void
+}
+
diff --git a/llvm/test/Transforms/Reassociate/basictest.ll b/llvm/test/Transforms/Reassociate/basictest.ll
new file mode 100644
index 00000000000..0a1722d439b
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/basictest.ll
@@ -0,0 +1,297 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -gvn -instcombine -S | FileCheck %s
+; RUN: opt < %s -passes='reassociate,gvn,instcombine' -S | FileCheck %s
+
+define i32 @test1(i32 %arg) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[ARG_NEG:%.*]] = sub i32 0, [[ARG:%.*]]
+; CHECK-NEXT: ret i32 [[ARG_NEG]]
+;
+ %tmp1 = sub i32 -12, %arg
+ %tmp2 = add i32 %tmp1, 12
+ ret i32 %tmp2
+}
+
+define i32 @test2(i32 %reg109, i32 %reg1111) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[REG117:%.*]] = add i32 [[REG1111:%.*]], [[REG109:%.*]]
+; CHECK-NEXT: ret i32 [[REG117]]
+;
+ %reg115 = add i32 %reg109, -30
+ %reg116 = add i32 %reg115, %reg1111
+ %reg117 = add i32 %reg116, 30
+ ret i32 %reg117
+}
+
+@e = external global i32
+@a = external global i32
+@b = external global i32
+@c = external global i32
+@f = external global i32
+
+define void @test3() {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[A:%.*]] = load i32, i32* @a, align 4
+; CHECK-NEXT: [[B:%.*]] = load i32, i32* @b, align 4
+; CHECK-NEXT: [[C:%.*]] = load i32, i32* @c, align 4
+; CHECK-NEXT: [[T1:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], [[C]]
+; CHECK-NEXT: store i32 [[T2]], i32* @e, align 4
+; CHECK-NEXT: store i32 [[T2]], i32* @f, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load i32, i32* @a
+ %B = load i32, i32* @b
+ %C = load i32, i32* @c
+ %t1 = add i32 %A, %B
+ %t2 = add i32 %t1, %C
+ %t3 = add i32 %C, %A
+ %t4 = add i32 %t3, %B
+ ; e = (a+b)+c;
+ store i32 %t2, i32* @e
+ ; f = (a+c)+b
+ store i32 %t4, i32* @f
+ ret void
+}
+
+define void @test4() {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[A:%.*]] = load i32, i32* @a, align 4
+; CHECK-NEXT: [[B:%.*]] = load i32, i32* @b, align 4
+; CHECK-NEXT: [[C:%.*]] = load i32, i32* @c, align 4
+; CHECK-NEXT: [[T1:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], [[C]]
+; CHECK-NEXT: store i32 [[T2]], i32* @e, align 4
+; CHECK-NEXT: store i32 [[T2]], i32* @f, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load i32, i32* @a
+ %B = load i32, i32* @b
+ %C = load i32, i32* @c
+ %t1 = add i32 %A, %B
+ %t2 = add i32 %t1, %C
+ %t3 = add i32 %C, %A
+ %t4 = add i32 %t3, %B
+ ; e = c+(a+b)
+ store i32 %t2, i32* @e
+ ; f = (c+a)+b
+ store i32 %t4, i32* @f
+ ret void
+}
+
+define void @test5() {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[A:%.*]] = load i32, i32* @a, align 4
+; CHECK-NEXT: [[B:%.*]] = load i32, i32* @b, align 4
+; CHECK-NEXT: [[C:%.*]] = load i32, i32* @c, align 4
+; CHECK-NEXT: [[T1:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], [[C]]
+; CHECK-NEXT: store i32 [[T2]], i32* @e, align 4
+; CHECK-NEXT: store i32 [[T2]], i32* @f, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load i32, i32* @a
+ %B = load i32, i32* @b
+ %C = load i32, i32* @c
+ %t1 = add i32 %B, %A
+ %t2 = add i32 %t1, %C
+ %t3 = add i32 %C, %A
+ %t4 = add i32 %t3, %B
+ ; e = c+(b+a)
+ store i32 %t2, i32* @e
+ ; f = (c+a)+b
+ store i32 %t4, i32* @f
+ ret void
+}
+
+define i32 @test6() {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: ret i32 0
+;
+ %tmp.0 = load i32, i32* @a
+ %tmp.1 = load i32, i32* @b
+ ; (a+b)
+ %tmp.2 = add i32 %tmp.0, %tmp.1
+ %tmp.4 = load i32, i32* @c
+ ; (a+b)+c
+ %tmp.5 = add i32 %tmp.2, %tmp.4
+ ; (a+c)
+ %tmp.8 = add i32 %tmp.0, %tmp.4
+ ; (a+c)+b
+ %tmp.11 = add i32 %tmp.8, %tmp.1
+ ; X ^ X = 0
+ %RV = xor i32 %tmp.5, %tmp.11
+ ret i32 %RV
+}
+
+; This should be one add and two multiplies.
+; A*A*B + A*C*A
+
+define i32 @test7(i32 %A, i32 %B, i32 %C) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = add i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[REASS_MUL2:%.*]] = mul i32 [[A:%.*]], [[A]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[REASS_MUL2]], [[REASS_ADD1]]
+; CHECK-NEXT: ret i32 [[REASS_MUL]]
+;
+ %aa = mul i32 %A, %A
+ %aab = mul i32 %aa, %B
+ %ac = mul i32 %A, %C
+ %aac = mul i32 %ac, %A
+ %r = add i32 %aab, %aac
+ ret i32 %r
+}
+
+define i32 @test8(i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[C:%.*]] = sub i32 [[Z:%.*]], [[A]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %A = sub i32 0, %X
+ %B = mul i32 %A, %Y
+ ; (-X)*Y + Z -> Z-X*Y
+ %C = add i32 %B, %Z
+ ret i32 %C
+}
+
+; PR5458
+
+define i32 @test9(i32 %X) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[X:%.*]], 94
+; CHECK-NEXT: ret i32 [[FACTOR]]
+;
+ %Y = mul i32 %X, 47
+ %Z = add i32 %Y, %Y
+ ret i32 %Z
+}
+
+define i32 @test10(i32 %X) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[X:%.*]], 3
+; CHECK-NEXT: ret i32 [[FACTOR]]
+;
+ %Y = add i32 %X ,%X
+ %Z = add i32 %Y, %X
+ ret i32 %Z
+}
+
+define i32 @test11(i32 %W) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[W:%.*]], 381
+; CHECK-NEXT: ret i32 [[FACTOR]]
+;
+ %X = mul i32 %W, 127
+ %Y = add i32 %X ,%X
+ %Z = add i32 %Y, %X
+ ret i32 %Z
+}
+
+declare void @mumble(i32)
+
+define i32 @test12(i32 %X) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[X_NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT: call void @mumble(i32 [[X_NEG]])
+; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[X]], -3
+; CHECK-NEXT: [[Z:%.*]] = add i32 [[FACTOR]], 6
+; CHECK-NEXT: ret i32 [[Z]]
+;
+ %X.neg = sub nsw nuw i32 0, %X
+ call void @mumble(i32 %X.neg)
+ %A = sub i32 1, %X
+ %B = sub i32 2, %X
+ %C = sub i32 3, %X
+ %Y = add i32 %A ,%B
+ %Z = add i32 %Y, %C
+ ret i32 %Z
+}
+
+define i32 @test13(i32 %X1, i32 %X2, i32 %X3) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = sub i32 [[X3:%.*]], [[X2:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[REASS_ADD]], [[X1:%.*]]
+; CHECK-NEXT: ret i32 [[REASS_MUL]]
+;
+ %A = sub i32 0, %X1
+ %B = mul i32 %A, %X2 ; -X1*X2
+ %C = mul i32 %X1, %X3 ; X1*X3
+ %D = add i32 %B, %C ; -X1*X2 + X1*X3 -> X1*(X3-X2)
+ ret i32 %D
+}
+
+; PR5359
+
+define i32 @test14(i32 %X1, i32 %X2) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = sub i32 [[X1:%.*]], [[X2:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[REASS_ADD]], 47
+; CHECK-NEXT: ret i32 [[REASS_MUL]]
+;
+ %B = mul i32 %X1, 47 ; X1*47
+ %C = mul i32 %X2, -47 ; X2*-47
+ %D = add i32 %B, %C ; X1*47 + X2*-47 -> 47*(X1-X2)
+ ret i32 %D
+}
+
+; Do not reassociate expressions of type i1
+
+define i32 @test15(i32 %X1, i32 %X2, i32 %X3) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X1:%.*]], 0
+; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[X2:%.*]], [[X3:%.*]]
+; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]]
+; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[X1]], i32 0
+; CHECK-NEXT: ret i32 [[D]]
+;
+ %A = icmp ne i32 %X1, 0
+ %B = icmp slt i32 %X2, %X3
+ %C = and i1 %A, %B
+ %D = select i1 %C, i32 %X1, i32 0
+ ret i32 %D
+}
+
+; PR30256 - previously this asserted.
+
+define i64 @test16(i1 %cmp, i64 %a, i64 %b) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[FACTOR:%.*]] = mul i64 [[A:%.*]], -4
+; CHECK-NEXT: [[ADD2:%.*]] = add i64 [[FACTOR]], [[B:%.*]]
+; CHECK-NEXT: ret i64 [[ADD2]]
+; CHECK: if.end:
+; CHECK-NEXT: ret i64 0
+;
+entry:
+ %shl = shl i64 %a, 1
+ %shl.neg = sub i64 0, %shl
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %add1 = add i64 %shl.neg, %shl.neg
+ %add2 = add i64 %add1, %b
+ ret i64 %add2
+
+if.end:
+ ret i64 0
+}
+
+define i32 @test17(i32 %X1, i32 %X2, i32 %X3, i32 %X4) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[X4:%.*]], [[X3:%.*]]
+; CHECK-NEXT: [[C:%.*]] = mul i32 [[A]], [[X1:%.*]]
+; CHECK-NEXT: [[D:%.*]] = mul i32 [[A]], [[X2:%.*]]
+; CHECK-NEXT: [[E:%.*]] = xor i32 [[C]], [[D]]
+; CHECK-NEXT: ret i32 [[E]]
+;
+ %A = mul i32 %X3, %X1
+ %B = mul i32 %X3, %X2
+ %C = mul i32 %A, %X4
+ %D = mul i32 %B, %X4
+ %E = xor i32 %C, %D
+ ret i32 %E
+}
+
diff --git a/llvm/test/Transforms/Reassociate/binop-identity.ll b/llvm/test/Transforms/Reassociate/binop-identity.ll
new file mode 100644
index 00000000000..13333fad599
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/binop-identity.ll
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Don't produce an instruction that is a no-op because the constant is an identity constant.
+
+define i32 @add_0(i32 %x) {
+; CHECK-LABEL: @add_0(
+; CHECK-NEXT: ret i32 [[X:%.*]]
+;
+ %a1 = add i32 %x, -30
+ %a2 = add i32 %a1, 30
+ ret i32 %a2
+}
+
+define i32 @mul_1(i32 %x) {
+; CHECK-LABEL: @mul_1(
+; CHECK-NEXT: ret i32 [[X:%.*]]
+;
+ %a1 = mul i32 %x, -1
+ %a2 = mul i32 %a1, -1
+ ret i32 %a2
+}
+
+define i8 @and_neg1(i8 %x) {
+; CHECK-LABEL: @and_neg1(
+; CHECK-NEXT: ret i8 [[X:%.*]]
+;
+ %a1 = and i8 %x, 255
+ %a2 = and i8 %a1, 255
+ ret i8 %a2
+}
+
+define i8 @or_0(i8 %x) {
+; CHECK-LABEL: @or_0(
+; CHECK-NEXT: ret i8 [[X:%.*]]
+;
+ %a1 = or i8 %x, 0
+ %a2 = or i8 %a1, 0
+ ret i8 %a2
+}
+
+define i8 @xor_0(i8 %x) {
+; CHECK-LABEL: @xor_0(
+; CHECK-NEXT: ret i8 [[X:%.*]]
+;
+ %a1 = xor i8 %x, 42
+ %a2 = xor i8 %a1, 42
+ ret i8 %a2
+}
+
+; FIXME - the binop identity constant for fadd is -0.0, so this didn't fold.
+
+define float @fadd_0(float %x) {
+; CHECK-LABEL: @fadd_0(
+; CHECK-NEXT: [[A2:%.*]] = fadd fast float [[X:%.*]], 0.000000e+00
+; CHECK-NEXT: ret float [[A2]]
+;
+ %a1 = fadd fast float %x, -30.0
+ %a2 = fadd fast float %a1, 30.0
+ ret float %a2
+}
+
+define float @fmul_1(float %x) {
+; CHECK-LABEL: @fmul_1(
+; CHECK-NEXT: ret float [[X:%.*]]
+;
+ %a1 = fmul fast float %x, 4.0
+ %a2 = fmul fast float %a1, 0.25
+ ret float %a2
+}
+
diff --git a/llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll b/llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll
new file mode 100644
index 00000000000..7afc660809f
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/canonicalize-neg-const.ll
@@ -0,0 +1,185 @@
+; RUN: opt -reassociate -gvn -S < %s | FileCheck %s
+
+; (x + 0.1234 * y) * (x + -0.1234 * y) -> (x + 0.1234 * y) * (x - 0.1234 * y)
+define double @test1(double %x, double %y) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD:%.*]] = fadd double %x, [[MUL]]
+; CHECK-NEXT: [[ADD21:%.*]] = fsub double %x, [[MUL]]
+; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[ADD]], [[ADD21]]
+; CHECK-NEXT: ret double [[MUL3]]
+;
+ %mul = fmul double 1.234000e-01, %y
+ %add = fadd double %mul, %x
+ %mul1 = fmul double -1.234000e-01, %y
+ %add2 = fadd double %mul1, %x
+ %mul3 = fmul double %add, %add2
+ ret double %mul3
+}
+
+; (x + -0.1234 * y) * (x + -0.1234 * y) -> (x - 0.1234 * y) * (x - 0.1234 * y)
+define double @test2(double %x, double %y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD1:%.*]] = fsub double %x, [[MUL]]
+; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[ADD1]], [[ADD1]]
+; CHECK-NEXT: ret double [[MUL3]]
+;
+ %mul = fmul double %y, -1.234000e-01
+ %add = fadd double %mul, %x
+ %mul1 = fmul double %y, -1.234000e-01
+ %add2 = fadd double %mul1, %x
+ %mul3 = fmul double %add, %add2
+ ret double %mul3
+}
+
+; (x + 0.1234 * y) * (x - -0.1234 * y) -> (x + 0.1234 * y) * (x + 0.1234 * y)
+define double @test3(double %x, double %y) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD:%.*]] = fadd double %x, [[MUL]]
+; CHECK-NEXT: [[MUL3:%.*]] = fmul double [[ADD]], [[ADD]]
+; CHECK-NEXT: ret double [[MUL3]]
+;
+ %mul = fmul double %y, 1.234000e-01
+ %add = fadd double %mul, %x
+ %mul1 = fmul double %y, -1.234000e-01
+ %add2 = fsub double %x, %mul1
+ %mul3 = fmul double %add, %add2
+ ret double %mul3
+}
+
+; Canonicalize (x - -0.1234 * y)
+define double @test5(double %x, double %y) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[SUB1:%.*]] = fadd double %x, [[MUL]]
+; CHECK-NEXT: ret double [[SUB1]]
+;
+ %mul = fmul double -1.234000e-01, %y
+ %sub = fsub double %x, %mul
+ ret double %sub
+}
+
+; Don't modify (-0.1234 * y - x)
+define double @test6(double %x, double %y) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, -1.234000e-01
+; CHECK-NEXT: [[SUB:%.*]] = fsub double [[MUL]], %x
+; CHECK-NEXT: ret double [[SUB]]
+;
+ %mul = fmul double -1.234000e-01, %y
+ %sub = fsub double %mul, %x
+ ret double %sub
+}
+
+; Canonicalize (-0.1234 * y + x) -> (x - 0.1234 * y)
+define double @test7(double %x, double %y) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD1:%.*]] = fsub double %x, [[MUL]]
+; CHECK-NEXT: ret double [[ADD1]]
+;
+ %mul = fmul double -1.234000e-01, %y
+ %add = fadd double %mul, %x
+ ret double %add
+}
+
+; Canonicalize (y * -0.1234 + x) -> (x - 0.1234 * y)
+define double @test8(double %x, double %y) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: [[MUL:%.*]] = fmul double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD1:%.*]] = fsub double %x, [[MUL]]
+; CHECK-NEXT: ret double [[ADD1]]
+;
+ %mul = fmul double %y, -1.234000e-01
+ %add = fadd double %mul, %x
+ ret double %add
+}
+
+; Canonicalize (x - -0.1234 / y)
+define double @test9(double %x, double %y) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: [[DIV:%.*]] = fdiv double 1.234000e-01, %y
+; CHECK-NEXT: [[SUB1:%.*]] = fadd double %x, [[DIV]]
+; CHECK-NEXT: ret double [[SUB1]]
+;
+ %div = fdiv double -1.234000e-01, %y
+ %sub = fsub double %x, %div
+ ret double %sub
+}
+
+; Don't modify (-0.1234 / y - x)
+define double @test10(double %x, double %y) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: [[DIV:%.*]] = fdiv double -1.234000e-01, %y
+; CHECK-NEXT: [[SUB:%.*]] = fsub double [[DIV]], %x
+; CHECK-NEXT: ret double [[SUB]]
+;
+ %div = fdiv double -1.234000e-01, %y
+ %sub = fsub double %div, %x
+ ret double %sub
+}
+
+; Canonicalize (-0.1234 / y + x) -> (x - 0.1234 / y)
+define double @test11(double %x, double %y) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[DIV:%.*]] = fdiv double 1.234000e-01, %y
+; CHECK-NEXT: [[ADD1:%.*]] = fsub double %x, [[DIV]]
+; CHECK-NEXT: ret double [[ADD1]]
+;
+ %div = fdiv double -1.234000e-01, %y
+ %add = fadd double %div, %x
+ ret double %add
+}
+
+; Canonicalize (y / -0.1234 + x) -> (x - y / 0.1234)
+define double @test12(double %x, double %y) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[DIV:%.*]] = fdiv double %y, 1.234000e-01
+; CHECK-NEXT: [[ADD1:%.*]] = fsub double %x, [[DIV]]
+; CHECK-NEXT: ret double [[ADD1]]
+;
+ %div = fdiv double %y, -1.234000e-01
+ %add = fadd double %div, %x
+ ret double %add
+}
+
+; Don't create an NSW violation
+define i4 @test13(i4 %x) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i4 %x, -2
+; CHECK-NEXT: [[ADD:%.*]] = add i4 [[MUL]], 3
+; CHECK-NEXT: ret i4 [[ADD]]
+;
+ %mul = mul nsw i4 %x, -2
+ %add = add i4 %mul, 3
+ ret i4 %add
+}
+
+; This tests used to cause an infinite loop where we would loop between
+; canonicalizing the negated constant (i.e., (X + Y*-5.0) -> (X - Y*5.0)) and
+; breaking up a subtract (i.e., (X - Y*5.0) -> X + (0 - Y*5.0)). To break the
+; cycle, we don't canonicalize the negative constant if we're going to later
+; break up the subtract.
+;
+; Check to make sure we don't canonicalize
+; (%pow2*-5.0 + %sub) -> (%sub - %pow2*5.0)
+; as we would later break up this subtract causing a cycle.
+
+define double @pr34078(double %A) {
+; CHECK-LABEL: @pr34078(
+; CHECK-NEXT: [[SUB:%.*]] = fsub fast double 1.000000e+00, %A
+; CHECK-NEXT: [[POW2:%.*]] = fmul double %A, %A
+; CHECK-NEXT: [[MUL5_NEG:%.*]] = fmul fast double [[POW2]], -5.000000e-01
+; CHECK-NEXT: [[SUB1:%.*]] = fadd fast double [[MUL5_NEG]], [[SUB]]
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast double [[SUB1]], 2.000000e+00
+; CHECK-NEXT: ret double [[FACTOR]]
+;
+ %sub = fsub fast double 1.000000e+00, %A
+ %pow2 = fmul double %A, %A
+ %mul5 = fmul fast double %pow2, 5.000000e-01
+ %sub1 = fsub fast double %sub, %mul5
+ %add = fadd fast double %sub1, %sub1
+ ret double %add
+}
diff --git a/llvm/test/Transforms/Reassociate/commute.ll b/llvm/test/Transforms/Reassociate/commute.ll
new file mode 100644
index 00000000000..760e51b05e1
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/commute.ll
@@ -0,0 +1,19 @@
+; RUN: opt -reassociate -S < %s | FileCheck %s
+
+declare void @use(i32)
+
+define void @test1(i32 %x, i32 %y) {
+; CHECK-LABEL: test1
+; CHECK: mul i32 %y, %x
+; CHECK: mul i32 %y, %x
+; CHECK: sub i32 %1, %2
+; CHECK: call void @use(i32 %{{.*}})
+; CHECK: call void @use(i32 %{{.*}})
+
+ %1 = mul i32 %x, %y
+ %2 = mul i32 %y, %x
+ %3 = sub i32 %1, %2
+ call void @use(i32 %1)
+ call void @use(i32 %3)
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/crash.ll b/llvm/test/Transforms/Reassociate/crash.ll
new file mode 100644
index 00000000000..f8774ea509a
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/crash.ll
@@ -0,0 +1,174 @@
+; RUN: opt -reassociate -disable-output < %s
+
+
+; rdar://7507855
+define fastcc i32 @test1() nounwind {
+entry:
+ %cond = select i1 undef, i32 1, i32 -1 ; <i32> [#uses=2]
+ br label %for.cond
+
+for.cond: ; preds = %for.body, %entry
+ %sub889 = sub i32 undef, undef ; <i32> [#uses=1]
+ %sub891 = sub i32 %sub889, %cond ; <i32> [#uses=0]
+ %add896 = sub i32 0, %cond ; <i32> [#uses=0]
+ ret i32 undef
+}
+
+; PR5981
+define i32 @test2() nounwind ssp {
+entry:
+ %0 = load i32, i32* undef, align 4
+ %1 = mul nsw i32 undef, %0
+ %2 = mul nsw i32 undef, %0
+ %3 = add nsw i32 undef, %1
+ %4 = add nsw i32 %3, %2
+ %5 = add nsw i32 %4, 4
+ %6 = shl i32 %0, 3
+ %7 = add nsw i32 %5, %6
+ br label %bb4.i9
+
+bb4.i9:
+ %8 = add nsw i32 undef, %1
+ ret i32 0
+}
+
+
+define i32 @test3(i32 %Arg, i32 %x1, i32 %x2, i32 %x3) {
+ %A = mul i32 %x1, %Arg
+ %B = mul i32 %Arg, %x2 ;; Part of add operation being factored, also used by C
+ %C = mul i32 %x3, %B
+
+ %D = add i32 %A, %B
+ %E = add i32 %D, %C
+ ret i32 %E
+}
+
+
+; rdar://9096268
+define void @x66303361ae3f602889d1b7d0f86e5455(i8* %arg) nounwind {
+_:
+ br label %_33
+
+_33: ; preds = %_33, %_
+ %tmp348 = load i8, i8* %arg, align 1
+ %tmp349 = lshr i8 %tmp348, 7
+ %tmp350 = or i8 %tmp349, 42
+ %tmp351 = add i8 %tmp350, -42
+ %tmp352 = zext i8 %tmp351 to i32
+ %tmp358 = add i32 %tmp352, -501049439
+ %tmp359 = mul i32 %tmp358, %tmp358
+ %tmp360 = mul i32 %tmp352, %tmp352
+ %tmp361 = sub i32 %tmp359, %tmp360
+ %tmp362 = mul i32 %tmp361, -920056735
+ %tmp363 = add i32 %tmp362, 501049439
+ %tmp364 = add i32 %tmp362, -2000262972
+ %tmp365 = sub i32 %tmp363, %tmp364
+ %tmp366 = sub i32 -501049439, %tmp362
+ %tmp367 = add i32 %tmp365, %tmp366
+ br label %_33
+}
+
+define void @test(i32 %a, i32 %b, i32 %c, i32 %d) {
+ %tmp.2 = xor i32 %a, %b ; <i32> [#uses=1]
+ %tmp.5 = xor i32 %c, %d ; <i32> [#uses=1]
+ %tmp.6 = xor i32 %tmp.2, %tmp.5 ; <i32> [#uses=1]
+ %tmp.9 = xor i32 %c, %a ; <i32> [#uses=1]
+ %tmp.12 = xor i32 %b, %d ; <i32> [#uses=1]
+ %tmp.13 = xor i32 %tmp.9, %tmp.12 ; <i32> [#uses=1]
+ %tmp.16 = xor i32 %tmp.6, %tmp.13 ; <i32> [#uses=0]
+ ret void
+}
+
+define i128 @foo() {
+ %mul = mul i128 0, 0
+ ret i128 %mul
+}
+
+define void @infinite_loop() {
+entry:
+ br label %loop
+loop:
+ %x = phi i32 [undef, %entry], [%x, %loop]
+ %dead = add i32 %x, 0
+ br label %loop
+unreachable1:
+ %y1 = add i32 %y1, 0
+ %z1 = add i32 %y1, 0
+ ret void
+unreachable2:
+ %y2 = add i32 %y2, 0
+ %z2 = add i32 %y2, %y2
+ ret void
+unreachable3:
+ %y3 = add i32 %y3, %y3
+ %z3 = add i32 %y3, 0
+ ret void
+unreachable4:
+ %y4 = add i32 %y4, %y4
+ %z4 = add i32 %y4, %y4
+ ret void
+}
+
+; PR13185
+define void @pr13185(i16 %p) {
+entry:
+ br label %for.cond
+
+for.cond: ; preds = %for.cond, %entry
+ %x.0 = phi i32 [ undef, %entry ], [ %conv, %for.cond ]
+ %conv = zext i16 %p to i32
+ br label %for.cond
+}
+
+; PR12963
+@a = external global i8
+define i8 @f0(i8 %x) {
+ %t0 = load i8, i8* @a
+ %t1 = mul i8 %x, %x
+ %t2 = mul i8 %t1, %t1
+ %t3 = mul i8 %t2, %t2
+ %t4 = mul i8 %t3, %x
+ %t5 = mul i8 %t4, %t4
+ %t6 = mul i8 %t5, %x
+ %t7 = mul i8 %t6, %t0
+ ret i8 %t7
+}
+
+define i32 @sozefx_(i32 %x, i32 %y) {
+ %t0 = sub i32 %x, %x
+ %t1 = mul i32 %t0, %t0
+ %t2 = mul i32 %x, %t0
+ %t3 = mul i32 %t1, %t1
+ %t4 = add i32 %t2, %t3
+ %t5 = mul i32 %x, %y
+ %t6 = add i32 %t4, %t5
+ ret i32 %t6
+}
+
+define i32 @bar(i32 %arg, i32 %arg1, i32 %arg2) {
+ %tmp1 = mul i32 %arg1, 2
+ %tmp2 = mul i32 %tmp1, 3
+ %tmp3 = mul i32 %arg2, 2
+ %tmp4 = add i32 %tmp1, 1 ; dead code
+ %ret = add i32 %tmp2, %tmp3
+ ret i32 %ret
+}
+
+; PR14060
+define i8 @hang(i8 %p, i8 %p0, i8 %p1, i8 %p2, i8 %p3, i8 %p4, i8 %p5, i8 %p6, i8 %p7, i8 %p8, i8 %p9) {
+ %tmp = zext i1 false to i8
+ %tmp16 = or i8 %tmp, 1
+ %tmp22 = or i8 %p7, %p0
+ %tmp23 = or i8 %tmp16, %tmp22
+ %tmp28 = or i8 %p9, %p1
+ %tmp31 = or i8 %tmp23, %p2
+ %tmp32 = or i8 %tmp31, %tmp28
+ %tmp38 = or i8 %p8, %p3
+ %tmp39 = or i8 %tmp16, %tmp38
+ %tmp43 = or i8 %tmp39, %p4
+ %tmp44 = or i8 %tmp43, 1
+ %tmp47 = or i8 %tmp32, %p5
+ %tmp50 = or i8 %tmp47, %p6
+ %tmp51 = or i8 %tmp44, %tmp50
+ ret i8 %tmp51
+}
diff --git a/llvm/test/Transforms/Reassociate/crash2.ll b/llvm/test/Transforms/Reassociate/crash2.ll
new file mode 100644
index 00000000000..7e4a3278c9e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/crash2.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -reassociate %s -S -o - | FileCheck %s
+
+; Reassociate pass used to crash on these example
+
+@g = global i32 0
+
+define float @undef1() {
+; CHECK-LABEL: @undef1(
+; CHECK-NEXT: ret float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float fsub (float -0.000000e+00, float bitcast (i32 ptrtoint (i32* @g to i32) to float)), float fsub (float -0.000000e+00, float bitcast (i32 ptrtoint (i32* @g to i32) to float)))))
+;
+ %t0 = fadd fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), bitcast (i32 ptrtoint (i32* @g to i32) to float)
+ %t1 = fsub fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), %t0
+ %t2 = fadd fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), %t1
+ ret float %t2
+}
+
+define void @undef2() {
+; CHECK-LABEL: @undef2(
+; CHECK-NEXT: unreachable
+;
+ %t0 = fadd fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), bitcast (i32 ptrtoint (i32* @g to i32) to float)
+ %t1 = fadd fast float %t0, 1.0
+ %t2 = fsub fast float %t0, %t1
+ %t3 = fmul fast float %t2, 2.0
+ unreachable
+}
+
diff --git a/llvm/test/Transforms/Reassociate/deadcode.ll b/llvm/test/Transforms/Reassociate/deadcode.ll
new file mode 100644
index 00000000000..866cf64d2a1
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/deadcode.ll
@@ -0,0 +1,37 @@
+; RUN: opt < %s -reassociate -disable-output
+
+; It has been detected that dead loops like the one in this test case can be
+; created by -jump-threading (it was detected by a csmith generated program).
+;
+; According to -verify this is valid input (even if it could be discussed if
+; the dead loop really satisfies SSA form).
+;
+; The problem found was that the -reassociate pass ends up in an infinite loop
+; when analysing the 'deadloop1' basic block. See "Bugzilla - Bug 30818".
+define void @deadloop1() {
+ br label %endlabel
+
+deadloop1:
+ %1 = xor i32 %2, 7
+ %2 = xor i32 %1, 8
+ br label %deadloop1
+
+endlabel:
+ ret void
+}
+
+
+; Another example showing that dead code could result in infinite loops in
+; reassociate pass. See "Bugzilla - Bug 30818".
+define void @deadloop2() {
+ br label %endlabel
+
+deadloop2:
+ %1 = and i32 %2, 7
+ %2 = and i32 %3, 8
+ %3 = and i32 %1, 6
+ br label %deadloop2
+
+endlabel:
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/erase_inst_made_change.ll b/llvm/test/Transforms/Reassociate/erase_inst_made_change.ll
new file mode 100644
index 00000000000..febb9447e2b
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/erase_inst_made_change.ll
@@ -0,0 +1,29 @@
+; RUN: opt < %s -inline -reassociate -S | FileCheck %s
+
+; This test case exposed a bug in reassociate where EraseInst's
+; removal of a dead call wasn't recognized as changing the IR.
+; So when runOnFunction propagated the "made changes" upwards
+; to the CallGraphSCCPass it signalled that no changes had been
+; made, so CallGraphSCCPass assumed that the old CallGraph,
+; as known by that pass manager, still was up-to-date.
+;
+; This was detected as an assert when trying to remove the
+; no longer used function 'bar' (due to incorrect reference
+; count in the CallGraph).
+
+define void @foo() {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret void
+entry:
+ call void @bar()
+ ret void
+}
+
+define internal void @bar() noinline nounwind readnone {
+; CHECK-NOT: bar
+entry:
+ ret void
+}
+
+
diff --git a/llvm/test/Transforms/Reassociate/factorize-again.ll b/llvm/test/Transforms/Reassociate/factorize-again.ll
new file mode 100644
index 00000000000..d86fbf40179
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/factorize-again.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -reassociate < %s | FileCheck %s
+
+define void @main(float, float) {
+; CHECK-LABEL: @main(
+; CHECK-NEXT: wrapper_entry:
+; CHECK-NEXT: [[TMP2:%.*]] = fsub float undef, [[TMP0:%.*]]
+; CHECK-NEXT: [[TMP3:%.*]] = fsub float undef, [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = call float @llvm.rsqrt.f32(float undef)
+; CHECK-NEXT: [[REASS_ADD2:%.*]] = fadd fast float [[TMP3]], [[TMP2]]
+; CHECK-NEXT: [[REASS_MUL3:%.*]] = fmul fast float [[TMP4]], [[REASS_ADD2]]
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = fadd fast float [[REASS_MUL3]], [[TMP4]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_ADD1]], undef
+; CHECK-NEXT: [[TMP5:%.*]] = call float @foo2(float [[REASS_MUL]], float 0.000000e+00)
+; CHECK-NEXT: [[MUL36:%.*]] = fmul fast float [[TMP5]], 1.500000e+00
+; CHECK-NEXT: call void @foo1(i32 4, float [[MUL36]])
+; CHECK-NEXT: ret void
+;
+wrapper_entry:
+ %2 = fsub float undef, %0
+ %3 = fsub float undef, %1
+ %4 = call float @llvm.rsqrt.f32(float undef)
+ %5 = fmul fast float undef, %4
+ %6 = fmul fast float %2, %4
+ %7 = fmul fast float %3, %4
+ %8 = fmul fast float %5, undef
+ %9 = fmul fast float %6, undef
+ %10 = fmul fast float %7, undef
+ %11 = fadd fast float %8, %9
+ %12 = fadd fast float %11, %10
+ %13 = call float @foo2(float %12, float 0.000000e+00)
+ %mul36 = fmul fast float %13, 1.500000e+00
+ call void @foo1(i32 4, float %mul36)
+ ret void
+}
+
+declare void @foo1(i32, float)
+
+declare float @foo2(float, float) #1
+
+declare float @llvm.rsqrt.f32(float) #1
+
+attributes #0 = { argmemonly nounwind }
+attributes #1 = { nounwind readnone }
+
diff --git a/llvm/test/Transforms/Reassociate/fast-AgressiveSubMove.ll b/llvm/test/Transforms/Reassociate/fast-AgressiveSubMove.ll
new file mode 100644
index 00000000000..d74d3121359
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-AgressiveSubMove.ll
@@ -0,0 +1,40 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+define float @test1(float %A) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[X:%.*]] = fadd float %A, 1.000000e+00
+; CHECK-NEXT: [[Y:%.*]] = fadd float %A, 1.000000e+00
+; CHECK-NEXT: [[R:%.*]] = fsub float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %X = fadd float %A, 1.000000e+00
+ %Y = fadd float %A, 1.000000e+00
+ %r = fsub float %X, %Y
+ ret float %r
+}
+
+define float @test2(float %A) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %X = fadd fast float 1.000000e+00, %A
+ %Y = fadd fast float 1.000000e+00, %A
+ %r = fsub fast float %X, %Y
+ ret float %r
+}
+
+; Check again using minimal subset of FMF.
+
+define float @test2_reassoc(float %A) {
+; CHECK-LABEL: @test2_reassoc(
+; CHECK-NEXT: [[X:%.*]] = fadd reassoc float %A, 1.000000e+00
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc float %A, 1.000000e+00
+; CHECK-NEXT: [[R:%.*]] = fsub reassoc float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %X = fadd reassoc float 1.000000e+00, %A
+ %Y = fadd reassoc float 1.000000e+00, %A
+ %r = fsub reassoc float %X, %Y
+ ret float %r
+}
+
diff --git a/llvm/test/Transforms/Reassociate/fast-ArrayOutOfBounds.ll b/llvm/test/Transforms/Reassociate/fast-ArrayOutOfBounds.ll
new file mode 100644
index 00000000000..0109e4fd1b3
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-ArrayOutOfBounds.ll
@@ -0,0 +1,65 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+; Not marked as fast, so must not change.
+define float @test1(float %a0, float %a1, float %a2, float %a3, float %a4) {
+; CHECK-LABEL: test1
+; CHECK-NEXT: %tmp.2 = fadd float %a3, %a4
+; CHECK-NEXT: %tmp.4 = fadd float %tmp.2, %a2
+; CHECK-NEXT: %tmp.6 = fadd float %tmp.4, %a1
+; CHECK-NEXT: %tmp.8 = fadd float %tmp.6, %a0
+; CHECK-NEXT: %tmp.11 = fadd float %a2, %a3
+; CHECK-NEXT: %tmp.13 = fadd float %tmp.11, %a1
+; CHECK-NEXT: %tmp.15 = fadd float %tmp.13, %a0
+; CHECK-NEXT: %tmp.18 = fadd float %a1, %a2
+; CHECK-NEXT: %tmp.20 = fadd float %tmp.18, %a0
+; CHECK-NEXT: %tmp.23 = fadd float %a0, %a1
+; CHECK-NEXT: %tmp.26 = fsub float %tmp.8, %tmp.15
+; CHECK-NEXT: %tmp.28 = fadd float %tmp.20, %tmp.26
+; CHECK-NEXT: %tmp.30 = fsub float %tmp.28, %tmp.23
+; CHECK-NEXT: %tmp.32 = fsub float %tmp.30, %a4
+; CHECK-NEXT: %tmp.34 = fsub float %tmp.32, %a2
+; CHECK-NEXT: %T = fmul float %tmp.34, %tmp.34
+; CHECK-NEXT: ret float %T
+
+ %tmp.2 = fadd float %a4, %a3
+ %tmp.4 = fadd float %tmp.2, %a2
+ %tmp.6 = fadd float %tmp.4, %a1
+ %tmp.8 = fadd float %tmp.6, %a0
+ %tmp.11 = fadd float %a3, %a2
+ %tmp.13 = fadd float %tmp.11, %a1
+ %tmp.15 = fadd float %tmp.13, %a0
+ %tmp.18 = fadd float %a2, %a1
+ %tmp.20 = fadd float %tmp.18, %a0
+ %tmp.23 = fadd float %a1, %a0
+ %tmp.26 = fsub float %tmp.8, %tmp.15
+ %tmp.28 = fadd float %tmp.26, %tmp.20
+ %tmp.30 = fsub float %tmp.28, %tmp.23
+ %tmp.32 = fsub float %tmp.30, %a4
+ %tmp.34 = fsub float %tmp.32, %a2
+ %T = fmul float %tmp.34, %tmp.34
+ ret float %T
+}
+
+; Should be able to eliminate everything.
+define float @test2(float %a0, float %a1, float %a2, float %a3, float %a4) {
+; CHECK-LABEL: test2
+; CHECK: ret float 0.000000e+00
+
+ %tmp.2 = fadd fast float %a4, %a3
+ %tmp.4 = fadd fast float %tmp.2, %a2
+ %tmp.6 = fadd fast float %tmp.4, %a1
+ %tmp.8 = fadd fast float %tmp.6, %a0
+ %tmp.11 = fadd fast float %a3, %a2
+ %tmp.13 = fadd fast float %tmp.11, %a1
+ %tmp.15 = fadd fast float %tmp.13, %a0
+ %tmp.18 = fadd fast float %a2, %a1
+ %tmp.20 = fadd fast float %tmp.18, %a0
+ %tmp.23 = fadd fast float %a1, %a0
+ %tmp.26 = fsub fast float %tmp.8, %tmp.15
+ %tmp.28 = fadd fast float %tmp.26, %tmp.20
+ %tmp.30 = fsub fast float %tmp.28, %tmp.23
+ %tmp.32 = fsub fast float %tmp.30, %a4
+ %tmp.34 = fsub fast float %tmp.32, %a2
+ %T = fmul fast float %tmp.34, %tmp.34
+ ret float %T
+}
diff --git a/llvm/test/Transforms/Reassociate/fast-MissedTree.ll b/llvm/test/Transforms/Reassociate/fast-MissedTree.ll
new file mode 100644
index 00000000000..021c48a293e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-MissedTree.ll
@@ -0,0 +1,39 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+define float @test1(float %A, float %B) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[Z:%.*]] = fadd fast float %A, %B
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd fast float %B, -5.0
+ %Y = fadd fast float %A, 5.0
+ %Z = fadd fast float %W, %Y
+ ret float %Z
+}
+
+; Check again using minimal subset of FMF.
+; Both 'reassoc' and 'nsz' are required.
+define float @test1_reassoc_nsz(float %A, float %B) {
+; CHECK-LABEL: @test1_reassoc_nsz(
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc nsz float %A, %B
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd reassoc nsz float %B, -5.0
+ %Y = fadd reassoc nsz float %A, 5.0
+ %Z = fadd reassoc nsz float %W, %Y
+ ret float %Z
+}
+
+; Verify the fold is not done with only 'reassoc' ('nsz' is required).
+define float @test1_reassoc(float %A, float %B) {
+; CHECK-LABEL: @test1_reassoc(
+; CHECK-NEXT: [[W:%.*]] = fadd reassoc float %B, -5.000000e+00
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc float %A, 5.000000e+00
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[Y]], [[W]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd reassoc float %B, -5.0
+ %Y = fadd reassoc float %A, 5.0
+ %Z = fadd reassoc float %W, %Y
+ ret float %Z
+}
diff --git a/llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll b/llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll
new file mode 100644
index 00000000000..b6926273249
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-ReassociateVector.ll
@@ -0,0 +1,400 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Check that a*c+b*c is turned into (a+b)*c
+
+define <4 x float> @test1(<4 x float> %a, <4 x float> %b, <4 x float> %c) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = fadd fast <4 x float> [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <4 x float> [[REASS_ADD]], [[C:%.*]]
+; CHECK-NEXT: ret <4 x float> [[REASS_MUL]]
+;
+ %mul = fmul fast <4 x float> %a, %c
+ %mul1 = fmul fast <4 x float> %b, %c
+ %add = fadd fast <4 x float> %mul, %mul1
+ ret <4 x float> %add
+}
+
+; Check that a*c+b*c is turned into (a+b)*c - minimum FMF subset version
+
+define <4 x float> @test1_reassoc(<4 x float> %a, <4 x float> %b, <4 x float> %c) {
+; CHECK-LABEL: @test1_reassoc(
+; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc <4 x float> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[MUL1:%.*]] = fmul reassoc <4 x float> [[B:%.*]], [[C]]
+; CHECK-NEXT: [[ADD:%.*]] = fadd reassoc <4 x float> [[MUL]], [[MUL1]]
+; CHECK-NEXT: ret <4 x float> [[ADD]]
+;
+ %mul = fmul reassoc <4 x float> %a, %c
+ %mul1 = fmul reassoc <4 x float> %b, %c
+ %add = fadd reassoc <4 x float> %mul, %mul1
+ ret <4 x float> %add
+}
+
+; Check that a*a*b+a*a*c is turned into a*(a*(b+c)).
+
+define <2 x float> @test2(<2 x float> %a, <2 x float> %b, <2 x float> %c) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = fadd fast <2 x float> [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[REASS_MUL2:%.*]] = fmul fast <2 x float> [[A:%.*]], [[A]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <2 x float> [[REASS_MUL2]], [[REASS_ADD1]]
+; CHECK-NEXT: ret <2 x float> [[REASS_MUL]]
+;
+ %t0 = fmul fast <2 x float> %a, %b
+ %t1 = fmul fast <2 x float> %a, %t0
+ %t2 = fmul fast <2 x float> %a, %c
+ %t3 = fmul fast <2 x float> %a, %t2
+ %t4 = fadd fast <2 x float> %t1, %t3
+ ret <2 x float> %t4
+}
+
+; Check that a*a*b+a*a*c is turned into a*(a*(b+c)) - minimum FMF subset version
+
+define <2 x float> @test2_reassoc(<2 x float> %a, <2 x float> %b, <2 x float> %c) {
+; CHECK-LABEL: @test2_reassoc(
+; CHECK-NEXT: [[T0:%.*]] = fmul reassoc <2 x float> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[T1:%.*]] = fmul reassoc <2 x float> [[A]], [[T0]]
+; CHECK-NEXT: [[T2:%.*]] = fmul reassoc <2 x float> [[A]], [[C:%.*]]
+; CHECK-NEXT: [[T3:%.*]] = fmul reassoc <2 x float> [[A]], [[T2]]
+; CHECK-NEXT: [[T4:%.*]] = fadd reassoc <2 x float> [[T1]], [[T3]]
+; CHECK-NEXT: ret <2 x float> [[T4]]
+;
+ %t0 = fmul reassoc <2 x float> %a, %b
+ %t1 = fmul reassoc <2 x float> %a, %t0
+ %t2 = fmul reassoc <2 x float> %a, %c
+ %t3 = fmul reassoc <2 x float> %a, %t2
+ %t4 = fadd reassoc <2 x float> %t1, %t3
+ ret <2 x float> %t4
+}
+
+; Check that a*b+a*c+d is turned into a*(b+c)+d.
+
+define <2 x double> @test3(<2 x double> %a, <2 x double> %b, <2 x double> %c, <2 x double> %d) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = fadd fast <2 x double> [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <2 x double> [[REASS_ADD]], [[A:%.*]]
+; CHECK-NEXT: [[T3:%.*]] = fadd fast <2 x double> [[REASS_MUL]], [[D:%.*]]
+; CHECK-NEXT: ret <2 x double> [[T3]]
+;
+ %t0 = fmul fast <2 x double> %a, %b
+ %t1 = fmul fast <2 x double> %a, %c
+ %t2 = fadd fast <2 x double> %t1, %d
+ %t3 = fadd fast <2 x double> %t0, %t2
+ ret <2 x double> %t3
+}
+
+; Check that a*b+a*c+d is turned into a*(b+c)+d - minimum FMF subset version
+
+define <2 x double> @test3_reassoc(<2 x double> %a, <2 x double> %b, <2 x double> %c, <2 x double> %d) {
+; CHECK-LABEL: @test3_reassoc(
+; CHECK-NEXT: [[T0:%.*]] = fmul reassoc <2 x double> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[T1:%.*]] = fmul reassoc <2 x double> [[A]], [[C:%.*]]
+; CHECK-NEXT: [[T2:%.*]] = fadd reassoc <2 x double> [[T1]], [[D:%.*]]
+; CHECK-NEXT: [[T3:%.*]] = fadd reassoc <2 x double> [[T0]], [[T2]]
+; CHECK-NEXT: ret <2 x double> [[T3]]
+;
+ %t0 = fmul reassoc <2 x double> %a, %b
+ %t1 = fmul reassoc <2 x double> %a, %c
+ %t2 = fadd reassoc <2 x double> %t1, %d
+ %t3 = fadd reassoc <2 x double> %t0, %t2
+ ret <2 x double> %t3
+}
+
+; No fast-math.
+
+define <2 x float> @test4(<2 x float> %A) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[X:%.*]] = fadd <2 x float> [[A:%.*]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: [[Y:%.*]] = fadd <2 x float> [[A]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[X]], [[Y]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %X = fadd <2 x float> %A, < float 1.000000e+00, float 1.000000e+00 >
+ %Y = fadd <2 x float> %A, < float 1.000000e+00, float 1.000000e+00 >
+ %R = fsub <2 x float> %X, %Y
+ ret <2 x float> %R
+}
+
+; Check 47*X + 47*X -> 94*X.
+
+define <2 x float> @test5(<2 x float> %X) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast <2 x float> [[X:%.*]], <float 9.400000e+01, float 9.400000e+01>
+; CHECK-NEXT: ret <2 x float> [[FACTOR]]
+;
+ %Y = fmul fast <2 x float> %X, <float 4.700000e+01, float 4.700000e+01>
+ %Z = fadd fast <2 x float> %Y, %Y
+ ret <2 x float> %Z
+}
+
+; Check 47*X + 47*X -> 94*X - minimum FMF subset version
+
+define <2 x float> @test5_reassoc(<2 x float> %X) {
+; CHECK-LABEL: @test5_reassoc(
+; CHECK-NEXT: [[Y:%.*]] = fmul reassoc <2 x float> [[X:%.*]], <float 4.700000e+01, float 4.700000e+01>
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc <2 x float> [[Y]], [[Y]]
+; CHECK-NEXT: ret <2 x float> [[Z]]
+;
+ %Y = fmul reassoc <2 x float> %X, <float 4.700000e+01, float 4.700000e+01>
+ %Z = fadd reassoc <2 x float> %Y, %Y
+ ret <2 x float> %Z
+}
+
+; Check X+X+X -> 3*X.
+
+define <2 x float> @test6(<2 x float> %X) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast <2 x float> [[X:%.*]], <float 3.000000e+00, float 3.000000e+00>
+; CHECK-NEXT: ret <2 x float> [[FACTOR]]
+;
+ %Y = fadd fast <2 x float> %X ,%X
+ %Z = fadd fast <2 x float> %Y, %X
+ ret <2 x float> %Z
+}
+
+; Check X+X+X -> 3*X - minimum FMF subset version
+
+define <2 x float> @test6_reassoc(<2 x float> %X) {
+; CHECK-LABEL: @test6_reassoc(
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc <2 x float> [[X:%.*]], [[X]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc <2 x float> [[X]], [[Y]]
+; CHECK-NEXT: ret <2 x float> [[Z]]
+;
+ %Y = fadd reassoc <2 x float> %X ,%X
+ %Z = fadd reassoc <2 x float> %Y, %X
+ ret <2 x float> %Z
+}
+
+; Check 127*W+50*W -> 177*W.
+
+define <2 x double> @test7(<2 x double> %W) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <2 x double> [[W:%.*]], <double 1.770000e+02, double 1.770000e+02>
+; CHECK-NEXT: ret <2 x double> [[REASS_MUL]]
+;
+ %X = fmul fast <2 x double> %W, <double 127.0, double 127.0>
+ %Y = fmul fast <2 x double> %W, <double 50.0, double 50.0>
+ %Z = fadd fast <2 x double> %Y, %X
+ ret <2 x double> %Z
+}
+
+; Check 127*W+50*W -> 177*W - minimum FMF subset version
+
+define <2 x double> @test7_reassoc(<2 x double> %W) {
+; CHECK-LABEL: @test7_reassoc(
+; CHECK-NEXT: [[X:%.*]] = fmul reassoc <2 x double> [[W:%.*]], <double 1.270000e+02, double 1.270000e+02>
+; CHECK-NEXT: [[Y:%.*]] = fmul reassoc <2 x double> [[W]], <double 5.000000e+01, double 5.000000e+01>
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc <2 x double> [[Y]], [[X]]
+; CHECK-NEXT: ret <2 x double> [[Z]]
+;
+ %X = fmul reassoc <2 x double> %W, <double 127.0, double 127.0>
+ %Y = fmul reassoc <2 x double> %W, <double 50.0, double 50.0>
+ %Z = fadd reassoc <2 x double> %Y, %X
+ ret <2 x double> %Z
+}
+
+; Check X*12*12 -> X*144.
+
+define <2 x float> @test8(<2 x float> %arg) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast <2 x float> [[ARG:%.*]], <float 1.440000e+02, float 1.440000e+02>
+; CHECK-NEXT: ret <2 x float> [[TMP2]]
+;
+ %tmp1 = fmul fast <2 x float> <float 1.200000e+01, float 1.200000e+01>, %arg
+ %tmp2 = fmul fast <2 x float> %tmp1, <float 1.200000e+01, float 1.200000e+01>
+ ret <2 x float> %tmp2
+}
+
+; Check X*12*12 -> X*144 - minimum FMF subset version
+
+define <2 x float> @test8_reassoc(<2 x float> %arg) {
+; CHECK-LABEL: @test8_reassoc(
+; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc <2 x float> [[ARG:%.*]], <float 1.200000e+01, float 1.200000e+01>
+; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc <2 x float> [[TMP1]], <float 1.200000e+01, float 1.200000e+01>
+; CHECK-NEXT: ret <2 x float> [[TMP2]]
+;
+ %tmp1 = fmul reassoc <2 x float> <float 1.200000e+01, float 1.200000e+01>, %arg
+ %tmp2 = fmul reassoc <2 x float> %tmp1, <float 1.200000e+01, float 1.200000e+01>
+ ret <2 x float> %tmp2
+}
+
+; Check (b+(a+1234))+-a -> b+1234.
+
+define <2 x double> @test9(<2 x double> %b, <2 x double> %a) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: [[TMP1:%.*]] = fsub fast <2 x double> zeroinitializer, [[A:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = fadd fast <2 x double> [[B:%.*]], <double 1.234000e+03, double 1.234000e+03>
+; CHECK-NEXT: ret <2 x double> [[TMP2]]
+;
+ %1 = fadd fast <2 x double> %a, <double 1.234000e+03, double 1.234000e+03>
+ %2 = fadd fast <2 x double> %b, %1
+ %3 = fsub fast <2 x double> <double 0.000000e+00, double 0.000000e+00>, %a
+ %4 = fadd fast <2 x double> %2, %3
+ ret <2 x double> %4
+}
+
+; Check (b+(a+1234))+-a -> b+1234 - minimum FMF subset version
+
+define <2 x double> @test9_reassoc(<2 x double> %b, <2 x double> %a) {
+; CHECK-LABEL: @test9_reassoc(
+; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc <2 x double> [[A:%.*]], <double 1.234000e+03, double 1.234000e+03>
+; CHECK-NEXT: [[TMP2:%.*]] = fadd reassoc <2 x double> [[B:%.*]], [[TMP1]]
+; CHECK-NEXT: [[TMP3:%.*]] = fsub reassoc <2 x double> zeroinitializer, [[A]]
+; CHECK-NEXT: [[TMP4:%.*]] = fadd reassoc <2 x double> [[TMP3]], [[TMP2]]
+; CHECK-NEXT: ret <2 x double> [[TMP4]]
+;
+ %1 = fadd reassoc <2 x double> %a, <double 1.234000e+03, double 1.234000e+03>
+ %2 = fadd reassoc <2 x double> %b, %1
+ %3 = fsub reassoc <2 x double> <double 0.000000e+00, double 0.000000e+00>, %a
+ %4 = fadd reassoc <2 x double> %2, %3
+ ret <2 x double> %4
+}
+
+; Check -(-(z*40)*a) -> a*40*z.
+
+define <2 x float> @test10(<2 x float> %a, <2 x float> %b, <2 x float> %z) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: [[TMP1:%.*]] = fsub fast <2 x float> zeroinitializer, zeroinitializer
+; CHECK-NEXT: [[E:%.*]] = fmul fast <2 x float> [[A:%.*]], <float 4.000000e+01, float 4.000000e+01>
+; CHECK-NEXT: [[F:%.*]] = fmul fast <2 x float> [[E]], [[Z:%.*]]
+; CHECK-NEXT: ret <2 x float> [[F]]
+;
+ %d = fmul fast <2 x float> %z, <float 4.000000e+01, float 4.000000e+01>
+ %c = fsub fast <2 x float> <float 0.000000e+00, float 0.000000e+00>, %d
+ %e = fmul fast <2 x float> %a, %c
+ %f = fsub fast <2 x float> <float 0.000000e+00, float 0.000000e+00>, %e
+ ret <2 x float> %f
+}
+
+; Check -(-(z*40)*a) -> a*40*z - minimum FMF subset version
+
+define <2 x float> @test10_reassoc(<2 x float> %a, <2 x float> %b, <2 x float> %z) {
+; CHECK-LABEL: @test10_reassoc(
+; CHECK-NEXT: [[D:%.*]] = fmul reassoc <2 x float> [[Z:%.*]], <float 4.000000e+01, float 4.000000e+01>
+; CHECK-NEXT: [[C:%.*]] = fsub reassoc <2 x float> zeroinitializer, [[D]]
+; CHECK-NEXT: [[E:%.*]] = fmul reassoc <2 x float> [[A:%.*]], [[C]]
+; CHECK-NEXT: [[F:%.*]] = fsub reassoc <2 x float> zeroinitializer, [[E]]
+; CHECK-NEXT: ret <2 x float> [[F]]
+;
+ %d = fmul reassoc <2 x float> %z, <float 4.000000e+01, float 4.000000e+01>
+ %c = fsub reassoc <2 x float> <float 0.000000e+00, float 0.000000e+00>, %d
+ %e = fmul reassoc <2 x float> %a, %c
+ %f = fsub reassoc <2 x float> <float 0.000000e+00, float 0.000000e+00>, %e
+ ret <2 x float> %f
+}
+
+; Check x*y+y*x -> x*y*2.
+
+define <2 x double> @test11(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast <2 x double> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast <2 x double> [[FACTOR]], <double 2.000000e+00, double 2.000000e+00>
+; CHECK-NEXT: ret <2 x double> [[REASS_MUL]]
+;
+ %1 = fmul fast <2 x double> %x, %y
+ %2 = fmul fast <2 x double> %y, %x
+ %3 = fadd fast <2 x double> %1, %2
+ ret <2 x double> %3
+}
+
+; Check x*y+y*x -> x*y*2 - minimum FMF subset version
+
+define <2 x double> @test11_reassoc(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @test11_reassoc(
+; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc <2 x double> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc <2 x double> [[X]], [[Y]]
+; CHECK-NEXT: [[TMP3:%.*]] = fadd reassoc <2 x double> [[TMP1]], [[TMP2]]
+; CHECK-NEXT: ret <2 x double> [[TMP3]]
+;
+ %1 = fmul reassoc <2 x double> %x, %y
+ %2 = fmul reassoc <2 x double> %y, %x
+ %3 = fadd reassoc <2 x double> %1, %2
+ ret <2 x double> %3
+}
+
+; FIXME: shifts should be converted to mul to assist further reassociation.
+
+define <2 x i64> @test12(<2 x i64> %b, <2 x i64> %c) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[MUL:%.*]] = mul <2 x i64> [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i64> [[MUL]], <i64 5, i64 5>
+; CHECK-NEXT: ret <2 x i64> [[SHL]]
+;
+ %mul = mul <2 x i64> %c, %b
+ %shl = shl <2 x i64> %mul, <i64 5, i64 5>
+ ret <2 x i64> %shl
+}
+
+; FIXME: expressions with a negative const should be canonicalized to assist
+; further reassociation.
+; We would expect (-5*b)+a -> a-(5*b) but only the constant operand is commuted.
+
+define <4 x float> @test13(<4 x float> %a, <4 x float> %b) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[MUL:%.*]] = fmul fast <4 x float> [[B:%.*]], <float -5.000000e+00, float -5.000000e+00, float -5.000000e+00, float -5.000000e+00>
+; CHECK-NEXT: [[ADD:%.*]] = fadd fast <4 x float> [[MUL]], [[A:%.*]]
+; CHECK-NEXT: ret <4 x float> [[ADD]]
+;
+ %mul = fmul fast <4 x float> <float -5.000000e+00, float -5.000000e+00, float -5.000000e+00, float -5.000000e+00>, %b
+ %add = fadd fast <4 x float> %mul, %a
+ ret <4 x float> %add
+}
+
+; Break up subtract to assist further reassociation.
+; Check a+b-c -> a+b+-c.
+
+define <2 x i64> @test14(<2 x i64> %a, <2 x i64> %b, <2 x i64> %c) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i64> [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[C_NEG:%.*]] = sub <2 x i64> zeroinitializer, [[C:%.*]]
+; CHECK-NEXT: [[SUB:%.*]] = add <2 x i64> [[ADD]], [[C_NEG]]
+; CHECK-NEXT: ret <2 x i64> [[SUB]]
+;
+ %add = add <2 x i64> %b, %a
+ %sub = sub <2 x i64> %add, %c
+ ret <2 x i64> %sub
+}
+
+define <2 x i32> @test15(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[TMP3]]
+;
+ %tmp1 = and <2 x i32> %x, %y
+ %tmp2 = and <2 x i32> %y, %x
+ %tmp3 = and <2 x i32> %tmp1, %tmp2
+ ret <2 x i32> %tmp3
+}
+
+define <2 x i32> @test16(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: [[TMP3:%.*]] = or <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[TMP3]]
+;
+ %tmp1 = or <2 x i32> %x, %y
+ %tmp2 = or <2 x i32> %y, %x
+ %tmp3 = or <2 x i32> %tmp1, %tmp2
+ ret <2 x i32> %tmp3
+}
+
+define <2 x i32> @test17(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT: ret <2 x i32> zeroinitializer
+;
+ %tmp1 = xor <2 x i32> %x, %y
+ %tmp2 = xor <2 x i32> %y, %x
+ %tmp3 = xor <2 x i32> %tmp1, %tmp2
+ ret <2 x i32> %tmp3
+}
+
+define <2 x i32> @test18(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT: [[TMP5:%.*]] = xor <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[TMP5]]
+;
+ %tmp1 = xor <2 x i32> %x, %y
+ %tmp2 = xor <2 x i32> %y, %x
+ %tmp3 = xor <2 x i32> %x, %y
+ %tmp4 = xor <2 x i32> %tmp1, %tmp2
+ %tmp5 = xor <2 x i32> %tmp4, %tmp3
+ ret <2 x i32> %tmp5
+}
diff --git a/llvm/test/Transforms/Reassociate/fast-SubReassociate.ll b/llvm/test/Transforms/Reassociate/fast-SubReassociate.ll
new file mode 100644
index 00000000000..9b2b55746db
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-SubReassociate.ll
@@ -0,0 +1,119 @@
+; RUN: opt < %s -reassociate -constprop -instcombine -S | FileCheck %s
+
+define float @test1(float %A, float %B) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[W:%.*]] = fadd float %B, 5.000000e+00
+; CHECK-NEXT: [[X:%.*]] = fadd float %A, -7.000000e+00
+; CHECK-NEXT: [[Y:%.*]] = fsub float [[X]], [[W]]
+; CHECK-NEXT: [[Z:%.*]] = fadd float [[Y]], 1.200000e+01
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd float 5.0, %B
+ %X = fadd float -7.0, %A
+ %Y = fsub float %X, %W
+ %Z = fadd float %Y, 12.0
+ ret float %Z
+}
+
+; With sub reassociation, constant folding can eliminate all of the constants.
+define float @test2(float %A, float %B) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[Z:%.*]] = fsub fast float %A, %B
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd fast float %B, 5.000000e+00
+ %X = fadd fast float %A, -7.000000e+00
+ %Y = fsub fast float %X, %W
+ %Z = fadd fast float %Y, 1.200000e+01
+ ret float %Z
+}
+
+; Check again using minimal subset of FMF.
+; Both 'reassoc' and 'nsz' are required.
+define float @test2_minimal(float %A, float %B) {
+; CHECK-LABEL: @test2_minimal(
+; CHECK-NEXT: [[Z:%.*]] = fsub reassoc nsz float %A, %B
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd reassoc nsz float %B, 5.000000e+00
+ %X = fadd reassoc nsz float %A, -7.000000e+00
+ %Y = fsub reassoc nsz float %X, %W
+ %Z = fadd reassoc nsz float %Y, 1.200000e+01
+ ret float %Z
+}
+
+; Verify the fold is not done with only 'reassoc' ('nsz' is required).
+define float @test2_reassoc(float %A, float %B) {
+; CHECK-LABEL: @test2_reassoc(
+; CHECK-NEXT: [[W:%.*]] = fadd reassoc float %B, 5.000000e+00
+; CHECK-NEXT: [[X:%.*]] = fadd reassoc float %A, -7.000000e+00
+; CHECK-NEXT: [[Y:%.*]] = fsub reassoc float [[X]], [[W]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[Y]], 1.200000e+01
+; CHECK-NEXT: ret float [[Z]]
+;
+ %W = fadd reassoc float %B, 5.000000e+00
+ %X = fadd reassoc float %A, -7.000000e+00
+ %Y = fsub reassoc float %X, %W
+ %Z = fadd reassoc float %Y, 1.200000e+01
+ ret float %Z
+}
+
+define float @test3(float %A, float %B, float %C, float %D) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[M:%.*]] = fadd float %A, 1.200000e+01
+; CHECK-NEXT: [[N:%.*]] = fadd float [[M]], %B
+; CHECK-NEXT: [[O:%.*]] = fadd float [[N]], %C
+; CHECK-NEXT: [[P:%.*]] = fsub float %D, [[O]]
+; CHECK-NEXT: [[Q:%.*]] = fadd float [[P]], 1.200000e+01
+; CHECK-NEXT: ret float [[Q]]
+;
+ %M = fadd float %A, 1.200000e+01
+ %N = fadd float %M, %B
+ %O = fadd float %N, %C
+ %P = fsub float %D, %O
+ %Q = fadd float %P, 1.200000e+01
+ ret float %Q
+}
+
+; With sub reassociation, constant folding can eliminate the two 12 constants.
+
+define float @test4(float %A, float %B, float %C, float %D) {
+; FIXME: InstCombine should be able to get us to the following:
+; %sum = fadd fast float %B, %A
+; %sum1 = fadd fast float %sum, %C
+; %Q = fsub fast float %D, %sum1
+; ret i32 %Q
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[B_NEG:%.*]] = fsub fast float -0.000000e+00, %B
+; CHECK-NEXT: [[O_NEG:%.*]] = fsub fast float [[B_NEG]], %A
+; CHECK-NEXT: [[P:%.*]] = fsub fast float [[O_NEG]], %C
+; CHECK-NEXT: [[Q:%.*]] = fadd fast float [[P]], %D
+; CHECK-NEXT: ret float [[Q]]
+;
+ %M = fadd fast float 1.200000e+01, %A
+ %N = fadd fast float %M, %B
+ %O = fadd fast float %N, %C
+ %P = fsub fast float %D, %O
+ %Q = fadd fast float 1.200000e+01, %P
+ ret float %Q
+}
+
+; Check again using minimal subset of FMF.
+
+define float @test4_reassoc(float %A, float %B, float %C, float %D) {
+; CHECK-LABEL: @test4_reassoc(
+; CHECK-NEXT: [[M:%.*]] = fadd reassoc float %A, 1.200000e+01
+; CHECK-NEXT: [[N:%.*]] = fadd reassoc float [[M]], %B
+; CHECK-NEXT: [[O:%.*]] = fadd reassoc float [[N]], %C
+; CHECK-NEXT: [[P:%.*]] = fsub reassoc float %D, [[O]]
+; CHECK-NEXT: [[Q:%.*]] = fadd reassoc float [[P]], 1.200000e+01
+; CHECK-NEXT: ret float [[Q]]
+;
+ %M = fadd reassoc float 1.200000e+01, %A
+ %N = fadd reassoc float %M, %B
+ %O = fadd reassoc float %N, %C
+ %P = fsub reassoc float %D, %O
+ %Q = fadd reassoc float 1.200000e+01, %P
+ ret float %Q
+}
+
diff --git a/llvm/test/Transforms/Reassociate/fast-basictest.ll b/llvm/test/Transforms/Reassociate/fast-basictest.ll
new file mode 100644
index 00000000000..ad94a793817
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-basictest.ll
@@ -0,0 +1,606 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -gvn -instcombine -S | FileCheck %s
+
+; With reassociation, constant folding can eliminate the 12 and -12 constants.
+define float @test1(float %arg) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[ARG_NEG:%.*]] = fsub fast float -0.000000e+00, [[ARG:%.*]]
+; CHECK-NEXT: ret float [[ARG_NEG]]
+;
+ %t1 = fsub fast float -1.200000e+01, %arg
+ %t2 = fadd fast float %t1, 1.200000e+01
+ ret float %t2
+}
+
+; Check again using the minimal subset of FMF.
+; Both 'reassoc' and 'nsz' are required.
+define float @test1_minimal(float %arg) {
+; CHECK-LABEL: @test1_minimal(
+; CHECK-NEXT: [[ARG_NEG:%.*]] = fsub reassoc nsz float -0.000000e+00, [[ARG:%.*]]
+; CHECK-NEXT: ret float [[ARG_NEG]]
+;
+ %t1 = fsub reassoc nsz float -1.200000e+01, %arg
+ %t2 = fadd reassoc nsz float %t1, 1.200000e+01
+ ret float %t2
+}
+
+; Verify the fold is not done with only 'reassoc' ('nsz' is required).
+define float @test1_reassoc(float %arg) {
+; CHECK-LABEL: @test1_reassoc(
+; CHECK-NEXT: [[T1:%.*]] = fsub reassoc float -1.200000e+01, [[ARG:%.*]]
+; CHECK-NEXT: [[T2:%.*]] = fadd reassoc float [[T1]], 1.200000e+01
+; CHECK-NEXT: ret float [[T2]]
+;
+ %t1 = fsub reassoc float -1.200000e+01, %arg
+ %t2 = fadd reassoc float %t1, 1.200000e+01
+ ret float %t2
+}
+
+define float @test2(float %reg109, float %reg1111) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[REG115:%.*]] = fadd float [[REG109:%.*]], -3.000000e+01
+; CHECK-NEXT: [[REG116:%.*]] = fadd float [[REG115]], [[REG1111:%.*]]
+; CHECK-NEXT: [[REG117:%.*]] = fadd float [[REG116]], 3.000000e+01
+; CHECK-NEXT: ret float [[REG117]]
+;
+ %reg115 = fadd float %reg109, -3.000000e+01
+ %reg116 = fadd float %reg115, %reg1111
+ %reg117 = fadd float %reg116, 3.000000e+01
+ ret float %reg117
+}
+
+define float @test3(float %reg109, float %reg1111) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[REG117:%.*]] = fadd fast float [[REG109:%.*]], [[REG1111:%.*]]
+; CHECK-NEXT: ret float [[REG117]]
+;
+ %reg115 = fadd fast float %reg109, -3.000000e+01
+ %reg116 = fadd fast float %reg115, %reg1111
+ %reg117 = fadd fast float %reg116, 3.000000e+01
+ ret float %reg117
+}
+
+define float @test3_reassoc(float %reg109, float %reg1111) {
+; CHECK-LABEL: @test3_reassoc(
+; CHECK-NEXT: [[REG115:%.*]] = fadd reassoc float [[REG109:%.*]], -3.000000e+01
+; CHECK-NEXT: [[REG116:%.*]] = fadd reassoc float [[REG115]], [[REG1111:%.*]]
+; CHECK-NEXT: [[REG117:%.*]] = fadd reassoc float [[REG116]], 3.000000e+01
+; CHECK-NEXT: ret float [[REG117]]
+;
+ %reg115 = fadd reassoc float %reg109, -3.000000e+01
+ %reg116 = fadd reassoc float %reg115, %reg1111
+ %reg117 = fadd reassoc float %reg116, 3.000000e+01
+ ret float %reg117
+}
+
+@fe = external global float
+@fa = external global float
+@fb = external global float
+@fc = external global float
+@ff = external global float
+
+define void @test4() {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[A:%.*]] = load float, float* @fa, align 4
+; CHECK-NEXT: [[B:%.*]] = load float, float* @fb, align 4
+; CHECK-NEXT: [[C:%.*]] = load float, float* @fc, align 4
+; CHECK-NEXT: [[T1:%.*]] = fadd fast float [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = fadd fast float [[T1]], [[C]]
+; CHECK-NEXT: store float [[T2]], float* @fe, align 4
+; CHECK-NEXT: store float [[T2]], float* @ff, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load float, float* @fa
+ %B = load float, float* @fb
+ %C = load float, float* @fc
+ %t1 = fadd fast float %A, %B
+ %t2 = fadd fast float %t1, %C
+ %t3 = fadd fast float %C, %A
+ %t4 = fadd fast float %t3, %B
+ ; e = (a+b)+c;
+ store float %t2, float* @fe
+ ; f = (a+c)+b
+ store float %t4, float* @ff
+ ret void
+}
+
+define void @test5() {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[A:%.*]] = load float, float* @fa, align 4
+; CHECK-NEXT: [[B:%.*]] = load float, float* @fb, align 4
+; CHECK-NEXT: [[C:%.*]] = load float, float* @fc, align 4
+; CHECK-NEXT: [[T1:%.*]] = fadd fast float [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = fadd fast float [[T1]], [[C]]
+; CHECK-NEXT: store float [[T2]], float* @fe, align 4
+; CHECK-NEXT: store float [[T2]], float* @ff, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load float, float* @fa
+ %B = load float, float* @fb
+ %C = load float, float* @fc
+ %t1 = fadd fast float %A, %B
+ %t2 = fadd fast float %t1, %C
+ %t3 = fadd fast float %C, %A
+ %t4 = fadd fast float %t3, %B
+ ; e = c+(a+b)
+ store float %t2, float* @fe
+ ; f = (c+a)+b
+ store float %t4, float* @ff
+ ret void
+}
+
+define void @test6() {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: [[A:%.*]] = load float, float* @fa, align 4
+; CHECK-NEXT: [[B:%.*]] = load float, float* @fb, align 4
+; CHECK-NEXT: [[C:%.*]] = load float, float* @fc, align 4
+; CHECK-NEXT: [[T1:%.*]] = fadd fast float [[B]], [[A]]
+; CHECK-NEXT: [[T2:%.*]] = fadd fast float [[T1]], [[C]]
+; CHECK-NEXT: store float [[T2]], float* @fe, align 4
+; CHECK-NEXT: store float [[T2]], float* @ff, align 4
+; CHECK-NEXT: ret void
+;
+ %A = load float, float* @fa
+ %B = load float, float* @fb
+ %C = load float, float* @fc
+ %t1 = fadd fast float %B, %A
+ %t2 = fadd fast float %t1, %C
+ %t3 = fadd fast float %C, %A
+ %t4 = fadd fast float %t3, %B
+ ; e = c+(b+a)
+ store float %t2, float* @fe
+ ; f = (c+a)+b
+ store float %t4, float* @ff
+ ret void
+}
+
+define float @test7(float %A, float %B, float %C) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = fadd fast float [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[REASS_MUL2:%.*]] = fmul fast float [[A:%.*]], [[A]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_MUL2]], [[REASS_ADD1]]
+; CHECK-NEXT: ret float [[REASS_MUL]]
+;
+ %aa = fmul fast float %A, %A
+ %aab = fmul fast float %aa, %B
+ %ac = fmul fast float %A, %C
+ %aac = fmul fast float %ac, %A
+ %r = fadd fast float %aab, %aac
+ ret float %r
+}
+
+define float @test7_reassoc(float %A, float %B, float %C) {
+; CHECK-LABEL: @test7_reassoc(
+; CHECK-NEXT: [[AA:%.*]] = fmul reassoc float [[A:%.*]], [[A]]
+; CHECK-NEXT: [[AAB:%.*]] = fmul reassoc float [[AA]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[A]], [[A]]
+; CHECK-NEXT: [[AAC:%.*]] = fmul reassoc float [[TMP1]], [[C:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fadd reassoc float [[AAB]], [[AAC]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %aa = fmul reassoc float %A, %A
+ %aab = fmul reassoc float %aa, %B
+ %ac = fmul reassoc float %A, %C
+ %aac = fmul reassoc float %ac, %A
+ %r = fadd reassoc float %aab, %aac
+ ret float %r
+}
+
+; (-X)*Y + Z -> Z-X*Y
+
+define float @test8(float %X, float %Y, float %Z) {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT: [[A:%.*]] = fmul fast float [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[C:%.*]] = fsub fast float [[Z:%.*]], [[A]]
+; CHECK-NEXT: ret float [[C]]
+;
+ %A = fsub fast float 0.0, %X
+ %B = fmul fast float %A, %Y
+ %C = fadd fast float %B, %Z
+ ret float %C
+}
+
+define float @test8_reassoc(float %X, float %Y, float %Z) {
+; CHECK-LABEL: @test8_reassoc(
+; CHECK-NEXT: [[A:%.*]] = fsub reassoc float 0.000000e+00, [[X:%.*]]
+; CHECK-NEXT: [[B:%.*]] = fmul reassoc float [[A]], [[Y:%.*]]
+; CHECK-NEXT: [[C:%.*]] = fadd reassoc float [[B]], [[Z:%.*]]
+; CHECK-NEXT: ret float [[C]]
+;
+ %A = fsub reassoc float 0.0, %X
+ %B = fmul reassoc float %A, %Y
+ %C = fadd reassoc float %B, %Z
+ ret float %C
+}
+
+define float @test9(float %X) {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float [[X:%.*]], 9.400000e+01
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %Y = fmul fast float %X, 4.700000e+01
+ %Z = fadd fast float %Y, %Y
+ ret float %Z
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @test9_reassoc_nsz(float %X) {
+; CHECK-LABEL: @test9_reassoc_nsz(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul reassoc nsz float [[X:%.*]], 9.400000e+01
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %Y = fmul reassoc nsz float %X, 4.700000e+01
+ %Z = fadd reassoc nsz float %Y, %Y
+ ret float %Z
+}
+
+; TODO: This doesn't require 'nsz'. It should fold to X * 94.0
+define float @test9_reassoc(float %X) {
+; CHECK-LABEL: @test9_reassoc(
+; CHECK-NEXT: [[Y:%.*]] = fmul reassoc float [[X:%.*]], 4.700000e+01
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[Y]], [[Y]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %Y = fmul reassoc float %X, 4.700000e+01
+ %Z = fadd reassoc float %Y, %Y
+ ret float %Z
+}
+
+; Side note: (x + x + x) and (3*x) each have only a single rounding. So
+; transforming x+x+x to 3*x is always safe, even without any FMF.
+; To avoid that special-case, we have the addition of 'x' four times, here.
+define float @test10(float %X) {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float [[X:%.*]], 4.000000e+00
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %Y = fadd fast float %X ,%X
+ %Z = fadd fast float %Y, %X
+ %W = fadd fast float %Z, %X
+ ret float %W
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @test10_reassoc_nsz(float %X) {
+; CHECK-LABEL: @test10_reassoc_nsz(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul reassoc nsz float [[X:%.*]], 4.000000e+00
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %Y = fadd reassoc nsz float %X ,%X
+ %Z = fadd reassoc nsz float %Y, %X
+ %W = fadd reassoc nsz float %Z, %X
+ ret float %W
+}
+
+; TODO: This doesn't require 'nsz'. It should fold to 4 * x
+define float @test10_reassoc(float %X) {
+; CHECK-LABEL: @test10_reassoc(
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc float [[X:%.*]], [[X]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[Y]], [[X]]
+; CHECK-NEXT: [[W:%.*]] = fadd reassoc float [[Z]], [[X]]
+; CHECK-NEXT: ret float [[W]]
+;
+ %Y = fadd reassoc float %X ,%X
+ %Z = fadd reassoc float %Y, %X
+ %W = fadd reassoc float %Z, %X
+ ret float %W
+}
+
+define float @test11(float %W) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float [[W:%.*]], 3.810000e+02
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %X = fmul fast float %W, 127.0
+ %Y = fadd fast float %X ,%X
+ %Z = fadd fast float %Y, %X
+ ret float %Z
+}
+
+; Check again using the minimal subset of FMF.
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @test11_reassoc_nsz(float %W) {
+; CHECK-LABEL: @test11_reassoc_nsz(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul reassoc nsz float [[W:%.*]], 3.810000e+02
+; CHECK-NEXT: ret float [[FACTOR]]
+;
+ %X = fmul reassoc nsz float %W, 127.0
+ %Y = fadd reassoc nsz float %X ,%X
+ %Z = fadd reassoc nsz float %Y, %X
+ ret float %Z
+}
+
+; TODO: This doesn't require 'nsz'. It should fold to W*381.0.
+define float @test11_reassoc(float %W) {
+; CHECK-LABEL: @test11_reassoc(
+; CHECK-NEXT: [[X:%.*]] = fmul reassoc float [[W:%.*]], 1.270000e+02
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc float [[X]], [[X]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[X]], [[Y]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %X = fmul reassoc float %W, 127.0
+ %Y = fadd reassoc float %X ,%X
+ %Z = fadd reassoc float %Y, %X
+ ret float %Z
+}
+
+define float @test12(float %X) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float [[X:%.*]], -3.000000e+00
+; CHECK-NEXT: [[Z:%.*]] = fadd fast float [[FACTOR]], 6.000000e+00
+; CHECK-NEXT: ret float [[Z]]
+;
+ %A = fsub fast float 1.000000e+00, %X
+ %B = fsub fast float 2.000000e+00, %X
+ %C = fsub fast float 3.000000e+00, %X
+ %Y = fadd fast float %A ,%B
+ %Z = fadd fast float %Y, %C
+ ret float %Z
+}
+
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @test12_reassoc_nsz(float %X) {
+; CHECK-LABEL: @test12_reassoc_nsz(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul reassoc nsz float [[X:%.*]], 3.000000e+00
+; CHECK-NEXT: [[Z:%.*]] = fsub reassoc nsz float 6.000000e+00, [[FACTOR]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %A = fsub reassoc nsz float 1.000000e+00, %X
+ %B = fsub reassoc nsz float 2.000000e+00, %X
+ %C = fsub reassoc nsz float 3.000000e+00, %X
+ %Y = fadd reassoc nsz float %A ,%B
+ %Z = fadd reassoc nsz float %Y, %C
+ ret float %Z
+}
+
+; TODO: This doesn't require 'nsz'. It should fold to (6.0 - 3.0*x)
+define float @test12_reassoc(float %X) {
+; CHECK-LABEL: @test12_reassoc(
+; CHECK-NEXT: [[A:%.*]] = fsub reassoc float 1.000000e+00, [[X:%.*]]
+; CHECK-NEXT: [[B:%.*]] = fsub reassoc float 2.000000e+00, [[X]]
+; CHECK-NEXT: [[C:%.*]] = fsub reassoc float 3.000000e+00, [[X]]
+; CHECK-NEXT: [[Y:%.*]] = fadd reassoc float [[A]], [[B]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[C]], [[Y]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %A = fsub reassoc float 1.000000e+00, %X
+ %B = fsub reassoc float 2.000000e+00, %X
+ %C = fsub reassoc float 3.000000e+00, %X
+ %Y = fadd reassoc float %A ,%B
+ %Z = fadd reassoc float %Y, %C
+ ret float %Z
+}
+
+define float @test13(float %X1, float %X2, float %X3) {
+; CHECK-LABEL: @test13(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = fsub fast float [[X3:%.*]], [[X2:%.*]]
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_ADD]], [[X1:%.*]]
+; CHECK-NEXT: ret float [[REASS_MUL]]
+;
+ %A = fsub fast float 0.000000e+00, %X1
+ %B = fmul fast float %A, %X2 ; -X1*X2
+ %C = fmul fast float %X1, %X3 ; X1*X3
+ %D = fadd fast float %B, %C ; -X1*X2 + X1*X3 -> X1*(X3-X2)
+ ret float %D
+}
+
+define float @test13_reassoc(float %X1, float %X2, float %X3) {
+; CHECK-LABEL: @test13_reassoc(
+; CHECK-NEXT: [[A:%.*]] = fsub reassoc float 0.000000e+00, [[X1:%.*]]
+; CHECK-NEXT: [[B:%.*]] = fmul reassoc float [[A]], [[X2:%.*]]
+; CHECK-NEXT: [[C:%.*]] = fmul reassoc float [[X1]], [[X3:%.*]]
+; CHECK-NEXT: [[D:%.*]] = fadd reassoc float [[B]], [[C]]
+; CHECK-NEXT: ret float [[D]]
+;
+ %A = fsub reassoc float 0.000000e+00, %X1
+ %B = fmul reassoc float %A, %X2 ; -X1*X2
+ %C = fmul reassoc float %X1, %X3 ; X1*X3
+ %D = fadd reassoc float %B, %C ; -X1*X2 + X1*X3 -> X1*(X3-X2)
+ ret float %D
+}
+
+define float @test14(float %X1, float %X2) {
+; CHECK-LABEL: @test14(
+; CHECK-NEXT: [[TMP1:%.*]] = fsub fast float [[X1:%.*]], [[X2:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast float [[TMP1]], 4.700000e+01
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %B = fmul fast float %X1, 47. ; X1*47
+ %C = fmul fast float %X2, -47. ; X2*-47
+ %D = fadd fast float %B, %C ; X1*47 + X2*-47 -> 47*(X1-X2)
+ ret float %D
+}
+
+; (x1 * 47) + (x2 * -47) => (x1 - x2) * 47
+; Check again with 'reassoc' and 'nsz' ('nsz' not technically required).
+define float @test14_reassoc_nsz(float %X1, float %X2) {
+; CHECK-LABEL: @test14_reassoc_nsz(
+; CHECK-NEXT: [[TMP1:%.*]] = fsub reassoc nsz float [[X1:%.*]], [[X2:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc nsz float [[TMP1]], 4.700000e+01
+; CHECK-NEXT: ret float [[TMP2]]
+;
+ %B = fmul reassoc nsz float %X1, 47. ; X1*47
+ %C = fmul reassoc nsz float %X2, -47. ; X2*-47
+ %D = fadd reassoc nsz float %B, %C ; X1*47 + X2*-47 -> 47*(X1-X2)
+ ret float %D
+}
+
+; TODO: This doesn't require 'nsz'. It should fold to ((x1 - x2) * 47.0)
+define float @test14_reassoc(float %X1, float %X2) {
+; CHECK-LABEL: @test14_reassoc(
+; CHECK-NEXT: [[B:%.*]] = fmul reassoc float [[X1:%.*]], 4.700000e+01
+; CHECK-NEXT: [[C:%.*]] = fmul reassoc float [[X2:%.*]], 4.700000e+01
+; CHECK-NEXT: [[D1:%.*]] = fsub reassoc float [[B]], [[C]]
+; CHECK-NEXT: ret float [[D1]]
+;
+ %B = fmul reassoc float %X1, 47. ; X1*47
+ %C = fmul reassoc float %X2, -47. ; X2*-47
+ %D = fadd reassoc float %B, %C ; X1*47 + X2*-47 -> 47*(X1-X2)
+ ret float %D
+}
+
+define float @test15(float %arg) {
+; CHECK-LABEL: @test15(
+; CHECK-NEXT: [[T2:%.*]] = fmul fast float [[ARG:%.*]], 1.440000e+02
+; CHECK-NEXT: ret float [[T2]]
+;
+ %t1 = fmul fast float 1.200000e+01, %arg
+ %t2 = fmul fast float %t1, 1.200000e+01
+ ret float %t2
+}
+
+define float @test15_reassoc(float %arg) {
+; CHECK-LABEL: @test15_reassoc(
+; CHECK-NEXT: [[T2:%.*]] = fmul reassoc float [[ARG:%.*]], 1.440000e+02
+; CHECK-NEXT: ret float [[T2]]
+;
+ %t1 = fmul reassoc float 1.200000e+01, %arg
+ %t2 = fmul reassoc float %t1, 1.200000e+01
+ ret float %t2
+}
+
+; (b+(a+1234))+-a -> b+1234
+define float @test16(float %b, float %a) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: [[TMP1:%.*]] = fadd fast float [[B:%.*]], 1.234000e+03
+; CHECK-NEXT: ret float [[TMP1]]
+;
+ %1 = fadd fast float %a, 1234.0
+ %2 = fadd fast float %b, %1
+ %3 = fsub fast float 0.0, %a
+ %4 = fadd fast float %2, %3
+ ret float %4
+}
+
+define float @test16_reassoc(float %b, float %a) {
+; CHECK-LABEL: @test16_reassoc(
+; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc float [[A:%.*]], 1.234000e+03
+; CHECK-NEXT: [[TMP2:%.*]] = fadd reassoc float [[TMP1]], [[B:%.*]]
+; CHECK-NEXT: [[TMP3:%.*]] = fsub reassoc float 0.000000e+00, [[A]]
+; CHECK-NEXT: [[TMP4:%.*]] = fadd reassoc float [[TMP3]], [[TMP2]]
+; CHECK-NEXT: ret float [[TMP4]]
+;
+ %1 = fadd reassoc float %a, 1234.0
+ %2 = fadd reassoc float %b, %1
+ %3 = fsub reassoc float 0.0, %a
+ %4 = fadd reassoc float %2, %3
+ ret float %4
+}
+
+; Test that we can turn things like X*-(Y*Z) -> X*-1*Y*Z.
+
+define float @test17(float %a, float %b, float %z) {
+; CHECK-LABEL: @test17(
+; CHECK-NEXT: [[E:%.*]] = fmul fast float [[A:%.*]], 1.234500e+04
+; CHECK-NEXT: [[F:%.*]] = fmul fast float [[E]], [[B:%.*]]
+; CHECK-NEXT: [[G:%.*]] = fmul fast float [[F]], [[Z:%.*]]
+; CHECK-NEXT: ret float [[G]]
+;
+ %c = fsub fast float 0.000000e+00, %z
+ %d = fmul fast float %a, %b
+ %e = fmul fast float %c, %d
+ %f = fmul fast float %e, 1.234500e+04
+ %g = fsub fast float 0.000000e+00, %f
+ ret float %g
+}
+
+define float @test17_reassoc(float %a, float %b, float %z) {
+; CHECK-LABEL: @test17_reassoc(
+; CHECK-NEXT: [[C:%.*]] = fsub reassoc float 0.000000e+00, [[Z:%.*]]
+; CHECK-NEXT: [[D:%.*]] = fmul reassoc float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[E:%.*]] = fmul reassoc float [[D]], [[C]]
+; CHECK-NEXT: [[F:%.*]] = fmul reassoc float [[E]], 1.234500e+04
+; CHECK-NEXT: [[G:%.*]] = fsub reassoc float 0.000000e+00, [[F]]
+; CHECK-NEXT: ret float [[G]]
+;
+ %c = fsub reassoc float 0.000000e+00, %z
+ %d = fmul reassoc float %a, %b
+ %e = fmul reassoc float %c, %d
+ %f = fmul reassoc float %e, 1.234500e+04
+ %g = fsub reassoc float 0.000000e+00, %f
+ ret float %g
+}
+
+define float @test18(float %a, float %b, float %z) {
+; CHECK-LABEL: @test18(
+; CHECK-NEXT: [[E:%.*]] = fmul fast float [[A:%.*]], 4.000000e+01
+; CHECK-NEXT: [[F:%.*]] = fmul fast float [[E]], [[Z:%.*]]
+; CHECK-NEXT: ret float [[F]]
+;
+ %d = fmul fast float %z, 4.000000e+01
+ %c = fsub fast float 0.000000e+00, %d
+ %e = fmul fast float %a, %c
+ %f = fsub fast float 0.000000e+00, %e
+ ret float %f
+}
+
+define float @test18_reassoc(float %a, float %b, float %z) {
+; CHECK-LABEL: @test18_reassoc(
+; CHECK-NEXT: [[D:%.*]] = fmul reassoc float [[Z:%.*]], 4.000000e+01
+; CHECK-NEXT: [[C:%.*]] = fsub reassoc float 0.000000e+00, [[D]]
+; CHECK-NEXT: [[E:%.*]] = fmul reassoc float [[C]], [[A:%.*]]
+; CHECK-NEXT: [[F:%.*]] = fsub reassoc float 0.000000e+00, [[E]]
+; CHECK-NEXT: ret float [[F]]
+;
+ %d = fmul reassoc float %z, 4.000000e+01
+ %c = fsub reassoc float 0.000000e+00, %d
+ %e = fmul reassoc float %a, %c
+ %f = fsub reassoc float 0.000000e+00, %e
+ ret float %f
+}
+
+; With sub reassociation, constant folding can eliminate the 12 and -12 constants.
+define float @test19(float %A, float %B) {
+; CHECK-LABEL: @test19(
+; CHECK-NEXT: [[Z:%.*]] = fsub fast float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret float [[Z]]
+;
+ %X = fadd fast float -1.200000e+01, %A
+ %Y = fsub fast float %X, %B
+ %Z = fadd fast float %Y, 1.200000e+01
+ ret float %Z
+}
+
+define float @test19_reassoc(float %A, float %B) {
+; CHECK-LABEL: @test19_reassoc(
+; CHECK-NEXT: [[X:%.*]] = fadd reassoc float [[A:%.*]], -1.200000e+01
+; CHECK-NEXT: [[Y:%.*]] = fsub reassoc float [[X]], [[B:%.*]]
+; CHECK-NEXT: [[Z:%.*]] = fadd reassoc float [[Y]], 1.200000e+01
+; CHECK-NEXT: ret float [[Z]]
+;
+ %X = fadd reassoc float -1.200000e+01, %A
+ %Y = fsub reassoc float %X, %B
+ %Z = fadd reassoc float %Y, 1.200000e+01
+ ret float %Z
+}
+
+; With sub reassociation, constant folding can eliminate the uses of %a.
+define float @test20(float %a, float %b, float %c) nounwind {
+; FIXME: Should be able to generate the below, which may expose more
+; opportunites for FAdd reassociation.
+; %sum = fadd fast float %c, %b
+; %t7 = fsub fast float 0, %sum
+; CHECK-LABEL: @test20(
+; CHECK-NEXT: [[B_NEG:%.*]] = fsub fast float -0.000000e+00, [[B:%.*]]
+; CHECK-NEXT: [[T7:%.*]] = fsub fast float [[B_NEG]], [[C:%.*]]
+; CHECK-NEXT: ret float [[T7]]
+;
+ %t3 = fsub fast float %a, %b
+ %t5 = fsub fast float %t3, %c
+ %t7 = fsub fast float %t5, %a
+ ret float %t7
+}
+
+define float @test20_reassoc(float %a, float %b, float %c) nounwind {
+; CHECK-LABEL: @test20_reassoc(
+; CHECK-NEXT: [[T3:%.*]] = fsub reassoc float [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[T5:%.*]] = fsub reassoc float [[T3]], [[C:%.*]]
+; CHECK-NEXT: [[T7:%.*]] = fsub reassoc float [[T5]], [[A]]
+; CHECK-NEXT: ret float [[T7]]
+;
+ %t3 = fsub reassoc float %a, %b
+ %t5 = fsub reassoc float %t3, %c
+ %t7 = fsub reassoc float %t5, %a
+ ret float %t7
+}
+
diff --git a/llvm/test/Transforms/Reassociate/fast-fp-commute.ll b/llvm/test/Transforms/Reassociate/fast-fp-commute.ll
new file mode 100644
index 00000000000..c623abdde11
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-fp-commute.ll
@@ -0,0 +1,46 @@
+; RUN: opt -reassociate -S < %s | FileCheck %s
+
+declare void @use(float)
+
+define void @test1(float %x, float %y) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float %y, %x
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast float %y, %x
+; CHECK-NEXT: [[TMP3:%.*]] = fsub fast float [[TMP1]], [[TMP2]]
+; CHECK-NEXT: call void @use(float [[TMP1]])
+; CHECK-NEXT: call void @use(float [[TMP3]])
+; CHECK-NEXT: ret void
+;
+ %1 = fmul fast float %x, %y
+ %2 = fmul fast float %y, %x
+ %3 = fsub fast float %1, %2
+ call void @use(float %1)
+ call void @use(float %3)
+ ret void
+}
+
+define float @test2(float %x, float %y) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float %y, %x
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast float %y, %x
+; CHECK-NEXT: [[TMP3:%.*]] = fsub fast float [[TMP1]], [[TMP2]]
+; CHECK-NEXT: ret float [[TMP3]]
+;
+ %1 = fmul fast float %x, %y
+ %2 = fmul fast float %y, %x
+ %3 = fsub fast float %1, %2
+ ret float %3
+}
+
+define float @test3(float %x, float %y) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float %y, %x
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[FACTOR]], 2.000000e+00
+; CHECK-NEXT: ret float [[REASS_MUL]]
+;
+ %1 = fmul fast float %x, %y
+ %2 = fmul fast float %y, %x
+ %3 = fadd fast float %1, %2
+ ret float %3
+}
+
diff --git a/llvm/test/Transforms/Reassociate/fast-mightymul.ll b/llvm/test/Transforms/Reassociate/fast-mightymul.ll
new file mode 100644
index 00000000000..98bdf7a55ac
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-mightymul.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -reassociate -disable-output
+; PR13021
+
+define float @test2(float %x) {
+ %t0 = fmul fast float %x, %x
+ %t1 = fmul fast float %t0, %t0
+ %t2 = fmul fast float %t1, %t1
+ %t3 = fmul fast float %t2, %t2
+ %t4 = fmul fast float %t3, %t3
+ %t5 = fmul fast float %t4, %t4
+ %t6 = fmul fast float %t5, %t5
+ %t7 = fmul fast float %t6, %t6
+ %t8 = fmul fast float %t7, %t7
+ %t9 = fmul fast float %t8, %t8
+ %t10 = fmul fast float %t9, %t9
+ %t11 = fmul fast float %t10, %t10
+ %t12 = fmul fast float %t11, %t11
+ %t13 = fmul fast float %t12, %t12
+ %t14 = fmul fast float %t13, %t13
+ %t15 = fmul fast float %t14, %t14
+ %t16 = fmul fast float %t15, %t15
+ %t17 = fmul fast float %t16, %t16
+ %t18 = fmul fast float %t17, %t17
+ %t19 = fmul fast float %t18, %t18
+ %t20 = fmul fast float %t19, %t19
+ %t21 = fmul fast float %t20, %t20
+ %t22 = fmul fast float %t21, %t21
+ %t23 = fmul fast float %t22, %t22
+ %t24 = fmul fast float %t23, %t23
+ %t25 = fmul fast float %t24, %t24
+ %t26 = fmul fast float %t25, %t25
+ %t27 = fmul fast float %t26, %t26
+ %t28 = fmul fast float %t27, %t27
+ ret float %t28
+}
diff --git a/llvm/test/Transforms/Reassociate/fast-multistep.ll b/llvm/test/Transforms/Reassociate/fast-multistep.ll
new file mode 100644
index 00000000000..6f2290f1c88
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fast-multistep.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Check that a*a*b+a*a*c is turned into a*(a*(b+c)).
+
+define float @fmultistep1(float %a, float %b, float %c) {
+; CHECK-LABEL: @fmultistep1(
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = fadd fast float %c, %b
+; CHECK-NEXT: [[REASS_MUL2:%.*]] = fmul fast float %a, %a
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_MUL:%.*]]2, [[REASS_ADD1]]
+; CHECK-NEXT: ret float [[REASS_MUL]]
+;
+ %t0 = fmul fast float %a, %b
+ %t1 = fmul fast float %a, %t0 ; a*(a*b)
+ %t2 = fmul fast float %a, %c
+ %t3 = fmul fast float %a, %t2 ; a*(a*c)
+ %t4 = fadd fast float %t1, %t3
+ ret float %t4
+}
+
+; Check that a*b+a*c+d is turned into a*(b+c)+d.
+
+define float @fmultistep2(float %a, float %b, float %c, float %d) {
+; CHECK-LABEL: @fmultistep2(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = fadd fast float %c, %b
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_ADD]], %a
+; CHECK-NEXT: [[T3:%.*]] = fadd fast float [[REASS_MUL]], %d
+; CHECK-NEXT: ret float [[T3]]
+;
+ %t0 = fmul fast float %a, %b
+ %t1 = fmul fast float %a, %c
+ %t2 = fadd fast float %t1, %d ; a*c+d
+ %t3 = fadd fast float %t0, %t2 ; a*b+(a*c+d)
+ ret float %t3
+}
+
diff --git a/llvm/test/Transforms/Reassociate/fp-commute.ll b/llvm/test/Transforms/Reassociate/fp-commute.ll
new file mode 100644
index 00000000000..eac5b5920ac
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fp-commute.ll
@@ -0,0 +1,19 @@
+; RUN: opt -reassociate -S < %s | FileCheck %s
+
+declare void @use(float)
+
+define void @test1(float %x, float %y) {
+; CHECK-LABEL: test1
+; CHECK: fmul float %x, %y
+; CHECK: fmul float %x, %y
+; CHECK: fsub float %1, %2
+; CHECK: call void @use(float %{{.*}})
+; CHECK: call void @use(float %{{.*}})
+
+ %1 = fmul float %x, %y
+ %2 = fmul float %y, %x
+ %3 = fsub float %1, %2
+ call void @use(float %1)
+ call void @use(float %3)
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/fp-expr.ll b/llvm/test/Transforms/Reassociate/fp-expr.ll
new file mode 100644
index 00000000000..e616c52f28e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/fp-expr.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -reassociate < %s | FileCheck %s
+
+define void @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[T1:%.*]] = tail call <4 x float> @blam()
+; CHECK-NEXT: [[T1_NEG:%.*]] = fsub fast <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[T1]]
+; CHECK-NEXT: [[T24:%.*]] = fadd fast <4 x float> [[T1_NEG]], undef
+; CHECK-NEXT: tail call void @wombat(<4 x float> [[T24]])
+; CHECK-NEXT: ret void
+;
+ %t1 = tail call <4 x float> @blam()
+ %t23 = fsub fast <4 x float> undef, %t1
+ %t24 = fadd fast <4 x float> %t23, undef
+ tail call void @wombat(<4 x float> %t24)
+ ret void
+}
+
+define half @test2() {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[T15:%.*]] = fsub fast half undef, undef
+; CHECK-NEXT: [[T15_NEG:%.*]] = fsub fast half 0xH8000, [[T15]]
+; CHECK-NEXT: [[T18:%.*]] = fadd fast half [[T15_NEG]], undef
+; CHECK-NEXT: ret half [[T18]]
+;
+ %t15 = fsub fast half undef, undef
+ %t17 = fsub fast half undef, %t15
+ %t18 = fadd fast half undef, %t17
+ ret half %t18
+}
+
+
+
+; Function Attrs: optsize
+declare <4 x float> @blam()
+
+; Function Attrs: optsize
+declare void @wombat(<4 x float>)
+
diff --git a/llvm/test/Transforms/Reassociate/infloop-deadphi.ll b/llvm/test/Transforms/Reassociate/infloop-deadphi.ll
new file mode 100644
index 00000000000..c5a45a4f7eb
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/infloop-deadphi.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -reassociate %s -S | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+; CHECK-LABEL: @f(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[DONE:%.*]]
+; CHECK: dead:
+; CHECK-NEXT: [[XOR0:%.*]] = xor i16 [[XOR1:%.*]], undef
+; CHECK-NEXT: [[XOR1]] = xor i16 [[XOR0]], undef
+; CHECK-NEXT: br i1 undef, label [[DEAD:%.*]], label [[DONE]]
+; CHECK: done:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %done
+
+dead:
+ %xor0 = xor i16 %xor1, undef
+ %xor1 = xor i16 %xor0, undef
+ br i1 undef, label %dead, label %done
+
+done:
+ %e = phi i16 [ %xor1, %dead ], [ 0, %entry ]
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/inverses.ll b/llvm/test/Transforms/Reassociate/inverses.ll
new file mode 100644
index 00000000000..14753b1724b
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/inverses.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -die -S | FileCheck %s
+
+; (A&B)&~A == 0
+define i32 @test1(i32 %a, i32 %b) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: ret i32 0
+;
+ %t2 = and i32 %b, %a
+ %t4 = xor i32 %a, -1
+ %t5 = and i32 %t2, %t4
+ ret i32 %t5
+}
+
+define <2 x i32> @not_op_vec_undef(<2 x i32> %a, <2 x i32> %b) {
+; CHECK-LABEL: @not_op_vec_undef(
+; CHECK-NEXT: ret <2 x i32> zeroinitializer
+;
+ %t2 = and <2 x i32> %b, %a
+ %t4 = xor <2 x i32> %a, <i32 -1, i32 undef>
+ %t5 = and <2 x i32> %t2, %t4
+ ret <2 x i32> %t5
+}
+
+; A&~A == 0
+define i32 @test2(i32 %a, i32 %b) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: ret i32 0
+;
+ %t1 = and i32 %a, 1234
+ %t2 = and i32 %b, %t1
+ %t4 = xor i32 %a, -1
+ %t5 = and i32 %t2, %t4
+ ret i32 %t5
+}
+
+; (b+(a+1234))+-a -> b+1234
+define i32 @test3(i32 %b, i32 %a) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[T5:%.*]] = add i32 [[B:%.*]], 1234
+; CHECK-NEXT: ret i32 [[T5]]
+;
+ %t1 = add i32 %a, 1234
+ %t2 = add i32 %b, %t1
+ %t4 = sub i32 0, %a
+ %t5 = add i32 %t2, %t4
+ ret i32 %t5
+}
+
+; (b+(a+1234))+~a -> b+1233
+define i32 @test4(i32 %b, i32 %a) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[T5:%.*]] = add i32 [[B:%.*]], 1233
+; CHECK-NEXT: ret i32 [[T5]]
+;
+ %t1 = add i32 %a, 1234
+ %t2 = add i32 %b, %t1
+ %t4 = xor i32 %a, -1
+ %t5 = add i32 %t2, %t4
+ ret i32 %t5
+}
+
diff --git a/llvm/test/Transforms/Reassociate/keep-debug-loc.ll b/llvm/test/Transforms/Reassociate/keep-debug-loc.ll
new file mode 100644
index 00000000000..1a1031f3584
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/keep-debug-loc.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -reassociate < %s | FileCheck %s
+
+; PR34231
+;
+; Verify that the original debug location is kept if the
+; replacement debug location is missing when
+; reassociating expressions.
+
+define i16 @fn1() !dbg !3 {
+ ret i16 undef
+}
+
+define void @fn2() !dbg !6 {
+; CHECK-LABEL: @fn2
+; CHECK: call i16 @fn1(), !dbg ![[LOC1:[0-9]+]]
+; CHECK-NOT: or i16
+ %inlinable_call = call i16 @fn1(), !dbg !7
+ %dbgless_instruction = or i16 %inlinable_call, 0
+ store i16 %dbgless_instruction, i16* undef, align 1
+ unreachable
+}
+
+define void @fn3() !dbg !8 {
+; CHECK-LABEL: @fn3
+; CHECK: load i16, i16* undef, !dbg ![[LOC2:[0-9]+]]
+; CHECK-NOT: or i16
+ %instruction = load i16, i16* undef, !dbg !9
+ %dbgless_instruction = or i16 %instruction, 0
+ store i16 %dbgless_instruction, i16* undef, align 1
+ unreachable
+}
+
+; CHECK: ![[LOC1]] = !DILocation(line: 7
+; CHECK: ![[LOC2]] = !DILocation(line: 9
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly)
+!1 = !DIFile(filename: "foo.c", directory: "/")
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0)
+!4 = !DISubroutineType(types: !5)
+!5 = !{}
+!6 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 3, type: !4, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0)
+!7 = !DILocation(line: 7, column: 10, scope: !6)
+!8 = distinct !DISubprogram(name: "fn3", scope: !1, file: !1, line: 8, type: !4, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0)
+!9 = !DILocation(line: 9, column: 10, scope: !8)
diff --git a/llvm/test/Transforms/Reassociate/long-chains.ll b/llvm/test/Transforms/Reassociate/long-chains.ll
new file mode 100644
index 00000000000..b0de1c6719e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/long-chains.ll
@@ -0,0 +1,37 @@
+; RUN: opt < %s -reassociate -stats -S 2>&1 | FileCheck %s
+; REQUIRES: asserts
+
+define i8 @longchain(i8 %in1, i8 %in2, i8 %in3, i8 %in4, i8 %in5, i8 %in6, i8 %in7, i8 %in8, i8 %in9, i8 %in10, i8 %in11, i8 %in12, i8 %in13, i8 %in14, i8 %in15, i8 %in16, i8 %in17, i8 %in18, i8 %in19, i8 %in20) {
+ %tmp1 = add i8 %in1, %in2
+ %tmp2 = add i8 %tmp1, %in3
+ %tmp3 = add i8 %tmp2, %in4
+ %tmp4 = add i8 %tmp3, %in3
+ %tmp5 = add i8 %tmp4, %in4
+ %tmp6 = add i8 %tmp5, %in5
+ %tmp7 = add i8 %tmp6, %in6
+ %tmp8 = add i8 %tmp7, %in7
+ %tmp9 = add i8 %tmp8, %in8
+ %tmp10 = add i8 %tmp9, %in9
+ %tmp11 = add i8 %tmp10, %in10
+ %tmp12 = add i8 %tmp11, %in11
+ %tmp13 = add i8 %tmp12, %in12
+ %tmp14 = add i8 %tmp13, %in13
+ %tmp15 = add i8 %tmp14, %in14
+ %tmp16 = add i8 %tmp15, %in15
+ %tmp17 = add i8 %tmp16, %in16
+ %tmp18 = add i8 %tmp17, %in17
+ %tmp19 = add i8 %tmp18, %in18
+ %tmp20 = add i8 %tmp19, %in19
+ %tmp21 = add i8 %tmp20, %in20
+ ret i8 %tmp20
+}
+
+; Check the number of instructions reassociated is in the tens not the hundreds.
+; At the time of writing, the exact numbers were:
+; Bad order: 220 reassociate - Number of insts reassociated
+; Good order: 55 reassociate - Number of insts reassociated
+;
+; CHECK: {{^[1-9][0-9]}} reassociate - Number of insts reassociated
+
+; Additionally check that we made at least three changes.
+; CHECK: {{^ *[3-9]}} reassociate - Number of multiplies factored
diff --git a/llvm/test/Transforms/Reassociate/looptest.ll b/llvm/test/Transforms/Reassociate/looptest.ll
new file mode 100644
index 00000000000..2c3db310571
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/looptest.ll
@@ -0,0 +1,52 @@
+; This testcase comes from this C fragment:
+;
+; void test(unsigned Num, int *Array) {
+; unsigned i, j, k;
+;
+; for (i = 0; i != Num; ++i)
+; for (j = 0; j != Num; ++j)
+; for (k = 0; k != Num; ++k)
+; printf("%d\n", i+k+j); /* Reassociate to (i+j)+k */
+;}
+;
+; In this case, we want to reassociate the specified expr so that i+j can be
+; hoisted out of the inner most loop.
+;
+; RUN: opt < %s -reassociate -S | FileCheck %s
+; END.
+@.LC0 = internal global [4 x i8] c"%d\0A\00" ; <[4 x i8]*> [#uses=1]
+
+declare i32 @printf(i8*, ...)
+
+; Check that (i+j) has been reassociated (i=reg115, j=reg116)
+; CHECK: %reg113 = add i32 %reg116, %reg115
+define void @test(i32 %Num, i32* %Array) {
+bb0:
+ %cond221 = icmp eq i32 0, %Num ; <i1> [#uses=3]
+ br i1 %cond221, label %bb7, label %bb2
+bb2: ; preds = %bb6, %bb0
+ %reg115 = phi i32 [ %reg120, %bb6 ], [ 0, %bb0 ] ; <i32> [#uses=2]
+ br i1 %cond221, label %bb6, label %bb3
+bb3: ; preds = %bb5, %bb2
+ %reg116 = phi i32 [ %reg119, %bb5 ], [ 0, %bb2 ] ; <i32> [#uses=2]
+ br i1 %cond221, label %bb5, label %bb4
+bb4: ; preds = %bb4, %bb3
+ %reg117 = phi i32 [ %reg118, %bb4 ], [ 0, %bb3 ] ; <i32> [#uses=2]
+ %reg113 = add i32 %reg115, %reg117 ; <i32> [#uses=1]
+ %reg114 = add i32 %reg113, %reg116 ; <i32> [#uses=1]
+ %cast227 = getelementptr [4 x i8], [4 x i8]* @.LC0, i64 0, i64 0 ; <i8*> [#uses=1]
+ call i32 (i8*, ...) @printf( i8* %cast227, i32 %reg114 ) ; <i32>:0 [#uses=0]
+ %reg118 = add i32 %reg117, 1 ; <i32> [#uses=2]
+ %cond224 = icmp ne i32 %reg118, %Num ; <i1> [#uses=1]
+ br i1 %cond224, label %bb4, label %bb5
+bb5: ; preds = %bb4, %bb3
+ %reg119 = add i32 %reg116, 1 ; <i32> [#uses=2]
+ %cond225 = icmp ne i32 %reg119, %Num ; <i1> [#uses=1]
+ br i1 %cond225, label %bb3, label %bb6
+bb6: ; preds = %bb5, %bb2
+ %reg120 = add i32 %reg115, 1 ; <i32> [#uses=2]
+ %cond226 = icmp ne i32 %reg120, %Num ; <i1> [#uses=1]
+ br i1 %cond226, label %bb2, label %bb7
+bb7: ; preds = %bb6, %bb0
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/matching-binops.ll b/llvm/test/Transforms/Reassociate/matching-binops.ll
new file mode 100644
index 00000000000..4771e3c8e1c
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/matching-binops.ll
@@ -0,0 +1,359 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; PR37098 - https://bugs.llvm.org/show_bug.cgi?id=37098
+; In all positive tests, we should reassociate binops
+; to allow more factoring folds.
+
+; There are 5 associative integer binops *
+; 13 integer binops *
+; 4 operand commutes =
+; 260 potential variations of this fold
+; for integer binops. There are another 40 for FP.
+; Mix the commutation options to provide coverage using less tests.
+
+define i8 @and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @and_shl(
+; CHECK-NEXT: [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = shl i8 %x, %shamt
+ %sy = shl i8 %y, %shamt
+ %a = and i8 %sx, %z
+ %r = and i8 %sy, %a
+ ret i8 %r
+}
+
+define i8 @or_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @or_shl(
+; CHECK-NEXT: [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = or i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = shl i8 %x, %shamt
+ %sy = shl i8 %y, %shamt
+ %a = or i8 %sx, %z
+ %r = or i8 %a, %sy
+ ret i8 %r
+}
+
+define i8 @xor_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @xor_shl(
+; CHECK-NEXT: [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = shl i8 %x, %shamt
+ %sy = shl i8 %y, %shamt
+ %a = xor i8 %z, %sx
+ %r = xor i8 %a, %sy
+ ret i8 %r
+}
+
+define i8 @and_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @and_lshr(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = lshr i8 %x, %shamt
+ %sy = lshr i8 %y, %shamt
+ %a = and i8 %z, %sx
+ %r = and i8 %sy, %a
+ ret i8 %r
+}
+
+define i8 @or_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @or_lshr(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = or i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = lshr i8 %x, %shamt
+ %sy = lshr i8 %y, %shamt
+ %a = or i8 %sx, %z
+ %r = or i8 %sy, %a
+ ret i8 %r
+}
+
+define i8 @xor_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @xor_lshr(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = lshr i8 %x, %shamt
+ %sy = lshr i8 %y, %shamt
+ %a = xor i8 %sx, %z
+ %r = xor i8 %a, %sy
+ ret i8 %r
+}
+
+define i8 @and_ashr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @and_ashr(
+; CHECK-NEXT: [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = ashr i8 %x, %shamt
+ %sy = ashr i8 %y, %shamt
+ %a = and i8 %z, %sx
+ %r = and i8 %a, %sy
+ ret i8 %r
+}
+
+define i8 @or_ashr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @or_ashr(
+; CHECK-NEXT: [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = or i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = ashr i8 %x, %shamt
+ %sy = ashr i8 %y, %shamt
+ %a = or i8 %z, %sx
+ %r = or i8 %sy, %a
+ ret i8 %r
+}
+
+; Vectors work too.
+
+define <2 x i8> @xor_ashr(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z, <2 x i8> %shamt) {
+; CHECK-LABEL: @xor_ashr(
+; CHECK-NEXT: [[SX:%.*]] = ashr <2 x i8> [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = ashr <2 x i8> [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = xor <2 x i8> [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[A]], [[SY]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %sx = ashr <2 x i8> %x, %shamt
+ %sy = ashr <2 x i8> %y, %shamt
+ %a = xor <2 x i8> %sx, %z
+ %r = xor <2 x i8> %a, %sy
+ ret <2 x i8> %r
+}
+
+; Negative test - different logic ops
+
+define i8 @or_and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @or_and_shl(
+; CHECK-NEXT: [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = shl i8 %x, %shamt
+ %sy = shl i8 %y, %shamt
+ %a = or i8 %sx, %z
+ %r = and i8 %sy, %a
+ ret i8 %r
+}
+
+; Negative test - different shift ops
+
+define i8 @or_lshr_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @or_lshr_shl(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = or i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = lshr i8 %x, %shamt
+ %sy = shl i8 %y, %shamt
+ %a = or i8 %sx, %z
+ %r = or i8 %a, %sy
+ ret i8 %r
+}
+
+; Negative test - multi-use
+
+define i8 @xor_lshr_multiuse(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @xor_lshr_multiuse(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[SY]]
+; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[A]], [[R]]
+; CHECK-NEXT: ret i8 [[R2]]
+;
+ %sx = lshr i8 %x, %shamt
+ %sy = lshr i8 %y, %shamt
+ %a = xor i8 %sx, %z
+ %r = xor i8 %a, %sy
+ %r2 = sdiv i8 %a, %r
+ ret i8 %r2
+}
+
+; Math ops work too. Change instruction positions too to verify placement.
+
+define i8 @add_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
+; CHECK-LABEL: @add_lshr(
+; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
+; CHECK-NEXT: [[A:%.*]] = add i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
+; CHECK-NEXT: [[R:%.*]] = add i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = lshr i8 %x, %shamt
+ %a = add i8 %sx, %z
+ %sy = lshr i8 %y, %shamt
+ %r = add i8 %a, %sy
+ ret i8 %r
+}
+
+; Make sure wrapping flags are cleared.
+
+define i8 @mul_sub(i8 %x, i8 %y, i8 %z, i8 %m) {
+; CHECK-LABEL: @mul_sub(
+; CHECK-NEXT: [[SX:%.*]] = sub i8 [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = sub i8 [[Y:%.*]], [[M]]
+; CHECK-NEXT: [[A:%.*]] = mul nsw i8 [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = mul nuw i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = sub i8 %x, %m
+ %sy = sub i8 %y, %m
+ %a = mul nsw i8 %sx, %z
+ %r = mul nuw i8 %a, %sy
+ ret i8 %r
+}
+
+define i8 @add_mul(i8 %x, i8 %y, i8 %z, i8 %m) {
+; CHECK-LABEL: @add_mul(
+; CHECK-NEXT: [[SX:%.*]] = mul nuw i8 [[X:%.*]], 42
+; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[Z:%.*]], [[SX]]
+; CHECK-NEXT: [[SY:%.*]] = mul nsw i8 [[M:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[A]], [[SY]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = mul nuw i8 %x, 42
+ %a = add nuw i8 %sx, %z
+ %sy = mul nsw i8 %y, %m
+ %r = add nsw i8 %sy, %a
+ ret i8 %r
+}
+
+; Floating-point works too if it's not strict.
+; TODO: These should not require the full 'fast' FMF.
+
+define float @fadd_fmul(float %x, float %y, float %z, float %m) {
+; CHECK-LABEL: @fadd_fmul(
+; CHECK-NEXT: [[SX:%.*]] = fmul float [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT: [[A:%.*]] = fadd fast float [[SX]], [[Z:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = fmul float [[Y:%.*]], [[M]]
+; CHECK-NEXT: [[R:%.*]] = fadd fast float [[A]], [[SY]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %sx = fmul float %x, %m
+ %a = fadd fast float %sx, %z
+ %sy = fmul float %y, %m
+ %r = fadd fast float %sy, %a
+ ret float %r
+}
+
+define float @fmul_fdiv(float %x, float %y, float %z, float %m) {
+; CHECK-LABEL: @fmul_fdiv(
+; CHECK-NEXT: [[SX:%.*]] = fdiv float [[X:%.*]], [[M:%.*]]
+; CHECK-NEXT: [[SY:%.*]] = fdiv float [[Y:%.*]], 4.200000e+01
+; CHECK-NEXT: [[A:%.*]] = fmul fast float [[SY]], [[Z:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fmul fast float [[A]], [[SX]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %sx = fdiv float %x, %m
+ %sy = fdiv float %y, 42.0
+ %a = fmul fast float %z, %sx
+ %r = fmul fast float %sy, %a
+ ret float %r
+}
+
+; Verify that debug info for modified instructions gets discarded (references become undef).
+
+define i32 @and_shl_dbg(i32 %x, i32 %y, i32 %z, i32 %shamt) {
+; CHECK-LABEL: @and_shl_dbg(
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[X:%.*]], metadata !7, metadata !DIExpression()), !dbg !20
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[Y:%.*]], metadata !13, metadata !DIExpression()), !dbg !21
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[Z:%.*]], metadata !14, metadata !DIExpression()), !dbg !22
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[SHAMT:%.*]], metadata !15, metadata !DIExpression()), !dbg !23
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X]], [[SHAMT]], !dbg !24
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[SHL]], metadata !16, metadata !DIExpression()), !dbg !25
+; CHECK-NEXT: [[SHL1:%.*]] = shl i32 [[Y]], [[SHAMT]], !dbg !26
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[SHL1]], metadata !17, metadata !DIExpression()), !dbg !27
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], [[Z]], !dbg !28
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[AND]], metadata !18, metadata !DIExpression()), !dbg !29
+; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND]], [[SHL1]], !dbg !30
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[AND2]], metadata !19, metadata !DIExpression()), !dbg !31
+; CHECK-NEXT: ret i32 [[AND2]], !dbg !32
+;
+ call void @llvm.dbg.value(metadata i32 %x, metadata !13, metadata !DIExpression()), !dbg !21
+ call void @llvm.dbg.value(metadata i32 %y, metadata !14, metadata !DIExpression()), !dbg !22
+ call void @llvm.dbg.value(metadata i32 %z, metadata !15, metadata !DIExpression()), !dbg !23
+ call void @llvm.dbg.value(metadata i32 %shamt, metadata !16, metadata !DIExpression()), !dbg !24
+ %shl = shl i32 %x, %shamt, !dbg !25
+ call void @llvm.dbg.value(metadata i32 %shl, metadata !17, metadata !DIExpression()), !dbg !26
+ %shl1 = shl i32 %y, %shamt, !dbg !27
+ call void @llvm.dbg.value(metadata i32 %shl1, metadata !18, metadata !DIExpression()), !dbg !28
+ %and = and i32 %shl, %z, !dbg !29
+ call void @llvm.dbg.value(metadata i32 %and, metadata !19, metadata !DIExpression()), !dbg !30
+ %and2 = and i32 %and, %shl1, !dbg !31
+ call void @llvm.dbg.value(metadata i32 %and2, metadata !20, metadata !DIExpression()), !dbg !32
+ ret i32 %and2, !dbg !33
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331069)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "ass.c", directory: "/Users/spatel/myllvm/release/bin")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 7.0.0 (trunk 331069)"}
+!8 = distinct !DISubprogram(name: "and_shl_dbg", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11, !11, !11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !15, !16, !17, !18, !19, !20}
+!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11)
+!14 = !DILocalVariable(name: "y", arg: 2, scope: !8, file: !1, line: 1, type: !11)
+!15 = !DILocalVariable(name: "z", arg: 3, scope: !8, file: !1, line: 1, type: !11)
+!16 = !DILocalVariable(name: "shamt", arg: 4, scope: !8, file: !1, line: 1, type: !11)
+!17 = !DILocalVariable(name: "sx", scope: !8, file: !1, line: 2, type: !11)
+!18 = !DILocalVariable(name: "sy", scope: !8, file: !1, line: 3, type: !11)
+!19 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)
+!20 = !DILocalVariable(name: "r", scope: !8, file: !1, line: 5, type: !11)
+!21 = !DILocation(line: 1, column: 21, scope: !8)
+!22 = !DILocation(line: 1, column: 28, scope: !8)
+!23 = !DILocation(line: 1, column: 35, scope: !8)
+!24 = !DILocation(line: 1, column: 42, scope: !8)
+!25 = !DILocation(line: 2, column: 14, scope: !8)
+!26 = !DILocation(line: 2, column: 7, scope: !8)
+!27 = !DILocation(line: 3, column: 14, scope: !8)
+!28 = !DILocation(line: 3, column: 7, scope: !8)
+!29 = !DILocation(line: 4, column: 14, scope: !8)
+!30 = !DILocation(line: 4, column: 7, scope: !8)
+!31 = !DILocation(line: 5, column: 14, scope: !8)
+!32 = !DILocation(line: 5, column: 7, scope: !8)
+!33 = !DILocation(line: 6, column: 3, scope: !8)
+
diff --git a/llvm/test/Transforms/Reassociate/mightymul.ll b/llvm/test/Transforms/Reassociate/mightymul.ll
new file mode 100644
index 00000000000..ae915da8e57
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/mightymul.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -reassociate -disable-output
+; PR13021
+
+define i32 @test1(i32 %x) {
+ %t0 = mul i32 %x, %x
+ %t1 = mul i32 %t0, %t0
+ %t2 = mul i32 %t1, %t1
+ %t3 = mul i32 %t2, %t2
+ %t4 = mul i32 %t3, %t3
+ %t5 = mul i32 %t4, %t4
+ %t6 = mul i32 %t5, %t5
+ %t7 = mul i32 %t6, %t6
+ %t8 = mul i32 %t7, %t7
+ %t9 = mul i32 %t8, %t8
+ %t10 = mul i32 %t9, %t9
+ %t11 = mul i32 %t10, %t10
+ %t12 = mul i32 %t11, %t11
+ %t13 = mul i32 %t12, %t12
+ %t14 = mul i32 %t13, %t13
+ %t15 = mul i32 %t14, %t14
+ %t16 = mul i32 %t15, %t15
+ %t17 = mul i32 %t16, %t16
+ %t18 = mul i32 %t17, %t17
+ %t19 = mul i32 %t18, %t18
+ %t20 = mul i32 %t19, %t19
+ %t21 = mul i32 %t20, %t20
+ %t22 = mul i32 %t21, %t21
+ %t23 = mul i32 %t22, %t22
+ %t24 = mul i32 %t23, %t23
+ %t25 = mul i32 %t24, %t24
+ %t26 = mul i32 %t25, %t25
+ %t27 = mul i32 %t26, %t26
+ %t28 = mul i32 %t27, %t27
+ ret i32 %t28
+}
diff --git a/llvm/test/Transforms/Reassociate/min_int.ll b/llvm/test/Transforms/Reassociate/min_int.ll
new file mode 100644
index 00000000000..52dab3a531f
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/min_int.ll
@@ -0,0 +1,13 @@
+; RUN: opt < %s -reassociate -dce -S | FileCheck %s
+
+; MIN_INT cannot be negated during reassociation
+
+define i32 @minint(i32 %i) {
+; CHECK: %mul = mul i32 %i, -2147483648
+; CHECK-NEXT: %add = add i32 %mul, 1
+; CHECK-NEXT: ret i32 %add
+ %mul = mul i32 %i, -2147483648
+ %add = add i32 %mul, 1
+ ret i32 %add
+}
+
diff --git a/llvm/test/Transforms/Reassociate/mixed-fast-nonfast-fp.ll b/llvm/test/Transforms/Reassociate/mixed-fast-nonfast-fp.ll
new file mode 100644
index 00000000000..14871f45b01
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/mixed-fast-nonfast-fp.ll
@@ -0,0 +1,42 @@
+; RUN: opt -reassociate %s -S | FileCheck %s
+
+define float @foo(float %a,float %b, float %c) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT: [[MUL3:%.*]] = fmul float %a, %b
+; CHECK-NEXT: [[FACTOR:%.*]] = fmul fast float %c, 2.000000e+00
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = fadd fast float [[FACTOR]], %b
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast float [[REASS_ADD1]], %a
+; CHECK-NEXT: [[ADD3:%.*]] = fadd fast float [[REASS_MUL]], [[MUL3]]
+; CHECK-NEXT: ret float [[ADD3]]
+;
+ %mul1 = fmul fast float %a, %c
+ %mul2 = fmul fast float %a, %b
+ %mul3 = fmul float %a, %b ; STRICT
+ %mul4 = fmul fast float %a, %c
+ %add1 = fadd fast float %mul1, %mul3
+ %add2 = fadd fast float %mul4, %mul2
+ %add3 = fadd fast float %add1, %add2
+ ret float %add3
+}
+
+define float @foo_reassoc(float %a,float %b, float %c) {
+; CHECK-LABEL: @foo_reassoc(
+; CHECK-NEXT: [[MUL1:%.*]] = fmul reassoc float %a, %c
+; CHECK-NEXT: [[MUL2:%.*]] = fmul fast float %b, %a
+; CHECK-NEXT: [[MUL3:%.*]] = fmul float %a, %b
+; CHECK-NEXT: [[MUL4:%.*]] = fmul reassoc float %a, %c
+; CHECK-NEXT: [[ADD1:%.*]] = fadd fast float [[MUL1]], [[MUL3]]
+; CHECK-NEXT: [[ADD2:%.*]] = fadd reassoc float [[MUL2]], [[MUL4]]
+; CHECK-NEXT: [[ADD3:%.*]] = fadd fast float [[ADD1]], [[ADD2]]
+; CHECK-NEXT: ret float [[ADD3]]
+;
+ %mul1 = fmul reassoc float %a, %c
+ %mul2 = fmul fast float %a, %b
+ %mul3 = fmul float %a, %b ; STRICT
+ %mul4 = fmul reassoc float %a, %c
+ %add1 = fadd fast float %mul1, %mul3
+ %add2 = fadd reassoc float %mul4, %mul2
+ %add3 = fadd fast float %add1, %add2
+ ret float %add3
+}
+
diff --git a/llvm/test/Transforms/Reassociate/mulfactor.ll b/llvm/test/Transforms/Reassociate/mulfactor.ll
new file mode 100644
index 00000000000..ca0dbcde897
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/mulfactor.ll
@@ -0,0 +1,128 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+define i32 @test1(i32 %a, i32 %b) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[T2:%.*]] = mul i32 %a, %a
+; CHECK-NEXT: [[T6:%.*]] = mul i32 %a, 2
+; CHECK-NEXT: [[REASS_ADD:%.*]] = add i32 [[T6]], %b
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 [[REASS_ADD]], %b
+; CHECK-NEXT: [[T11:%.*]] = add i32 [[REASS_MUL]], [[T2]]
+; CHECK-NEXT: ret i32 [[T11]]
+;
+ %t2 = mul i32 %a, %a
+ %t5 = shl i32 %a, 1
+ %t6 = mul i32 %t5, %b
+ %t8 = mul i32 %b, %b
+ %t7 = add i32 %t6, %t2
+ %t11 = add i32 %t7, %t8
+ ret i32 %t11
+}
+
+define i32 @test2(i32 %t) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i32 %t, 42
+; CHECK-NEXT: [[D:%.*]] = add i32 [[REASS_MUL]], 15
+; CHECK-NEXT: ret i32 [[D]]
+;
+ %a = mul i32 %t, 6
+ %b = mul i32 %t, 36
+ %c = add i32 %b, 15
+ %d = add i32 %c, %a
+ ret i32 %d
+}
+
+; (x^8)
+define i32 @test3(i32 %x) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 %x, %x
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], [[TMP1]]
+; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], [[TMP2]]
+; CHECK-NEXT: ret i32 [[TMP3]]
+;
+ %a = mul i32 %x, %x
+ %b = mul i32 %a, %x
+ %c = mul i32 %b, %x
+ %d = mul i32 %c, %x
+ %e = mul i32 %d, %x
+ %f = mul i32 %e, %x
+ %g = mul i32 %f, %x
+ ret i32 %g
+}
+
+; (x^7)
+define i32 @test4(i32 %x) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 %x, %x
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], %x
+; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], %x
+; CHECK-NEXT: [[F:%.*]] = mul i32 [[TMP3]], [[TMP2]]
+; CHECK-NEXT: ret i32 [[F]]
+;
+ %a = mul i32 %x, %x
+ %b = mul i32 %a, %x
+ %c = mul i32 %b, %x
+ %d = mul i32 %c, %x
+ %e = mul i32 %d, %x
+ %f = mul i32 %e, %x
+ ret i32 %f
+}
+
+; (x^4) * (y^2)
+define i32 @test5(i32 %x, i32 %y) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 %x, %x
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], %y
+; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], [[TMP2]]
+; CHECK-NEXT: ret i32 [[TMP3]]
+;
+ %a = mul i32 %x, %y
+ %b = mul i32 %a, %y
+ %c = mul i32 %b, %x
+ %d = mul i32 %c, %x
+ %e = mul i32 %d, %x
+ ret i32 %e
+}
+
+; (x^5) * (y^3) * z
+define i32 @test6(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 %x, %x
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], %y
+; CHECK-NEXT: [[F:%.*]] = mul i32 %y, %x
+; CHECK-NEXT: [[G:%.*]] = mul i32 [[F]], [[TMP2]]
+; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[G]], [[TMP2]]
+; CHECK-NEXT: [[H:%.*]] = mul i32 [[TMP3]], %z
+; CHECK-NEXT: ret i32 [[H]]
+;
+ %a = mul i32 %x, %y
+ %b = mul i32 %a, %x
+ %c = mul i32 %b, %y
+ %d = mul i32 %c, %x
+ %e = mul i32 %d, %y
+ %f = mul i32 %e, %x
+ %g = mul i32 %f, %z
+ %h = mul i32 %g, %x
+ ret i32 %h
+}
+
+; (x^4) * (y^3) * (z^2)
+define i32 @test7(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT: [[TMP1:%.*]] = mul i32 %x, %x
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], %y
+; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], %z
+; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[TMP3]], %y
+; CHECK-NEXT: [[H:%.*]] = mul i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: ret i32 [[H]]
+;
+ %a = mul i32 %y, %x
+ %b = mul i32 %a, %z
+ %c = mul i32 %b, %z
+ %d = mul i32 %c, %x
+ %e = mul i32 %d, %y
+ %f = mul i32 %e, %y
+ %g = mul i32 %f, %x
+ %h = mul i32 %g, %x
+ ret i32 %h
+}
+
diff --git a/llvm/test/Transforms/Reassociate/multistep.ll b/llvm/test/Transforms/Reassociate/multistep.ll
new file mode 100644
index 00000000000..239ffe08227
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/multistep.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Check that a*a*b+a*a*c is turned into a*(a*(b+c)).
+
+define i64 @multistep1(i64 %a, i64 %b, i64 %c) {
+; CHECK-LABEL: @multistep1(
+; CHECK-NEXT: [[REASS_ADD1:%.*]] = add i64 %c, %b
+; CHECK-NEXT: [[REASS_MUL2:%.*]] = mul i64 %a, %a
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i64 [[REASS_MUL:%.*]]2, [[REASS_ADD1]]
+; CHECK-NEXT: ret i64 [[REASS_MUL]]
+;
+ %t0 = mul i64 %a, %b
+ %t1 = mul i64 %a, %t0 ; a*(a*b)
+ %t2 = mul i64 %a, %c
+ %t3 = mul i64 %a, %t2 ; a*(a*c)
+ %t4 = add i64 %t1, %t3
+ ret i64 %t4
+}
+
+; Check that a*b+a*c+d is turned into a*(b+c)+d.
+
+define i64 @multistep2(i64 %a, i64 %b, i64 %c, i64 %d) {
+; CHECK-LABEL: @multistep2(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = add i64 %c, %b
+; CHECK-NEXT: [[REASS_MUL:%.*]] = mul i64 [[REASS_ADD]], %a
+; CHECK-NEXT: [[T3:%.*]] = add i64 [[REASS_MUL]], %d
+; CHECK-NEXT: ret i64 [[T3]]
+;
+ %t0 = mul i64 %a, %b
+ %t1 = mul i64 %a, %c
+ %t2 = add i64 %t1, %d ; a*c+d
+ %t3 = add i64 %t0, %t2 ; a*b+(a*c+d)
+ ret i64 %t3
+}
+
diff --git a/llvm/test/Transforms/Reassociate/negation.ll b/llvm/test/Transforms/Reassociate/negation.ll
new file mode 100644
index 00000000000..f443083ff3f
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/negation.ll
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+; Test that we can turn things like X*-(Y*Z) -> X*-1*Y*Z.
+
+define i32 @test1(i32 %a, i32 %b, i32 %z) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[E:%.*]] = mul i32 [[A:%.*]], 12345
+; CHECK-NEXT: [[F:%.*]] = mul i32 [[E]], [[B:%.*]]
+; CHECK-NEXT: [[G:%.*]] = mul i32 [[F]], [[Z:%.*]]
+; CHECK-NEXT: ret i32 [[G]]
+;
+ %c = sub i32 0, %z
+ %d = mul i32 %a, %b
+ %e = mul i32 %c, %d
+ %f = mul i32 %e, 12345
+ %g = sub i32 0, %f
+ ret i32 %g
+}
+
+define i32 @test2(i32 %a, i32 %b, i32 %z) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[E:%.*]] = mul i32 [[A:%.*]], 40
+; CHECK-NEXT: [[F:%.*]] = mul i32 [[E]], [[Z:%.*]]
+; CHECK-NEXT: ret i32 [[F]]
+;
+ %d = mul i32 %z, 40
+ %c = sub i32 0, %d
+ %e = mul i32 %a, %c
+ %f = sub i32 0, %e
+ ret i32 %f
+}
+
+define <2 x i32> @negate_vec_undefs(<2 x i32> %a, <2 x i32> %b, <2 x i32> %z) {
+; CHECK-LABEL: @negate_vec_undefs(
+; CHECK-NEXT: [[E:%.*]] = mul <2 x i32> [[A:%.*]], <i32 40, i32 40>
+; CHECK-NEXT: [[F:%.*]] = mul <2 x i32> [[E]], [[Z:%.*]]
+; CHECK-NEXT: ret <2 x i32> [[F]]
+;
+ %d = mul <2 x i32> %z, <i32 40, i32 40>
+ %c = sub <2 x i32> <i32 0, i32 undef>, %d
+ %e = mul <2 x i32> %a, %c
+ %f = sub <2 x i32> <i32 0, i32 undef>, %e
+ ret <2 x i32> %f
+}
+
diff --git a/llvm/test/Transforms/Reassociate/negation1.ll b/llvm/test/Transforms/Reassociate/negation1.ll
new file mode 100644
index 00000000000..674e57df956
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/negation1.ll
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+; Test that we can turn things like A*B + X - A*B -> X.
+
+define i32 @test1(i32 %a, i32 %b, i32 %x) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: ret i32 [[X:%.*]]
+;
+ %c = mul i32 %a, %b
+ %d = add i32 %c, %x
+ %c1 = mul i32 %a, %b
+ %f = sub i32 %d, %c1
+ ret i32 %f
+}
+
diff --git a/llvm/test/Transforms/Reassociate/no-op.ll b/llvm/test/Transforms/Reassociate/no-op.ll
new file mode 100644
index 00000000000..7b02df99464
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/no-op.ll
@@ -0,0 +1,38 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; When there is nothing to do, or not much to do, check that reassociate leaves
+; things alone.
+
+declare void @use(i32)
+
+define void @test1(i32 %a, i32 %b) {
+; Shouldn't change or move any of the add instructions. Should commute but
+; otherwise not change or move any of the mul instructions.
+; CHECK-LABEL: @test1(
+ %a0 = add nsw i32 %a, 1
+; CHECK-NEXT: %a0 = add nsw i32 %a, 1
+ %m0 = mul nsw i32 3, %a
+; CHECK-NEXT: %m0 = mul nsw i32 %a, 3
+ %a1 = add nsw i32 %a0, %b
+; CHECK-NEXT: %a1 = add nsw i32 %a0, %b
+ %m1 = mul nsw i32 %b, %m0
+; CHECK-NEXT: %m1 = mul nsw i32 %m0, %b
+ call void @use(i32 %a1)
+; CHECK-NEXT: call void @use
+ call void @use(i32 %m1)
+ ret void
+}
+
+define void @test2(i32 %a, i32 %b, i32 %c, i32 %d) {
+; The initial add doesn't change so should not lose the nsw flag.
+; CHECK-LABEL: @test2(
+ %a0 = add nsw i32 %b, %a
+; CHECK-NEXT: %a0 = add nsw i32 %b, %a
+ %a1 = add nsw i32 %a0, %d
+; CHECK-NEXT: %a1 = add i32 %a0, %c
+ %a2 = add nsw i32 %a1, %c
+; CHECK-NEXT: %a2 = add i32 %a1, %d
+ call void @use(i32 %a2)
+; CHECK-NEXT: call void @use
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/optional-flags.ll b/llvm/test/Transforms/Reassociate/optional-flags.ll
new file mode 100644
index 00000000000..bf599be78bc
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/optional-flags.ll
@@ -0,0 +1,29 @@
+; RUN: opt -S -reassociate < %s | FileCheck %s
+; rdar://8944681
+
+; Reassociate should clear optional flags like nsw when reassociating.
+
+; CHECK-LABEL: @test0(
+; CHECK: %y = add i64 %b, %a
+; CHECK: %z = add i64 %y, %c
+define i64 @test0(i64 %a, i64 %b, i64 %c) {
+ %y = add nsw i64 %c, %b
+ %z = add i64 %y, %a
+ ret i64 %z
+}
+
+; CHECK-LABEL: @test1(
+; CHECK: %y = add i64 %b, %a
+; CHECK: %z = add i64 %y, %c
+define i64 @test1(i64 %a, i64 %b, i64 %c) {
+ %y = add i64 %c, %b
+ %z = add nsw i64 %y, %a
+ ret i64 %z
+}
+
+; PR9215
+; CHECK: %s = add nsw i32 %y, %x
+define i32 @test2(i32 %x, i32 %y) {
+ %s = add nsw i32 %x, %y
+ ret i32 %s
+}
diff --git a/llvm/test/Transforms/Reassociate/otherops.ll b/llvm/test/Transforms/Reassociate/otherops.ll
new file mode 100644
index 00000000000..7718881d8e5
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/otherops.ll
@@ -0,0 +1,42 @@
+; Reassociation should apply to Add, Mul, And, Or, & Xor
+;
+; RUN: opt < %s -reassociate -constprop -instcombine -die -S | FileCheck %s
+
+define i32 @test_mul(i32 %arg) {
+; CHECK-LABEL: test_mul
+; CHECK-NEXT: %tmp2 = mul i32 %arg, 144
+; CHECK-NEXT: ret i32 %tmp2
+
+ %tmp1 = mul i32 12, %arg
+ %tmp2 = mul i32 %tmp1, 12
+ ret i32 %tmp2
+}
+
+define i32 @test_and(i32 %arg) {
+; CHECK-LABEL: test_and
+; CHECK-NEXT: %tmp2 = and i32 %arg, 14
+; CHECK-NEXT: ret i32 %tmp2
+
+ %tmp1 = and i32 14, %arg
+ %tmp2 = and i32 %tmp1, 14
+ ret i32 %tmp2
+}
+
+define i32 @test_or(i32 %arg) {
+; CHECK-LABEL: test_or
+; CHECK-NEXT: %tmp2 = or i32 %arg, 14
+; CHECK-NEXT: ret i32 %tmp2
+
+ %tmp1 = or i32 14, %arg
+ %tmp2 = or i32 %tmp1, 14
+ ret i32 %tmp2
+}
+
+define i32 @test_xor(i32 %arg) {
+; CHECK-LABEL: test_xor
+; CHECK-NEXT: ret i32 %arg
+
+ %tmp1 = xor i32 12, %arg
+ %tmp2 = xor i32 %tmp1, 12
+ ret i32 %tmp2
+}
diff --git a/llvm/test/Transforms/Reassociate/pointer-collision-non-determinism.ll b/llvm/test/Transforms/Reassociate/pointer-collision-non-determinism.ll
new file mode 100644
index 00000000000..c8eaa7d290f
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/pointer-collision-non-determinism.ll
@@ -0,0 +1,107 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -run-twice -reassociate %s -S -o - | FileCheck %s
+; RUN: opt -run-twice -reassociate %s -S -o - | FileCheck %s
+
+; The PairMap[NumBinaryOps] used by the Reassociate pass used to have Value
+; *pointers as keys and no handling for values being removed. In some cases (in
+; practice very rarely, but in this particular test - well over 50% of the time)
+; a newly created Value would happen to get allocated at the same memory
+; address, effectively "replacing" the key in the map.
+;
+; Test that that doesn't happen anymore and the pass is deterministic.
+;
+; The failure rate of this test (at least, on my 8 core iMac), when ran in the
+; context of other unit tests executed | specifically, I was trying
+;
+; ./bin/llvm-lit -v ../test/Transforms/Reassociate
+;
+; is as follows:
+;
+; # of RUN lines repeated | just -run-twice | -run-twice and CHECK lines
+; ------------------------+-----------------+---------------------------
+; 1 | 30% | <didn't measure>
+; 2 | 55% | 95%
+; 3 | 55% | <didn't measure>
+;
+; hence the specific shape of this test. The IR itself comes from a real-world
+; code, successfully bugpointed.
+
+define float @test(float %arg) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP:%.*]] = fmul fast float [[ARG:%.*]], 0x3FE99999A0000000
+; CHECK-NEXT: [[TMP110:%.*]] = fsub fast float 1.000000e+00, [[TMP]]
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast float [[ARG]], 0x3FE99999A0000000
+; CHECK-NEXT: [[TMP311:%.*]] = fsub fast float 1.000000e+00, [[TMP2]]
+; CHECK-NEXT: [[REASS_MUL160:%.*]] = fmul fast float [[TMP110]], [[ARG]]
+; CHECK-NEXT: [[TMP4:%.*]] = fmul fast float [[REASS_MUL160]], [[TMP311]]
+; CHECK-NEXT: [[TMP5:%.*]] = fadd fast float [[TMP4]], [[ARG]]
+; CHECK-NEXT: [[TMP6:%.*]] = fmul fast float [[TMP5]], [[ARG]]
+; CHECK-NEXT: [[TMP7:%.*]] = fadd fast float [[TMP6]], [[ARG]]
+; CHECK-NEXT: [[TMP8:%.*]] = fmul fast float [[TMP7]], [[ARG]]
+; CHECK-NEXT: [[TMP9:%.*]] = fadd fast float [[TMP8]], [[ARG]]
+; CHECK-NEXT: [[TMP10:%.*]] = fmul fast float [[TMP9]], [[ARG]]
+; CHECK-NEXT: [[TMP11:%.*]] = fadd fast float [[TMP10]], [[ARG]]
+; CHECK-NEXT: [[TMP12:%.*]] = fmul fast float [[TMP11]], [[ARG]]
+; CHECK-NEXT: [[TMP13:%.*]] = fadd fast float [[TMP12]], [[ARG]]
+; CHECK-NEXT: [[TMP14:%.*]] = fmul fast float [[TMP13]], [[ARG]]
+; CHECK-NEXT: [[TMP15:%.*]] = fadd fast float [[TMP14]], [[ARG]]
+; CHECK-NEXT: [[TMP16:%.*]] = fmul fast float [[TMP15]], [[ARG]]
+; CHECK-NEXT: [[TMP17:%.*]] = fadd fast float [[TMP16]], [[ARG]]
+; CHECK-NEXT: [[TMP18:%.*]] = fmul fast float [[TMP17]], [[ARG]]
+; CHECK-NEXT: [[TMP19:%.*]] = fadd fast float [[TMP18]], [[ARG]]
+; CHECK-NEXT: [[TMP20:%.*]] = fmul fast float [[TMP19]], [[ARG]]
+; CHECK-NEXT: [[TMP21:%.*]] = fadd fast float [[TMP20]], [[ARG]]
+; CHECK-NEXT: [[TMP22:%.*]] = fmul fast float [[TMP21]], [[ARG]]
+; CHECK-NEXT: [[TMP23:%.*]] = fadd fast float [[TMP22]], [[ARG]]
+; CHECK-NEXT: [[REASS_MUL166:%.*]] = fmul fast float [[ARG]], [[ARG]]
+; CHECK-NEXT: [[TMP24:%.*]] = fmul fast float [[REASS_MUL166]], [[TMP23]]
+; CHECK-NEXT: [[TMP25:%.*]] = fadd fast float [[TMP24]], [[ARG]]
+; CHECK-NEXT: [[TMP26:%.*]] = fmul fast float [[TMP25]], [[ARG]]
+; CHECK-NEXT: [[TMP27:%.*]] = fadd fast float [[TMP26]], [[ARG]]
+; CHECK-NEXT: [[TMP29:%.*]] = fmul fast float [[ARG]], [[ARG]]
+; CHECK-NEXT: [[TMP31:%.*]] = fmul fast float [[TMP29]], 0x3FEA2E8B80000000
+; CHECK-NEXT: [[TMP33:%.*]] = fmul fast float [[TMP31]], [[TMP27]]
+; CHECK-NEXT: [[TMP34:%.*]] = fadd fast float [[TMP33]], [[ARG]]
+; CHECK-NEXT: ret float [[TMP34]]
+;
+entry:
+ %tmp = fmul fast float %arg, 0xBFE99999A0000000
+ %tmp1 = fadd fast float %tmp, 1.000000e+00
+ %tmp2 = fmul fast float %arg, 0xBFE99999A0000000
+ %tmp3 = fadd fast float %tmp2, 1.000000e+00
+ %reass.mul156 = fmul fast float %arg, %tmp1
+ %reass.mul160 = fmul fast float %arg, %tmp1
+ %tmp4 = fmul fast float %reass.mul160, %tmp3
+ %tmp5 = fadd fast float %arg, %tmp4
+ %tmp6 = fmul fast float %tmp5, %arg
+ %tmp7 = fadd fast float %tmp6, %arg
+ %tmp8 = fmul fast float %tmp7, %arg
+ %tmp9 = fadd fast float %arg, %tmp8
+ %tmp10 = fmul fast float %tmp9, %arg
+ %tmp11 = fadd fast float %tmp10, %arg
+ %tmp12 = fmul fast float %tmp11, %arg
+ %tmp13 = fadd fast float %tmp12, %arg
+ %tmp14 = fmul fast float %tmp13, %arg
+ %tmp15 = fadd fast float %arg, %tmp14
+ %tmp16 = fmul fast float %tmp15, %arg
+ %tmp17 = fadd fast float %tmp16, %arg
+ %tmp18 = fmul fast float %tmp17, %arg
+ %tmp19 = fadd fast float %tmp18, %arg
+ %tmp20 = fmul fast float %tmp19, %arg
+ %tmp21 = fadd fast float %tmp20, %arg
+ %tmp22 = fmul fast float %tmp21, %arg
+ %tmp23 = fadd fast float %tmp22, %arg
+ %reass.mul166 = fmul fast float %arg, %tmp23
+ %tmp24 = fmul fast float %reass.mul166, %arg
+ %tmp25 = fadd fast float %arg, %tmp24
+ %tmp26 = fmul fast float %arg, %tmp25
+ %tmp27 = fadd fast float %tmp26, %arg
+ %tmp28 = fmul fast float %arg, %tmp27
+ %tmp29 = fmul fast float %tmp28, %arg
+ %tmp31 = fmul fast float %tmp29, 0x3FED1745C0000000
+ %tmp33 = fmul fast float %tmp31, 0x3FECCCCCC0000000
+ %tmp34 = fadd fast float %arg, %tmp33
+ ret float %tmp34
+}
+
diff --git a/llvm/test/Transforms/Reassociate/pr12245.ll b/llvm/test/Transforms/Reassociate/pr12245.ll
new file mode 100644
index 00000000000..0e7152e2a17
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/pr12245.ll
@@ -0,0 +1,46 @@
+; RUN: opt < %s -basicaa -inline -instcombine -reassociate -dse -disable-output
+; PR12245
+
+@a = common global i32 0, align 4
+@d = common global i32 0, align 4
+
+define i32 @fn2() nounwind uwtable ssp {
+entry:
+ %0 = load i32, i32* @a, align 4
+ %dec = add nsw i32 %0, -1
+ store i32 %dec, i32* @a, align 4
+ %1 = load i32, i32* @d, align 4
+ %sub = sub nsw i32 %dec, %1
+ store i32 %sub, i32* @d, align 4
+ %2 = load i32, i32* @a, align 4
+ %dec1 = add nsw i32 %2, -1
+ store i32 %dec1, i32* @a, align 4
+ %3 = load i32, i32* @d, align 4
+ %sub2 = sub nsw i32 %dec1, %3
+ store i32 %sub2, i32* @d, align 4
+ %4 = load i32, i32* @a, align 4
+ %dec3 = add nsw i32 %4, -1
+ store i32 %dec3, i32* @a, align 4
+ %5 = load i32, i32* @d, align 4
+ %sub4 = sub nsw i32 %dec3, %5
+ store i32 %sub4, i32* @d, align 4
+ %6 = load i32, i32* @a, align 4
+ %dec5 = add nsw i32 %6, -1
+ store i32 %dec5, i32* @a, align 4
+ %7 = load i32, i32* @d, align 4
+ %sub6 = sub nsw i32 %dec5, %7
+ store i32 %sub6, i32* @d, align 4
+ %8 = load i32, i32* @a, align 4
+ %dec7 = add nsw i32 %8, -1
+ store i32 %dec7, i32* @a, align 4
+ %9 = load i32, i32* @d, align 4
+ %sub8 = sub nsw i32 %dec7, %9
+ store i32 %sub8, i32* @d, align 4
+ ret i32 0
+}
+
+define i32 @fn1() nounwind uwtable ssp {
+entry:
+ %call = call i32 @fn2()
+ ret i32 %call
+}
diff --git a/llvm/test/Transforms/Reassociate/pr21205.ll b/llvm/test/Transforms/Reassociate/pr21205.ll
new file mode 100644
index 00000000000..0c6fd3ab569
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/pr21205.ll
@@ -0,0 +1,21 @@
+; RUN: opt -reassociate -S < %s | FileCheck %s
+; PR21205
+
+@a = common global i32 0, align 4
+@b = common global i32 0, align 4
+
+; Don't canonicalize %conv - undef into %conv + (-undef).
+; CHECK-LABEL: @test1
+; CHECK: %sub = fsub fast float %conv, undef
+; CHECK: %sub1 = fadd fast float %sub, -1.000000e+00
+
+define i32 @test1() {
+entry:
+ %0 = load i32, i32* @a, align 4
+ %conv = sitofp i32 %0 to float
+ %sub = fsub fast float %conv, undef
+ %sub1 = fadd fast float %sub, -1.000000e+00
+ %conv2 = fptosi float %sub1 to i32
+ store i32 %conv2, i32* @b, align 4
+ ret i32 undef
+}
diff --git a/llvm/test/Transforms/Reassociate/pr28367.ll b/llvm/test/Transforms/Reassociate/pr28367.ll
new file mode 100644
index 00000000000..55a6fcba26c
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/pr28367.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -reassociate -S
+
+; PR28367
+
+; Check to make sure this test does not assert or segfault. If we get too
+; aggressive with retrying instructions it's possible to invalidate our
+; iterator. See PR28367 for complete details.
+
+define void @fn1(i32 %a, i1 %c, i32* %ptr) {
+entry:
+ br label %for.cond
+
+for.cond:
+ %d.0 = phi i32 [ 1, %entry ], [ 2, %for.body ]
+ br i1 %c, label %for.end, label %for.body
+
+for.body:
+ %sub1 = sub i32 %a, %d.0
+ %dead1 = add i32 %sub1, 1
+ %dead2 = mul i32 %dead1, 3
+ %dead3 = mul i32 %dead2, %sub1
+ %sub2 = sub nsw i32 0, %d.0
+ store i32 %sub2, i32* %ptr, align 4
+ br label %for.cond
+
+for.end:
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/propagate-flags.ll b/llvm/test/Transforms/Reassociate/propagate-flags.ll
new file mode 100644
index 00000000000..b6cc9bad540
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/propagate-flags.ll
@@ -0,0 +1,13 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+define double @func(double %a, double %b) {
+; CHECK-LABEL: @func(
+; CHECK-NEXT: [[TMP1:%.*]] = fmul fast double %b, %a
+; CHECK-NEXT: [[TMP2:%.*]] = fmul fast double [[TMP1]], [[TMP1]]
+; CHECK-NEXT: ret double [[TMP2]]
+;
+ %mul1 = fmul fast double %a, %a
+ %mul2 = fmul fast double %b, %b
+ %mul3 = fmul fast double %mul1, %mul2
+ ret double %mul3
+}
diff --git a/llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll b/llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll
new file mode 100644
index 00000000000..3bd8396638a
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/reassoc-intermediate-fnegs.ll
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Input is A op (B op C)
+
+define half @faddsubAssoc1(half %a, half %b) {
+; CHECK-LABEL: @faddsubAssoc1(
+; CHECK-NEXT: [[T2_NEG:%.*]] = fmul fast half [[A:%.*]], 0xH4500
+; CHECK-NEXT: [[REASS_MUL:%.*]] = fmul fast half [[B:%.*]], 0xH4500
+; CHECK-NEXT: [[T51:%.*]] = fsub fast half [[REASS_MUL]], [[T2_NEG]]
+; CHECK-NEXT: [[T5:%.*]] = fadd fast half [[REASS_MUL]], [[T2_NEG]]
+; CHECK-NEXT: ret half [[T51]]
+;
+ %t1 = fmul fast half %b, 0xH4200 ; 3*b
+ %t2 = fmul fast half %a, 0xH4500 ; 5*a
+ %t3 = fmul fast half %b, 0xH4000 ; 2*b
+ %t4 = fsub fast half %t2, %t1 ; 5 * a - 3 * b
+ %t5 = fsub fast half %t3, %t4 ; 2 * b - ( 5 * a - 3 * b)
+ ret half %t5 ; = 5 * (b - a)
+}
+
+; Input is (A op B) op C
+
+define half @faddsubAssoc2(half %a, half %b) {
+; CHECK-LABEL: @faddsubAssoc2(
+; CHECK-NEXT: [[T2:%.*]] = fmul fast half [[A:%.*]], 0xH4500
+; CHECK-NEXT: [[T5:%.*]] = fadd fast half [[B:%.*]], [[T2]]
+; CHECK-NEXT: ret half [[T5]]
+;
+ %t1 = fmul fast half %b, 0xH4200 ; 3*b
+ %t2 = fmul fast half %a, 0xH4500 ; 5*a
+ %t3 = fmul fast half %b, 0xH4000 ; 2*b
+ %t4 = fadd fast half %t2, %t1 ; 5 * a + 3 * b
+ %t5 = fsub fast half %t4, %t3 ; (5 * a + 3 * b) - (2 * b)
+ ret half %t5 ; = 5 * a + b
+}
+
diff --git a/llvm/test/Transforms/Reassociate/reassociate-deadinst.ll b/llvm/test/Transforms/Reassociate/reassociate-deadinst.ll
new file mode 100644
index 00000000000..df314d571d3
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/reassociate-deadinst.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -inline -functionattrs -reassociate -S | FileCheck %s
+
+; CHECK-NOT: func1
+; CHECK-LABEL: main
+; CHECK-NEXT: ret void
+
+define internal i16 @func1() noinline #0 {
+ ret i16 0
+}
+
+define void @main(i16 %argc, i16** %argv) #0 {
+ %_tmp0 = call i16 @func1()
+ %_tmp2 = zext i16 %_tmp0 to i32
+ ret void
+}
+attributes #0 = { minsize nounwind optsize }
diff --git a/llvm/test/Transforms/Reassociate/reassociate_dbgvalue_discard.ll b/llvm/test/Transforms/Reassociate/reassociate_dbgvalue_discard.ll
new file mode 100644
index 00000000000..1addee5fa31
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/reassociate_dbgvalue_discard.ll
@@ -0,0 +1,79 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -reassociate -S -o - | FileCheck %s
+
+; After reassociation m1 and m2 aren't calculated as m1=c*a and m2=c*b any longer.
+; So let's verify that the dbg.value nodes for m1 and m3 are invalidated.
+
+source_filename = "reassociate_dbgvalue_discard.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define dso_local i32 @test1(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr #0 !dbg !7 {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata !16, metadata !DIExpression()), !dbg !20
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 undef, metadata !17, metadata !DIExpression()), !dbg !21
+; CHECK-NEXT: [[M1:%.*]] = mul i32 [[D:%.*]], [[C:%.*]], !dbg !22
+; CHECK-NEXT: [[M3:%.*]] = mul i32 [[M1]], [[A:%.*]], !dbg !23
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[M3]], metadata !18, metadata !DIExpression()), !dbg !24
+; CHECK-NEXT: [[M2:%.*]] = mul i32 [[D]], [[C]], !dbg !25
+; CHECK-NEXT: [[M4:%.*]] = mul i32 [[M2]], [[B:%.*]], !dbg !26
+; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 [[M4]], metadata !19, metadata !DIExpression()), !dbg !27
+; CHECK-NEXT: [[RES:%.*]] = xor i32 [[M3]], [[M4]]
+; CHECK-NEXT: ret i32 [[RES]], !dbg !28
+;
+entry:
+ %m1 = mul i32 %c, %a, !dbg !24
+ call void @llvm.dbg.value(metadata i32 %m1, metadata !16, metadata !DIExpression()), !dbg !25
+ %m2 = mul i32 %c, %b, !dbg !26
+ call void @llvm.dbg.value(metadata i32 %m2, metadata !17, metadata !DIExpression()), !dbg !27
+ %m3 = mul i32 %m1, %d, !dbg !28
+ call void @llvm.dbg.value(metadata i32 %m3, metadata !18, metadata !DIExpression()), !dbg !29
+ %m4 = mul i32 %m2, %d, !dbg !30
+ call void @llvm.dbg.value(metadata i32 %m4, metadata !19, metadata !DIExpression()), !dbg !31
+ %res = xor i32 %m3, %m4
+ ret i32 %res, !dbg !32
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind readnone uwtable }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 330596) (llvm/trunk 330594)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "reassociate_dbgvalue_discard.c", directory: "")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 7.0.0 (trunk 330596) (llvm/trunk 330594)"}
+!7 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10, !10, !10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12, !13, !14, !15, !16, !17, !18, !19}
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
+!13 = !DILocalVariable(name: "b", arg: 2, scope: !7, file: !1, line: 3, type: !10)
+!14 = !DILocalVariable(name: "c", arg: 3, scope: !7, file: !1, line: 3, type: !10)
+!15 = !DILocalVariable(name: "d", arg: 4, scope: !7, file: !1, line: 3, type: !10)
+!16 = !DILocalVariable(name: "t1", scope: !7, file: !1, line: 4, type: !10)
+!17 = !DILocalVariable(name: "t2", scope: !7, file: !1, line: 5, type: !10)
+!18 = !DILocalVariable(name: "t3", scope: !7, file: !1, line: 6, type: !10)
+!19 = !DILocalVariable(name: "t4", scope: !7, file: !1, line: 7, type: !10)
+!20 = !DILocation(line: 3, column: 15, scope: !7)
+!21 = !DILocation(line: 3, column: 22, scope: !7)
+!22 = !DILocation(line: 3, column: 29, scope: !7)
+!23 = !DILocation(line: 3, column: 36, scope: !7)
+!24 = !DILocation(line: 4, column: 14, scope: !7)
+!25 = !DILocation(line: 4, column: 7, scope: !7)
+!26 = !DILocation(line: 5, column: 14, scope: !7)
+!27 = !DILocation(line: 5, column: 7, scope: !7)
+!28 = !DILocation(line: 6, column: 15, scope: !7)
+!29 = !DILocation(line: 6, column: 7, scope: !7)
+!30 = !DILocation(line: 7, column: 15, scope: !7)
+!31 = !DILocation(line: 7, column: 7, scope: !7)
+!32 = !DILocation(line: 8, column: 3, scope: !7)
diff --git a/llvm/test/Transforms/Reassociate/repeats.ll b/llvm/test/Transforms/Reassociate/repeats.ll
new file mode 100644
index 00000000000..547cb0ad72c
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/repeats.ll
@@ -0,0 +1,252 @@
+; RUN: opt < %s -reassociate -S | FileCheck %s
+
+; Tests involving repeated operations on the same value.
+
+define i8 @nilpotent(i8 %x) {
+; CHECK-LABEL: @nilpotent(
+ %tmp = xor i8 %x, %x
+ ret i8 %tmp
+; CHECK: ret i8 0
+}
+
+define i2 @idempotent(i2 %x) {
+; CHECK-LABEL: @idempotent(
+ %tmp1 = and i2 %x, %x
+ %tmp2 = and i2 %tmp1, %x
+ %tmp3 = and i2 %tmp2, %x
+ ret i2 %tmp3
+; CHECK: ret i2 %x
+}
+
+define i2 @add(i2 %x) {
+; CHECK-LABEL: @add(
+ %tmp1 = add i2 %x, %x
+ %tmp2 = add i2 %tmp1, %x
+ %tmp3 = add i2 %tmp2, %x
+ ret i2 %tmp3
+; CHECK: ret i2 0
+}
+
+define i2 @cst_add() {
+; CHECK-LABEL: @cst_add(
+ %tmp1 = add i2 1, 1
+ %tmp2 = add i2 %tmp1, 1
+ ret i2 %tmp2
+; CHECK: ret i2 -1
+}
+
+define i8 @cst_mul() {
+; CHECK-LABEL: @cst_mul(
+ %tmp1 = mul i8 3, 3
+ %tmp2 = mul i8 %tmp1, 3
+ %tmp3 = mul i8 %tmp2, 3
+ %tmp4 = mul i8 %tmp3, 3
+ ret i8 %tmp4
+; CHECK: ret i8 -13
+}
+
+define i3 @foo3x5(i3 %x) {
+; Can be done with two multiplies.
+; CHECK-LABEL: @foo3x5(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i3 %x, %x
+ %tmp2 = mul i3 %tmp1, %x
+ %tmp3 = mul i3 %tmp2, %x
+ %tmp4 = mul i3 %tmp3, %x
+ ret i3 %tmp4
+}
+
+define i3 @foo3x6(i3 %x) {
+; Can be done with two multiplies.
+; CHECK-LABEL: @foo3x6(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i3 %x, %x
+ %tmp2 = mul i3 %tmp1, %x
+ %tmp3 = mul i3 %tmp2, %x
+ %tmp4 = mul i3 %tmp3, %x
+ %tmp5 = mul i3 %tmp4, %x
+ ret i3 %tmp5
+}
+
+define i3 @foo3x7(i3 %x) {
+; Can be done with two multiplies.
+; CHECK-LABEL: @foo3x7(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i3 %x, %x
+ %tmp2 = mul i3 %tmp1, %x
+ %tmp3 = mul i3 %tmp2, %x
+ %tmp4 = mul i3 %tmp3, %x
+ %tmp5 = mul i3 %tmp4, %x
+ %tmp6 = mul i3 %tmp5, %x
+ ret i3 %tmp6
+}
+
+define i4 @foo4x8(i4 %x) {
+; Can be done with two multiplies.
+; CHECK-LABEL: @foo4x8(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ ret i4 %tmp7
+}
+
+define i4 @foo4x9(i4 %x) {
+; Can be done with three multiplies.
+; CHECK-LABEL: @foo4x9(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ ret i4 %tmp8
+}
+
+define i4 @foo4x10(i4 %x) {
+; Can be done with three multiplies.
+; CHECK-LABEL: @foo4x10(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ ret i4 %tmp9
+}
+
+define i4 @foo4x11(i4 %x) {
+; Can be done with four multiplies.
+; CHECK-LABEL: @foo4x11(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ %tmp10 = mul i4 %tmp9, %x
+ ret i4 %tmp10
+}
+
+define i4 @foo4x12(i4 %x) {
+; Can be done with two multiplies.
+; CHECK-LABEL: @foo4x12(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ %tmp10 = mul i4 %tmp9, %x
+ %tmp11 = mul i4 %tmp10, %x
+ ret i4 %tmp11
+}
+
+define i4 @foo4x13(i4 %x) {
+; Can be done with three multiplies.
+; CHECK-LABEL: @foo4x13(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ %tmp10 = mul i4 %tmp9, %x
+ %tmp11 = mul i4 %tmp10, %x
+ %tmp12 = mul i4 %tmp11, %x
+ ret i4 %tmp12
+}
+
+define i4 @foo4x14(i4 %x) {
+; Can be done with three multiplies.
+; CHECK-LABEL: @foo4x14(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ %tmp10 = mul i4 %tmp9, %x
+ %tmp11 = mul i4 %tmp10, %x
+ %tmp12 = mul i4 %tmp11, %x
+ %tmp13 = mul i4 %tmp12, %x
+ ret i4 %tmp13
+}
+
+define i4 @foo4x15(i4 %x) {
+; Can be done with four multiplies.
+; CHECK-LABEL: @foo4x15(
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: mul
+; CHECK-NEXT: ret
+ %tmp1 = mul i4 %x, %x
+ %tmp2 = mul i4 %tmp1, %x
+ %tmp3 = mul i4 %tmp2, %x
+ %tmp4 = mul i4 %tmp3, %x
+ %tmp5 = mul i4 %tmp4, %x
+ %tmp6 = mul i4 %tmp5, %x
+ %tmp7 = mul i4 %tmp6, %x
+ %tmp8 = mul i4 %tmp7, %x
+ %tmp9 = mul i4 %tmp8, %x
+ %tmp10 = mul i4 %tmp9, %x
+ %tmp11 = mul i4 %tmp10, %x
+ %tmp12 = mul i4 %tmp11, %x
+ %tmp13 = mul i4 %tmp12, %x
+ %tmp14 = mul i4 %tmp13, %x
+ ret i4 %tmp14
+}
diff --git a/llvm/test/Transforms/Reassociate/secondary.ll b/llvm/test/Transforms/Reassociate/secondary.ll
new file mode 100644
index 00000000000..a52000ada53
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/secondary.ll
@@ -0,0 +1,24 @@
+; RUN: opt -S -reassociate < %s | FileCheck %s
+; rdar://9167457
+
+; Reassociate shouldn't break this testcase involving a secondary
+; reassociation.
+
+; CHECK: define
+; CHECK-NOT: undef
+; CHECK: %factor = mul i32 %tmp3, -2
+; CHECK-NOT: undef
+; CHECK: }
+
+define void @x0f2f640ab6718391b59ce96d9fdeda54(i32 %arg, i32 %arg1, i32 %arg2, i32* %.out) nounwind {
+_:
+ %tmp = sub i32 %arg, %arg1
+ %tmp3 = mul i32 %tmp, -1268345047
+ %tmp4 = add i32 %tmp3, 2014710503
+ %tmp5 = add i32 %tmp3, -1048397418
+ %tmp6 = sub i32 %tmp4, %tmp5
+ %tmp7 = sub i32 -2014710503, %tmp3
+ %tmp8 = add i32 %tmp6, %tmp7
+ store i32 %tmp8, i32* %.out
+ ret void
+}
diff --git a/llvm/test/Transforms/Reassociate/shift-factor.ll b/llvm/test/Transforms/Reassociate/shift-factor.ll
new file mode 100644
index 00000000000..4b102b07d5e
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/shift-factor.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+; There should be exactly one shift and one add left.
+
+define i32 @test1(i32 %X, i32 %Y) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[REASS_ADD:%.*]] = add i32 %Y, %X
+; CHECK-NEXT: [[REASS_MUL:%.*]] = shl i32 [[REASS_ADD]], 1
+; CHECK-NEXT: ret i32 [[REASS_MUL]]
+;
+ %t2 = shl i32 %X, 1
+ %t6 = shl i32 %Y, 1
+ %t4 = add i32 %t6, %t2
+ ret i32 %t4
+}
+
diff --git a/llvm/test/Transforms/Reassociate/shifttest.ll b/llvm/test/Transforms/Reassociate/shifttest.ll
new file mode 100644
index 00000000000..d9a5336fbfb
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/shifttest.ll
@@ -0,0 +1,12 @@
+; With shl->mul reassociation, we can see that this is (shl A, 9) * A
+;
+; RUN: opt < %s -reassociate -instcombine -S |\
+; RUN: grep "shl .*, 9"
+
+define i32 @test(i32 %A, i32 %B) {
+ %X = shl i32 %A, 5 ; <i32> [#uses=1]
+ %Y = shl i32 %A, 4 ; <i32> [#uses=1]
+ %Z = mul i32 %Y, %X ; <i32> [#uses=1]
+ ret i32 %Z
+}
+
diff --git a/llvm/test/Transforms/Reassociate/subtest.ll b/llvm/test/Transforms/Reassociate/subtest.ll
new file mode 100644
index 00000000000..c1a80e26ce6
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/subtest.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -reassociate -instcombine -S | FileCheck %s
+
+; With sub reassociation, constant folding can eliminate the 12 and -12 constants.
+define i32 @test1(i32 %A, i32 %B) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: [[Z:%.*]] = sub i32 %A, %B
+; CHECK-NEXT: ret i32 [[Z]]
+;
+ %X = add i32 -12, %A
+ %Y = sub i32 %X, %B
+ %Z = add i32 %Y, 12
+ ret i32 %Z
+}
+
+; PR2047
+; With sub reassociation, constant folding can eliminate the uses of %a.
+define i32 @test2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: [[SUM:%.*]] = add i32 %c, %b
+; CHECK-NEXT: [[TMP7:%.*]] = sub i32 0, [[SUM]]
+; CHECK-NEXT: ret i32 [[TMP7]]
+;
+ %tmp3 = sub i32 %a, %b
+ %tmp5 = sub i32 %tmp3, %c
+ %tmp7 = sub i32 %tmp5, %a
+ ret i32 %tmp7
+}
+
diff --git a/llvm/test/Transforms/Reassociate/vaarg_movable.ll b/llvm/test/Transforms/Reassociate/vaarg_movable.ll
new file mode 100644
index 00000000000..be4fe121fae
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/vaarg_movable.ll
@@ -0,0 +1,28 @@
+; RUN: opt -S -reassociate -die < %s | FileCheck %s
+
+; The two va_arg instructions depend on the memory/context, are therfore not
+; identical and the sub should not be optimized to 0 by reassociate.
+;
+; CHECK-LABEL: @func(
+; ...
+; CHECK: %v0 = va_arg i8** %varargs, i32
+; CHECK: %v1 = va_arg i8** %varargs, i32
+; CHECK: %v0.neg = sub i32 0, %v0
+; CHECK: %sub = add i32 %v0.neg, 1
+; CHECK: %add = add i32 %sub, %v1
+; ...
+; CHECK: ret i32 %add
+define i32 @func(i32 %dummy, ...) {
+ %varargs = alloca i8*, align 8
+ %varargs1 = bitcast i8** %varargs to i8*
+ call void @llvm.va_start(i8* %varargs1)
+ %v0 = va_arg i8** %varargs, i32
+ %v1 = va_arg i8** %varargs, i32
+ %sub = sub nsw i32 %v1, %v0
+ %add = add nsw i32 %sub, 1
+ call void @llvm.va_end(i8* %varargs1)
+ ret i32 %add
+}
+
+declare void @llvm.va_start(i8*)
+declare void @llvm.va_end(i8*)
diff --git a/llvm/test/Transforms/Reassociate/wrap-flags.ll b/llvm/test/Transforms/Reassociate/wrap-flags.ll
new file mode 100644
index 00000000000..f56719d32c2
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/wrap-flags.ll
@@ -0,0 +1,45 @@
+; RUN: opt < %s -reassociate -dce -S | FileCheck %s
+; PR12985
+
+; Verify the nsw flags are preserved when converting shl to mul.
+
+; CHECK-LABEL: @shl_to_mul_nsw(
+; CHECK: %mul = mul i32 %i, -2147483648
+; CHECK: add i32 %mul, 1
+define i32 @shl_to_mul_nsw(i32 %i) {
+entry:
+ %mul = shl nsw i32 %i, 31
+ %mul2 = add i32 %mul, 1
+ ret i32 %mul2
+}
+
+; CHECK-LABEL: @shl_to_mul_nuw(
+; CHECK: %mul = mul nuw i32 %i, 4
+; CHECK: add i32 %mul, 1
+define i32 @shl_to_mul_nuw(i32 %i) {
+entry:
+ %mul = shl nuw i32 %i, 2
+ %mul2 = add i32 %mul, 1
+ ret i32 %mul2
+}
+
+; CHECK-LABEL: @shl_to_mul_nuw_nsw(
+; CHECK: %mul = mul nuw nsw i32 %i, 4
+; CHECK: add i32 %mul, 1
+define i32 @shl_to_mul_nuw_nsw(i32 %i) {
+entry:
+ %mul = shl nuw nsw i32 %i, 2
+ %mul2 = add i32 %mul, 1
+ ret i32 %mul2
+}
+
+; CHECK-LABEL: @pr23926(
+; CHECK: %[[X1_neg:.*]] = sub i2 0, %X1
+; CHECK-NEXT: %[[sub_one:.*]] = add i2 %[[X1_neg]], -1
+; CHECK-NEXT: %[[add:.*]] = add i2 %[[sub_one]], %X2
+; CHECK-NEXT: ret i2 %[[add]]
+define i2 @pr23926(i2 %X1, i2 %X2) {
+ %add = add nuw i2 %X1, 1
+ %sub = sub nuw nsw i2 %X2, %add
+ ret i2 %sub
+}
diff --git a/llvm/test/Transforms/Reassociate/xor_reassoc.ll b/llvm/test/Transforms/Reassociate/xor_reassoc.ll
new file mode 100644
index 00000000000..4d617ea0310
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/xor_reassoc.ll
@@ -0,0 +1,294 @@
+;RUN: opt -S -reassociate < %s | FileCheck %s
+
+; ==========================================================================
+;
+; Xor reassociation general cases
+;
+; ==========================================================================
+
+; (x | c1) ^ (x | c2) => (x & c3) ^ c3, where c3 = c1^c2
+;
+define i32 @xor1(i32 %x) {
+ %or = or i32 %x, 123
+ %or1 = or i32 %x, 456
+ %xor = xor i32 %or, %or1
+ ret i32 %xor
+
+;CHECK-LABEL: @xor1(
+;CHECK: %and.ra = and i32 %x, 435
+;CHECK: %xor = xor i32 %and.ra, 435
+}
+
+; (x | c1) ^ (x | c2) => (x & c3) ^ c3, where c3 = c1^c2
+;
+define <2 x i32> @xor1_vec(<2 x i32> %x) {
+ %or = or <2 x i32> %x, <i32 123, i32 123>
+ %or1 = or <2 x i32> %x, <i32 456, i32 456>
+ %xor = xor <2 x i32> %or, %or1
+ ret <2 x i32> %xor
+
+;CHECK-LABEL: @xor1_vec(
+;CHECK: %and.ra = and <2 x i32> %x, <i32 435, i32 435>
+;CHECK: %xor = xor <2 x i32> %and.ra, <i32 435, i32 435>
+}
+
+; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2))
+; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y
+define i32 @xor2(i32 %x, i32 %y) {
+ %and = and i32 %x, 123
+ %xor = xor i32 %and, %y
+ %and1 = and i32 %x, 456
+ %xor2 = xor i32 %xor, %and1
+ ret i32 %xor2
+
+;CHECK-LABEL: @xor2(
+;CHECK: %and.ra = and i32 %x, 435
+;CHECK: %xor2 = xor i32 %and.ra, %y
+}
+
+; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2))
+; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y
+define <2 x i32> @xor2_vec(<2 x i32> %x, <2 x i32> %y) {
+ %and = and <2 x i32> %x, <i32 123, i32 123>
+ %xor = xor <2 x i32> %and, %y
+ %and1 = and <2 x i32> %x, <i32 456, i32 456>
+ %xor2 = xor <2 x i32> %xor, %and1
+ ret <2 x i32> %xor2
+
+;CHECK-LABEL: @xor2_vec(
+;CHECK: %and.ra = and <2 x i32> %x, <i32 435, i32 435>
+;CHECK: %xor2 = xor <2 x i32> %and.ra, %y
+}
+
+; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2
+; c3 = ~c1 ^ c2
+define i32 @xor3(i32 %x, i32 %y) {
+ %or = or i32 %x, 123
+ %xor = xor i32 %or, %y
+ %and = and i32 %x, 456
+ %xor1 = xor i32 %xor, %and
+ ret i32 %xor1
+
+;CHECK-LABEL: @xor3(
+;CHECK: %and.ra = and i32 %x, -436
+;CHECK: %xor = xor i32 %y, 123
+;CHECK: %xor1 = xor i32 %xor, %and.ra
+}
+
+; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2
+; c3 = ~c1 ^ c2
+define <2 x i32> @xor3_vec(<2 x i32> %x, <2 x i32> %y) {
+ %or = or <2 x i32> %x, <i32 123, i32 123>
+ %xor = xor <2 x i32> %or, %y
+ %and = and <2 x i32> %x, <i32 456, i32 456>
+ %xor1 = xor <2 x i32> %xor, %and
+ ret <2 x i32> %xor1
+
+;CHECK-LABEL: @xor3_vec(
+;CHECK: %and.ra = and <2 x i32> %x, <i32 -436, i32 -436>
+;CHECK: %xor = xor <2 x i32> %y, <i32 123, i32 123>
+;CHECK: %xor1 = xor <2 x i32> %xor, %and.ra
+}
+
+; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2)
+define i32 @xor4(i32 %x, i32 %y) {
+ %and = and i32 %x, -124
+ %xor = xor i32 %y, 435
+ %xor1 = xor i32 %xor, %and
+ ret i32 %xor1
+; CHECK-LABEL: @xor4(
+; CHECK: %and = and i32 %x, -124
+; CHECK: %xor = xor i32 %y, 435
+; CHECK: %xor1 = xor i32 %xor, %and
+}
+
+; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2)
+define <2 x i32> @xor4_vec(<2 x i32> %x, <2 x i32> %y) {
+ %and = and <2 x i32> %x, <i32 -124, i32 -124>
+ %xor = xor <2 x i32> %y, <i32 435, i32 435>
+ %xor1 = xor <2 x i32> %xor, %and
+ ret <2 x i32> %xor1
+; CHECK-LABEL: @xor4_vec(
+; CHECK: %and = and <2 x i32> %x, <i32 -124, i32 -124>
+; CHECK: %xor = xor <2 x i32> %y, <i32 435, i32 435>
+; CHECK: %xor1 = xor <2 x i32> %xor, %and
+}
+
+; ==========================================================================
+;
+; Xor reassociation special cases
+;
+; ==========================================================================
+
+; Special case1:
+; (x | c1) ^ (x & ~c1) = c1
+define i32 @xor_special1(i32 %x, i32 %y) {
+ %or = or i32 %x, 123
+ %xor = xor i32 %or, %y
+ %and = and i32 %x, -124
+ %xor1 = xor i32 %xor, %and
+ ret i32 %xor1
+; CHECK-LABEL: @xor_special1(
+; CHECK: %xor1 = xor i32 %y, 123
+; CHECK: ret i32 %xor1
+}
+
+; Special case1:
+; (x | c1) ^ (x & ~c1) = c1
+define <2 x i32> @xor_special1_vec(<2 x i32> %x, <2 x i32> %y) {
+ %or = or <2 x i32> %x, <i32 123, i32 123>
+ %xor = xor <2 x i32> %or, %y
+ %and = and <2 x i32> %x, <i32 -124, i32 -124>
+ %xor1 = xor <2 x i32> %xor, %and
+ ret <2 x i32> %xor1
+; CHECK-LABEL: @xor_special1_vec(
+; CHECK: %xor1 = xor <2 x i32> %y, <i32 123, i32 123>
+; CHECK: ret <2 x i32> %xor1
+}
+
+; Special case1:
+; (x | c1) ^ (x & c1) = x ^ c1
+define i32 @xor_special2(i32 %x, i32 %y) {
+ %or = or i32 %x, 123
+ %xor = xor i32 %or, %y
+ %and = and i32 %x, 123
+ %xor1 = xor i32 %xor, %and
+ ret i32 %xor1
+; CHECK-LABEL: @xor_special2(
+; CHECK: %xor = xor i32 %x, 123
+; CHECK: %xor1 = xor i32 %xor, %y
+; CHECK: ret i32 %xor1
+}
+
+; Special case1:
+; (x | c1) ^ (x & c1) = x ^ c1
+define <2 x i32> @xor_special2_vec(<2 x i32> %x, <2 x i32> %y) {
+ %or = or <2 x i32> %x, <i32 123, i32 123>
+ %xor = xor <2 x i32> %or, %y
+ %and = and <2 x i32> %x, <i32 123, i32 123>
+ %xor1 = xor <2 x i32> %xor, %and
+ ret <2 x i32> %xor1
+; CHECK-LABEL: @xor_special2_vec(
+; CHECK: %xor = xor <2 x i32> %x, <i32 123, i32 123>
+; CHECK: %xor1 = xor <2 x i32> %xor, %y
+; CHECK: ret <2 x i32> %xor1
+}
+
+; (x | c1) ^ (x | c1) => 0
+define i32 @xor_special3(i32 %x) {
+ %or = or i32 %x, 123
+ %or1 = or i32 %x, 123
+ %xor = xor i32 %or, %or1
+ ret i32 %xor
+;CHECK-LABEL: @xor_special3(
+;CHECK: ret i32 0
+}
+
+; (x | c1) ^ (x | c1) => 0
+define <2 x i32> @xor_special3_vec(<2 x i32> %x) {
+ %or = or <2 x i32> %x, <i32 123, i32 123>
+ %or1 = or <2 x i32> %x, <i32 123, i32 123>
+ %xor = xor <2 x i32> %or, %or1
+ ret <2 x i32> %xor
+;CHECK-LABEL: @xor_special3_vec(
+;CHECK: ret <2 x i32> zeroinitializer
+}
+
+; (x & c1) ^ (x & c1) => 0
+define i32 @xor_special4(i32 %x) {
+ %or = and i32 %x, 123
+ %or1 = and i32 123, %x
+ %xor = xor i32 %or, %or1
+ ret i32 %xor
+;CHECK-LABEL: @xor_special4(
+;CHECK: ret i32 0
+}
+
+; (x & c1) ^ (x & c1) => 0
+define <2 x i32> @xor_special4_vec(<2 x i32> %x) {
+ %or = and <2 x i32> %x, <i32 123, i32 123>
+ %or1 = and <2 x i32> <i32 123, i32 123>, %x
+ %xor = xor <2 x i32> %or, %or1
+ ret <2 x i32> %xor
+;CHECK-LABEL: @xor_special4_vec(
+;CHECK: ret <2 x i32> zeroinitializer
+}
+
+; ==========================================================================
+;
+; Xor reassociation curtail code size
+;
+; ==========================================================================
+
+; (x | c1) ^ (x | c2) => (x & c3) ^ c3
+; is enabled if one of operands has multiple uses
+;
+define i32 @xor_ra_size1(i32 %x) {
+ %or = or i32 %x, 123
+ %or1 = or i32 %x, 456
+ %xor = xor i32 %or, %or1
+
+ %add = add i32 %xor, %or
+ ret i32 %add
+;CHECK-LABEL: @xor_ra_size1(
+;CHECK: %xor = xor i32 %and.ra, 435
+}
+
+; (x | c1) ^ (x | c2) => (x & c3) ^ c3
+; is disenabled if bothf operands has multiple uses.
+;
+define i32 @xor_ra_size2(i32 %x) {
+ %or = or i32 %x, 123
+ %or1 = or i32 %x, 456
+ %xor = xor i32 %or, %or1
+
+ %add = add i32 %xor, %or
+ %add2 = add i32 %add, %or1
+ ret i32 %add2
+
+;CHECK-LABEL: @xor_ra_size2(
+;CHECK: %or1 = or i32 %x, 456
+;CHECK: %xor = xor i32 %or, %or1
+}
+
+
+; ==========================================================================
+;
+; Xor reassociation bugs
+;
+; ==========================================================================
+
+@xor_bug1_data = external global <{}>, align 4
+define void @xor_bug1() {
+ %1 = ptrtoint i32* undef to i64
+ %2 = xor i64 %1, ptrtoint (<{}>* @xor_bug1_data to i64)
+ %3 = and i64 undef, %2
+ ret void
+}
+
+; The bug was that when the compiler optimize "(x | c1)" ^ "(x & c2)", it may
+; swap the two xor-subexpressions if they are not in canoninical order; however,
+; when optimizer swaps two sub-expressions, if forgot to swap the cached value
+; of c1 and c2 accordingly, hence cause the problem.
+;
+define i32 @xor_bug2(i32, i32, i32, i32) {
+ %5 = mul i32 %0, 123
+ %6 = add i32 %2, 24
+ %7 = add i32 %1, 8
+ %8 = and i32 %1, 3456789
+ %9 = or i32 %8, 4567890
+ %10 = and i32 %1, 543210987
+ %11 = or i32 %1, 891034567
+ %12 = and i32 %2, 255
+ %13 = xor i32 %9, %10
+ %14 = xor i32 %11, %13
+ %15 = xor i32 %5, %14
+ %16 = and i32 %3, 255
+ %17 = xor i32 %16, 42
+ %18 = add i32 %6, %7
+ %19 = add i32 %18, %12
+ %20 = add i32 %19, %15
+ ret i32 %20
+;CHECK-LABEL: @xor_bug2(
+;CHECK: xor i32 %5, 891034567
+}
OpenPOWER on IntegriCloud