1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s 3 4define <4 x float> @fmul_zero_not_fast(<4 x float> %x) nounwind { 5; CHECK-LABEL: fmul_zero_not_fast: 6; CHECK: # %bb.0: 7; CHECK-NEXT: xorps %xmm1, %xmm1 8; CHECK-NEXT: mulps %xmm1, %xmm0 9; CHECK-NEXT: retq 10 %r = fmul <4 x float> %x, zeroinitializer 11 ret <4 x float> %r 12} 13 14define <4 x float> @fmul_zero_nsz_nnan(<4 x float> %x) nounwind { 15; CHECK-LABEL: fmul_zero_nsz_nnan: 16; CHECK: # %bb.0: 17; CHECK-NEXT: xorps %xmm0, %xmm0 18; CHECK-NEXT: retq 19 %r = fmul nsz nnan <4 x float> %x, zeroinitializer 20 ret <4 x float> %r 21} 22 23define <4 x float> @fmul_zero_nsz_nnan_undef(<4 x float> %x) nounwind { 24; CHECK-LABEL: fmul_zero_nsz_nnan_undef: 25; CHECK: # %bb.0: 26; CHECK-NEXT: xorps %xmm0, %xmm0 27; CHECK-NEXT: retq 28 %r = fmul nsz nnan <4 x float> %x, <float 0.0, float 0.0, float 0.0, float undef> 29 ret <4 x float> %r 30} 31 32define float @fmul2_f32(float %x) { 33; CHECK-LABEL: fmul2_f32: 34; CHECK: # %bb.0: 35; CHECK-NEXT: addss %xmm0, %xmm0 36; CHECK-NEXT: retq 37 %y = fmul float %x, 2.0 38 ret float %y 39} 40 41; fmul 2.0, x -> fadd x, x for vectors. 42 43define <4 x float> @fmul2_v4f32(<4 x float> %x) { 44; CHECK-LABEL: fmul2_v4f32: 45; CHECK: # %bb.0: 46; CHECK-NEXT: addps %xmm0, %xmm0 47; CHECK-NEXT: retq 48 %y = fmul <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0> 49 ret <4 x float> %y 50} 51 52define <4 x float> @fmul2_v4f32_undef(<4 x float> %x) { 53; CHECK-LABEL: fmul2_v4f32_undef: 54; CHECK: # %bb.0: 55; CHECK-NEXT: addps %xmm0, %xmm0 56; CHECK-NEXT: retq 57 %y = fmul <4 x float> %x, <float undef, float 2.0, float 2.0, float 2.0> 58 ret <4 x float> %y 59} 60 61define <4 x float> @constant_fold_fmul_v4f32(<4 x float> %x) { 62; CHECK-LABEL: constant_fold_fmul_v4f32: 63; CHECK: # %bb.0: 64; CHECK-NEXT: movaps {{.*#+}} xmm0 = [8.0E+0,8.0E+0,8.0E+0,8.0E+0] 65; CHECK-NEXT: retq 66 %y = fmul <4 x float> <float 4.0, float 4.0, float 4.0, float 4.0>, <float 2.0, float 2.0, float 2.0, float 2.0> 67 ret <4 x float> %y 68} 69 70define <4 x float> @constant_fold_fmul_v4f32_undef(<4 x float> %x) { 71; CHECK-LABEL: constant_fold_fmul_v4f32_undef: 72; CHECK: # %bb.0: 73; CHECK-NEXT: movaps {{.*#+}} xmm0 = [8.0E+0,NaN,8.0E+0,NaN] 74; CHECK-NEXT: retq 75 %y = fmul <4 x float> <float 4.0, float undef, float 4.0, float 4.0>, <float 2.0, float 2.0, float 2.0, float undef> 76 ret <4 x float> %y 77} 78 79define <4 x float> @fmul0_v4f32_nsz_nnan(<4 x float> %x) { 80; CHECK-LABEL: fmul0_v4f32_nsz_nnan: 81; CHECK: # %bb.0: 82; CHECK-NEXT: xorps %xmm0, %xmm0 83; CHECK-NEXT: retq 84 %y = fmul nnan nsz <4 x float> %x, <float 0.0, float 0.0, float 0.0, float 0.0> 85 ret <4 x float> %y 86} 87 88define <4 x float> @fmul0_v4f32_undef(<4 x float> %x) { 89; CHECK-LABEL: fmul0_v4f32_undef: 90; CHECK: # %bb.0: 91; CHECK-NEXT: xorps %xmm0, %xmm0 92; CHECK-NEXT: retq 93 %y = fmul nnan nsz <4 x float> %x, <float undef, float 0.0, float undef, float 0.0> 94 ret <4 x float> %y 95} 96 97define <4 x float> @fmul_c2_c4_v4f32(<4 x float> %x) { 98; CHECK-LABEL: fmul_c2_c4_v4f32: 99; CHECK: # %bb.0: 100; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 101; CHECK-NEXT: retq 102 %y = fmul fast <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0> 103 %z = fmul fast <4 x float> %y, <float 4.0, float 4.0, float 4.0, float 4.0> 104 ret <4 x float> %z 105} 106 107define <4 x float> @fmul_c3_c4_v4f32(<4 x float> %x) { 108; CHECK-LABEL: fmul_c3_c4_v4f32: 109; CHECK: # %bb.0: 110; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 111; CHECK-NEXT: retq 112 %y = fmul fast <4 x float> %x, <float 3.0, float 3.0, float 3.0, float 3.0> 113 %z = fmul fast <4 x float> %y, <float 4.0, float 4.0, float 4.0, float 4.0> 114 ret <4 x float> %z 115} 116 117; CHECK: float 5 118; CHECK: float 12 119; CHECK: float 21 120; CHECK: float 32 121 122; We should be able to pre-multiply the two constant vectors. 123define <4 x float> @fmul_v4f32_two_consts_no_splat(<4 x float> %x) { 124; CHECK-LABEL: fmul_v4f32_two_consts_no_splat: 125; CHECK: # %bb.0: 126; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 127; CHECK-NEXT: retq 128 %y = fmul fast <4 x float> %x, <float 1.0, float 2.0, float 3.0, float 4.0> 129 %z = fmul fast <4 x float> %y, <float 5.0, float 6.0, float 7.0, float 8.0> 130 ret <4 x float> %z 131} 132 133; Same as above, but reverse operands to make sure non-canonical form is also handled. 134define <4 x float> @fmul_v4f32_two_consts_no_splat_non_canonical(<4 x float> %x) { 135; CHECK-LABEL: fmul_v4f32_two_consts_no_splat_non_canonical: 136; CHECK: # %bb.0: 137; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 138; CHECK-NEXT: retq 139 %y = fmul fast <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, %x 140 %z = fmul fast <4 x float> <float 5.0, float 6.0, float 7.0, float 8.0>, %y 141 ret <4 x float> %z 142} 143 144; Node-level FMF and no function-level attributes. 145 146define <4 x float> @fmul_v4f32_two_consts_no_splat_reassoc(<4 x float> %x) { 147; CHECK-LABEL: fmul_v4f32_two_consts_no_splat_reassoc: 148; CHECK: # %bb.0: 149; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 150; CHECK-NEXT: retq 151 %y = fmul <4 x float> %x, <float 1.0, float 2.0, float 3.0, float 4.0> 152 %z = fmul reassoc <4 x float> %y, <float 5.0, float 6.0, float 7.0, float 8.0> 153 ret <4 x float> %z 154} 155 156; Multiplication by 2.0 is a special case because that gets converted to fadd x, x. 157 158define <4 x float> @fmul_v4f32_two_consts_no_splat_reassoc_2(<4 x float> %x) { 159; CHECK-LABEL: fmul_v4f32_two_consts_no_splat_reassoc_2: 160; CHECK: # %bb.0: 161; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 162; CHECK-NEXT: retq 163 %y = fadd <4 x float> %x, %x 164 %z = fmul reassoc <4 x float> %y, <float 5.0, float 6.0, float 7.0, float 8.0> 165 ret <4 x float> %z 166} 167 168; CHECK: float 6 169; CHECK: float 14 170; CHECK: float 24 171; CHECK: float 36 172 173; More than one use of a constant multiply should not inhibit the optimization. 174; Instead of a chain of 2 dependent mults, this test will have 2 independent mults. 175define <4 x float> @fmul_v4f32_two_consts_no_splat_multiple_use(<4 x float> %x) { 176; CHECK-LABEL: fmul_v4f32_two_consts_no_splat_multiple_use: 177; CHECK: # %bb.0: 178; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 179; CHECK-NEXT: retq 180 %y = fmul fast <4 x float> %x, <float 1.0, float 2.0, float 3.0, float 4.0> 181 %z = fmul fast <4 x float> %y, <float 5.0, float 6.0, float 7.0, float 8.0> 182 %a = fadd fast <4 x float> %y, %z 183 ret <4 x float> %a 184} 185 186; PR22698 - http://llvm.org/bugs/show_bug.cgi?id=22698 187; Make sure that we don't infinite loop swapping constants back and forth. 188 189; CHECK: float 24 190; CHECK: float 24 191; CHECK: float 24 192; CHECK: float 24 193 194define <4 x float> @PR22698_splats(<4 x float> %a) { 195; CHECK-LABEL: PR22698_splats: 196; CHECK: # %bb.0: 197; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 198; CHECK-NEXT: retq 199 %mul1 = fmul fast <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>, <float 3.0, float 3.0, float 3.0, float 3.0> 200 %mul2 = fmul fast <4 x float> <float 4.0, float 4.0, float 4.0, float 4.0>, %mul1 201 %mul3 = fmul fast <4 x float> %a, %mul2 202 ret <4 x float> %mul3 203} 204 205; Same as above, but verify that non-splat vectors are handled correctly too. 206 207; CHECK: float 45 208; CHECK: float 120 209; CHECK: float 231 210; CHECK: float 384 211 212define <4 x float> @PR22698_no_splats(<4 x float> %a) { 213; CHECK-LABEL: PR22698_no_splats: 214; CHECK: # %bb.0: 215; CHECK-NEXT: mulps {{.*}}(%rip), %xmm0 216; CHECK-NEXT: retq 217 %mul1 = fmul fast <4 x float> <float 1.0, float 2.0, float 3.0, float 4.0>, <float 5.0, float 6.0, float 7.0, float 8.0> 218 %mul2 = fmul fast <4 x float> <float 9.0, float 10.0, float 11.0, float 12.0>, %mul1 219 %mul3 = fmul fast <4 x float> %a, %mul2 220 ret <4 x float> %mul3 221} 222 223define float @fmul_c2_c4_f32(float %x) { 224; CHECK-LABEL: fmul_c2_c4_f32: 225; CHECK: # %bb.0: 226; CHECK-NEXT: mulss {{.*}}(%rip), %xmm0 227; CHECK-NEXT: retq 228 %y = fmul fast float %x, 2.0 229 %z = fmul fast float %y, 4.0 230 ret float %z 231} 232 233define float @fmul_c3_c4_f32(float %x) { 234; CHECK-LABEL: fmul_c3_c4_f32: 235; CHECK: # %bb.0: 236; CHECK-NEXT: mulss {{.*}}(%rip), %xmm0 237; CHECK-NEXT: retq 238 %y = fmul fast float %x, 3.0 239 %z = fmul fast float %y, 4.0 240 ret float %z 241} 242 243define float @fmul_fneg_fneg_f32(float %x, float %y) { 244; CHECK-LABEL: fmul_fneg_fneg_f32: 245; CHECK: # %bb.0: 246; CHECK-NEXT: mulss %xmm1, %xmm0 247; CHECK-NEXT: retq 248 %x.neg = fsub float -0.0, %x 249 %y.neg = fsub float -0.0, %y 250 %mul = fmul float %x.neg, %y.neg 251 ret float %mul 252} 253 254define <4 x float> @fmul_fneg_fneg_v4f32(<4 x float> %x, <4 x float> %y) { 255; CHECK-LABEL: fmul_fneg_fneg_v4f32: 256; CHECK: # %bb.0: 257; CHECK-NEXT: mulps %xmm1, %xmm0 258; CHECK-NEXT: retq 259 %x.neg = fsub <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, %x 260 %y.neg = fsub <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, %y 261 %mul = fmul <4 x float> %x.neg, %y.neg 262 ret <4 x float> %mul 263} 264 265; PR47517 - this could crash if we create 'fmul x, 0.0' nodes 266; that do not constant fold in a particular order. 267 268define float @getNegatedExpression_crash(float* %p) { 269; CHECK-LABEL: getNegatedExpression_crash: 270; CHECK: # %bb.0: 271; CHECK-NEXT: movl $0, (%rdi) 272; CHECK-NEXT: xorps %xmm0, %xmm0 273; CHECK-NEXT: retq 274 store float 0.0, float* %p, align 1 275 %real = load float, float* %p, align 1 276 %r2 = fmul fast float %real, %real 277 %t1 = fmul fast float %real, 42.0 278 %t2 = fmul fast float %real, %t1 279 %mul_ac56 = fmul fast float %t2, %t1 280 %mul_ac72 = fmul fast float %r2, %mul_ac56 281 ret float %mul_ac72 282} 283