diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 33ca46ca1c2c6..b95c1466871bc 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -1271,6 +1271,7 @@ bool Instruction::isAssociative() const { switch (Opcode) { case FMul: + return cast(this)->hasAllowReassoc(); case FAdd: return cast(this)->hasAllowReassoc() && cast(this)->hasNoSignedZeros(); diff --git a/llvm/test/Transforms/Attributor/nofpclass-fmul.ll b/llvm/test/Transforms/Attributor/nofpclass-fmul.ll new file mode 100644 index 0000000000000..6d0edf0681ed4 --- /dev/null +++ b/llvm/test/Transforms/Attributor/nofpclass-fmul.ll @@ -0,0 +1,288 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal < %s | FileCheck %s + +; Test that multiply by a constant with a sufficiently large exponent +; proves the result is not subnormal. + +define float @ret_fmul_f32(float %arg0, float %arg1) { +; CHECK-LABEL: define float @ret_fmul_f32( +; CHECK-SAME: float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG0]], [[ARG1]] +; CHECK-NEXT: ret float [[FMUL]] +; + %fmul = fmul float %arg0, %arg1 + ret float %fmul +} + +define float @ret_fmul_square_f32(float %arg) { +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmul_square_f32( +; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[ARG]], [[ARG]] +; CHECK-NEXT: ret float [[FMUL]] +; + %fmul = fmul float %arg, %arg + ret float %fmul +} + +define float @ret_mul_exponent_f32_22(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_22( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4150000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x4150000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_23(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_23( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4160000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x4160000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_24(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_24( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4170000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x4170000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_23_nnan(float nofpclass(nan) %arg0) { +; CHECK-LABEL: define nofpclass(nan) float @ret_mul_exponent_f32_23_nnan( +; CHECK-SAME: float nofpclass(nan) [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x4160000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x4160000000000000 + ret float %call +} + +define double @ret_mul_exponent_f64_24(double %arg0) { +; CHECK-LABEL: define double @ret_mul_exponent_f64_24( +; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4170000000000000 +; CHECK-NEXT: ret double [[CALL]] +; + %call = fmul double %arg0, 0x4170000000000000 + ret double %call +} + +define double @ret_mul_exponent_f64_51(double %arg0) { +; CHECK-LABEL: define double @ret_mul_exponent_f64_51( +; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4320000000000000 +; CHECK-NEXT: ret double [[CALL]] +; + %call = fmul double %arg0, 0x4320000000000000 + ret double %call +} + +define double @ret_mul_exponent_f64_52(double %arg0) { +; CHECK-LABEL: define double @ret_mul_exponent_f64_52( +; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4330000000000000 +; CHECK-NEXT: ret double [[CALL]] +; + %call = fmul double %arg0, 0x4330000000000000 + ret double %call +} + +define double @ret_mul_exponent_f64_53(double %arg0) { +; CHECK-LABEL: define double @ret_mul_exponent_f64_53( +; CHECK-SAME: double [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul double [[ARG0]], 0x4340000000000000 +; CHECK-NEXT: ret double [[CALL]] +; + %call = fmul double %arg0, 0x4340000000000000 + ret double %call +} + +define half @ret_mul_exponent_f16_8(half %arg0) { +; CHECK-LABEL: define half @ret_mul_exponent_f16_8( +; CHECK-SAME: half [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul half [[ARG0]], 0xH5C00 +; CHECK-NEXT: ret half [[CALL]] +; + %call = fmul half %arg0, 0xH5C00 + ret half %call +} + +define half @ret_mul_exponent_f16_9(half %arg0) { +; CHECK-LABEL: define half @ret_mul_exponent_f16_9( +; CHECK-SAME: half [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul half [[ARG0]], 0xH6000 +; CHECK-NEXT: ret half [[CALL]] +; + %call = fmul half %arg0, 0xH6000 + ret half %call +} + +define half @ret_mul_exponent_f16_10(half %arg0) { +; CHECK-LABEL: define half @ret_mul_exponent_f16_10( +; CHECK-SAME: half [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul half [[ARG0]], 0xH6400 +; CHECK-NEXT: ret half [[CALL]] +; + %call = fmul half %arg0, 0xH6400 + ret half %call +} + +define bfloat @ret_mul_exponent_bf16_6(bfloat %arg0) { +; CHECK-LABEL: define bfloat @ret_mul_exponent_bf16_6( +; CHECK-SAME: bfloat [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul bfloat [[ARG0]], 0xR4280 +; CHECK-NEXT: ret bfloat [[CALL]] +; + %call = fmul bfloat %arg0, 0xR4280 + ret bfloat %call +} + +define bfloat @ret_mul_exponent_bf16_7(bfloat %arg0) { +; CHECK-LABEL: define bfloat @ret_mul_exponent_bf16_7( +; CHECK-SAME: bfloat [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul bfloat [[ARG0]], 0xR4300 +; CHECK-NEXT: ret bfloat [[CALL]] +; + %call = fmul bfloat %arg0, 0xR4300 + ret bfloat %call +} + +define bfloat @ret_mul_exponent_bf16_8(bfloat %arg0) { +; CHECK-LABEL: define bfloat @ret_mul_exponent_bf16_8( +; CHECK-SAME: bfloat [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul bfloat [[ARG0]], 0xR4380 +; CHECK-NEXT: ret bfloat [[CALL]] +; + %call = fmul bfloat %arg0, 0xR4380 + ret bfloat %call +} + +define float @ret_mul_exponent_f32_neg22(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_neg22( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x3E90000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x3E90000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_neg23(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_neg23( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x3E80000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x3E80000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_neg24(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_neg24( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x3E70000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x3E70000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_neg126(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_neg126( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x3810000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x3810000000000000 + ret float %call +} + +define float @ret_mul_exponent_f32_neg127(float %arg0) { +; CHECK-LABEL: define float @ret_mul_exponent_f32_neg127( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x3800000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x3800000000000000 + ret float %call +} + +define <2 x float> @ret_mul_exponent_v2f32_splat_23(<2 x float> %arg0) { +; CHECK-LABEL: define <2 x float> @ret_mul_exponent_v2f32_splat_23( +; CHECK-SAME: <2 x float> [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul <2 x float> [[ARG0]], splat (float 0x4160000000000000) +; CHECK-NEXT: ret <2 x float> [[CALL]] +; + %call = fmul <2 x float> %arg0, splat (float 0x4160000000000000) + ret <2 x float> %call +} + +define <2 x float> @ret_mul_exponent_v2f32_splat_poison_23(<2 x float> %arg0) { +; CHECK-LABEL: define <2 x float> @ret_mul_exponent_v2f32_splat_poison_23( +; CHECK-SAME: <2 x float> [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul <2 x float> [[ARG0]], +; CHECK-NEXT: ret <2 x float> [[CALL]] +; + %call = fmul <2 x float> %arg0, + ret <2 x float> %call +} + +; TODO: Should be able to prove nofpclass(sub) +define <2 x float> @ret_mul_exponent_v2f32_nonsplat(<2 x float> %arg0) { +; CHECK-LABEL: define <2 x float> @ret_mul_exponent_v2f32_nonsplat( +; CHECK-SAME: <2 x float> [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul <2 x float> [[ARG0]], +; CHECK-NEXT: ret <2 x float> [[CALL]] +; + %call = fmul <2 x float> %arg0, + ret <2 x float> %call +} + +; Cannot prove this is not-subnormal +define <2 x float> @ret_mul_partially_foldable_exponent_v2f32(<2 x float> %arg0) { +; CHECK-LABEL: define <2 x float> @ret_mul_partially_foldable_exponent_v2f32( +; CHECK-SAME: <2 x float> [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul <2 x float> [[ARG0]], +; CHECK-NEXT: ret <2 x float> [[CALL]] +; + %call = fmul <2 x float> %arg0, + ret <2 x float> %call +} + +define float @ret_mul_f32_0(float %arg0) { +; CHECK-LABEL: define float @ret_mul_f32_0( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0.000000e+00 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0.0 + ret float %call +} + +define float @ret_mul_f32_inf(float %arg0) { +; CHECK-LABEL: define float @ret_mul_f32_inf( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x7FF0000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x7FF0000000000000 + ret float %call +} + +define float @ret_mul_f32_nan(float %arg0) { +; CHECK-LABEL: define float @ret_mul_f32_nan( +; CHECK-SAME: float [[ARG0:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: [[CALL:%.*]] = fmul float [[ARG0]], 0x7FF8000000000000 +; CHECK-NEXT: ret float [[CALL]] +; + %call = fmul float %arg0, 0x7FF8000000000000 + ret float %call +} + diff --git a/llvm/test/Transforms/InstCombine/2006-10-26-VectorReassoc.ll b/llvm/test/Transforms/InstCombine/2006-10-26-VectorReassoc.ll index fb860a5e7bdf3..6509797e0d3dc 100644 --- a/llvm/test/Transforms/InstCombine/2006-10-26-VectorReassoc.ll +++ b/llvm/test/Transforms/InstCombine/2006-10-26-VectorReassoc.ll @@ -35,12 +35,10 @@ define <4 x float> @test_fmul_reassoc_nsz(<4 x float> %V) { } ; (V * C1) * C2 => V * (C1 * C2) -; TODO: This doesn't require 'nsz'. It should fold to V * { 1.0, 4.0e+05, -9.0, 16.0 } define <4 x float> @test_fmul_reassoc(<4 x float> %V) { ; CHECK-LABEL: @test_fmul_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc <4 x float> [[V:%.*]], -; CHECK-NEXT: [[TMP2:%.*]] = fmul reassoc <4 x float> [[TMP1]], -; CHECK-NEXT: ret <4 x float> [[TMP2]] +; CHECK: [[TMP1:%.*]] = fmul reassoc <4 x float> %V, +; CHECK-NEXT: ret <4 x float> [[TMP1]] %Y = fmul reassoc <4 x float> %V, < float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00 > %Z = fmul reassoc <4 x float> %Y, < float 1.000000e+00, float 2.000000e+05, float -3.000000e+00, float 4.000000e+00 > ret <4 x float> %Z diff --git a/llvm/test/Transforms/InstCombine/fdiv.ll b/llvm/test/Transforms/InstCombine/fdiv.ll index 54b0bf8c50ac7..3465781e3af9d 100644 --- a/llvm/test/Transforms/InstCombine/fdiv.ll +++ b/llvm/test/Transforms/InstCombine/fdiv.ll @@ -525,8 +525,7 @@ define <2 x float> @div_constant_dividend2_reassoc_only(<2 x float> %x) { define <2 x float> @div_constant_dividend3(<2 x float> %x) { ; CHECK-LABEL: @div_constant_dividend3( -; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc arcp <2 x float> [[X:%.*]], -; CHECK-NEXT: [[T2:%.*]] = fmul reassoc arcp <2 x float> [[TMP1]], +; CHECK-NEXT: [[T2:%.*]] = fmul reassoc arcp <2 x float> [[X:%.*]], ; CHECK-NEXT: ret <2 x float> [[T2]] ; %t1 = fdiv <2 x float> , %x diff --git a/llvm/test/Transforms/InstCombine/issue64967-reassoc-fmul.ll b/llvm/test/Transforms/InstCombine/issue64967-reassoc-fmul.ll index 16f9cf2dd64c5..5d064234bf609 100644 --- a/llvm/test/Transforms/InstCombine/issue64967-reassoc-fmul.ll +++ b/llvm/test/Transforms/InstCombine/issue64967-reassoc-fmul.ll @@ -25,8 +25,7 @@ define float @fmul(float %x) { define float @fmul_reassoc(float %x) { ; CHECK-LABEL: define float @fmul_reassoc( ; CHECK-SAME: float [[X:%.*]]) { -; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc float [[X]], 2.000000e+00 -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[FMUL0]], 4.000000e+00 +; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[X]], 8.000000e+00 ; CHECK-NEXT: ret float [[FMUL1]] ; %fmul0 = fmul reassoc float %x, 2.0 @@ -37,8 +36,7 @@ define float @fmul_reassoc(float %x) { define <2 x float> @fmul_reassoc_v2(<2 x float> %x) { ; CHECK-LABEL: define <2 x float> @fmul_reassoc_v2( ; CHECK-SAME: <2 x float> [[X:%.*]]) { -; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc <2 x float> [[X]], splat (float 2.000000e+00) -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc <2 x float> [[FMUL0]], splat (float 4.000000e+00) +; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc <2 x float> [[X]], splat (float 8.000000e+00) ; CHECK-NEXT: ret <2 x float> [[FMUL1]] ; %fmul0 = fmul reassoc <2 x float> %x, splat (float 2.0) @@ -54,8 +52,7 @@ define <2 x float> @fmul_reassoc_v2(<2 x float> %x) { define float @fmul_reassoc_negative_0(float %x) { ; CHECK-LABEL: define float @fmul_reassoc_negative_0( ; CHECK-SAME: float [[X:%.*]]) { -; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc float [[X]], 2.000000e+00 -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[FMUL0]], -4.000000e+00 +; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[X]], -8.000000e+00 ; CHECK-NEXT: ret float [[FMUL1]] ; %fmul0 = fmul reassoc float %x, 2.0 @@ -71,8 +68,7 @@ define float @fmul_reassoc_negative_0(float %x) { define float @fmul_reassoc_negative_1(float %x) { ; CHECK-LABEL: define float @fmul_reassoc_negative_1( ; CHECK-SAME: float [[X:%.*]]) { -; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc float [[X]], -2.000000e+00 -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[FMUL0]], 4.000000e+00 +; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[X]], -8.000000e+00 ; CHECK-NEXT: ret float [[FMUL1]] ; %fmul0 = fmul reassoc float %x, -2.0 @@ -95,8 +91,7 @@ define float @fmul_reassoc_nsz(float %x) { define float @fmul_reassoc_posk_neg0(float %x) { ; CHECK-LABEL: define float @fmul_reassoc_posk_neg0( ; CHECK-SAME: float [[X:%.*]]) { -; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc float [[X]], 4.000000e+00 -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[FMUL0]], -0.000000e+00 +; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[X]], -0.000000e+00 ; CHECK-NEXT: ret float [[FMUL1]] ; %fmul0 = fmul reassoc float %x, 4.0 @@ -108,8 +103,7 @@ define float @fmul_reassoc_neg0_posk(float %x) { ; CHECK-LABEL: define float @fmul_reassoc_neg0_posk( ; CHECK-SAME: float [[X:%.*]]) { ; CHECK-NEXT: [[FMUL0:%.*]] = fmul reassoc float [[X]], -0.000000e+00 -; CHECK-NEXT: [[FMUL1:%.*]] = fmul reassoc float [[FMUL0]], 4.000000e+00 -; CHECK-NEXT: ret float [[FMUL1]] +; CHECK-NEXT: ret float [[FMUL0]] ; %fmul0 = fmul reassoc float %x, -0.0 %fmul1 = fmul reassoc float %fmul0, 4.0