diff options
Diffstat (limited to 'llvm/test/Transforms/Reassociate')
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 +} |