751 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=slp-vectorizer -S < %s -mtriple=x86_64-unknown-linux -mattr=+sse2 | FileCheck %s --check-prefixes=CHECK,SSE3; RUN: opt -passes=slp-vectorizer -S < %s -mtriple=x86_64-unknown-linux -mcpu=corei7-avx | FileCheck %s --check-prefixes=CHECK,AVX4;5; This file tests the look-ahead operand reordering heuristic.6;7;8; This checks that operand reordering will reorder the operands of the adds9; by taking into consideration the instructions beyond the immediate10; predecessors.11;12; A[0] B[0] C[0] D[0] C[1] D[1] A[1] B[1]13; \ / \ / \ / \ /14; - - - -15; \ / \ /16; + +17; | |18; S[0] S[1]19;20define void @lookahead_basic(ptr %array) {21; CHECK-LABEL: @lookahead_basic(22; CHECK-NEXT: entry:23; CHECK-NEXT: [[IDX2:%.*]] = getelementptr inbounds double, ptr [[ARRAY:%.*]], i64 224; CHECK-NEXT: [[IDX4:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 425; CHECK-NEXT: [[IDX6:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 626; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY]], align 827; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[IDX2]], align 828; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[IDX4]], align 829; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr [[IDX6]], align 830; CHECK-NEXT: [[TMP4:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP1]]31; CHECK-NEXT: [[TMP5:%.*]] = fsub fast <2 x double> [[TMP2]], [[TMP3]]32; CHECK-NEXT: [[TMP6:%.*]] = fadd fast <2 x double> [[TMP5]], [[TMP4]]33; CHECK-NEXT: store <2 x double> [[TMP6]], ptr [[ARRAY]], align 834; CHECK-NEXT: ret void35;36entry:37 %idx1 = getelementptr inbounds double, ptr %array, i64 138 %idx2 = getelementptr inbounds double, ptr %array, i64 239 %idx3 = getelementptr inbounds double, ptr %array, i64 340 %idx4 = getelementptr inbounds double, ptr %array, i64 441 %idx5 = getelementptr inbounds double, ptr %array, i64 542 %idx6 = getelementptr inbounds double, ptr %array, i64 643 %idx7 = getelementptr inbounds double, ptr %array, i64 744 45 %A_0 = load double, ptr %array, align 846 %A_1 = load double, ptr %idx1, align 847 %B_0 = load double, ptr %idx2, align 848 %B_1 = load double, ptr %idx3, align 849 %C_0 = load double, ptr %idx4, align 850 %C_1 = load double, ptr %idx5, align 851 %D_0 = load double, ptr %idx6, align 852 %D_1 = load double, ptr %idx7, align 853 54 %subAB_0 = fsub fast double %A_0, %B_055 %subCD_0 = fsub fast double %C_0, %D_056 57 %subAB_1 = fsub fast double %A_1, %B_158 %subCD_1 = fsub fast double %C_1, %D_159 60 %addABCD_0 = fadd fast double %subAB_0, %subCD_061 %addCDAB_1 = fadd fast double %subCD_1, %subAB_162 63 store double %addABCD_0, ptr %array, align 864 store double %addCDAB_1, ptr %idx1, align 865 ret void66}67 68 69; Check whether the look-ahead operand reordering heuristic will avoid70; bundling the alt opcodes. The vectorized code should have no shuffles.71;72; A[0] B[0] A[0] B[0] A[1] A[1] A[1] B[1]73; \ / \ / \ / \ /74; + - - +75; \ / \ /76; + +77; | |78; S[0] S[1]79;80define void @lookahead_alt1(ptr %array) {81; CHECK-LABEL: @lookahead_alt1(82; CHECK-NEXT: entry:83; CHECK-NEXT: [[IDX2:%.*]] = getelementptr inbounds double, ptr [[ARRAY:%.*]], i64 284; CHECK-NEXT: [[IDX4:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 485; CHECK-NEXT: [[IDX5:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 586; CHECK-NEXT: [[IDX6:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 687; CHECK-NEXT: [[IDX7:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 788; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY]], align 889; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[IDX2]], align 890; CHECK-NEXT: [[TMP2:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP1]]91; CHECK-NEXT: [[TMP3:%.*]] = fadd fast <2 x double> [[TMP0]], [[TMP1]]92; CHECK-NEXT: [[TMP4:%.*]] = fadd fast <2 x double> [[TMP3]], [[TMP2]]93; CHECK-NEXT: store <2 x double> [[TMP4]], ptr [[ARRAY]], align 894; CHECK-NEXT: ret void95;96entry:97 %idx1 = getelementptr inbounds double, ptr %array, i64 198 %idx2 = getelementptr inbounds double, ptr %array, i64 299 %idx3 = getelementptr inbounds double, ptr %array, i64 3100 %idx4 = getelementptr inbounds double, ptr %array, i64 4101 %idx5 = getelementptr inbounds double, ptr %array, i64 5102 %idx6 = getelementptr inbounds double, ptr %array, i64 6103 %idx7 = getelementptr inbounds double, ptr %array, i64 7104 105 %A_0 = load double, ptr %array, align 8106 %A_1 = load double, ptr %idx1, align 8107 %B_0 = load double, ptr %idx2, align 8108 %B_1 = load double, ptr %idx3, align 8109 110 %addAB_0_L = fadd fast double %A_0, %B_0111 %subAB_0_R = fsub fast double %A_0, %B_0112 113 %subAB_1_L = fsub fast double %A_1, %B_1114 %addAB_1_R = fadd fast double %A_1, %B_1115 116 %addABCD_0 = fadd fast double %addAB_0_L, %subAB_0_R117 %addCDAB_1 = fadd fast double %subAB_1_L, %addAB_1_R118 119 store double %addABCD_0, ptr %array, align 8120 store double %addCDAB_1, ptr %idx1, align 8121 ret void122}123 124 125; This code should get vectorized all the way to the loads with shuffles for126; the alt opcodes.127;128; A[0] B[0] C[0] D[0] C[1] D[1] A[1] B[1]129; \ / \ / \ / \ /130; + - + -131; \ / \ /132; + +133; | |134; S[0] S[1]135;136define void @lookahead_alt2(ptr %array) {137; CHECK-LABEL: @lookahead_alt2(138; CHECK-NEXT: entry:139; CHECK-NEXT: [[IDX2:%.*]] = getelementptr inbounds double, ptr [[ARRAY:%.*]], i64 2140; CHECK-NEXT: [[IDX4:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 4141; CHECK-NEXT: [[IDX6:%.*]] = getelementptr inbounds double, ptr [[ARRAY]], i64 6142; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY]], align 8143; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[IDX2]], align 8144; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[IDX4]], align 8145; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr [[IDX6]], align 8146; CHECK-NEXT: [[TMP4:%.*]] = fsub fast <2 x double> [[TMP2]], [[TMP3]]147; CHECK-NEXT: [[TMP5:%.*]] = fadd fast <2 x double> [[TMP2]], [[TMP3]]148; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <2 x double> [[TMP4]], <2 x double> [[TMP5]], <2 x i32> <i32 0, i32 3>149; CHECK-NEXT: [[TMP7:%.*]] = fadd fast <2 x double> [[TMP0]], [[TMP1]]150; CHECK-NEXT: [[TMP8:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP1]]151; CHECK-NEXT: [[TMP9:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP8]], <2 x i32> <i32 0, i32 3>152; CHECK-NEXT: [[TMP10:%.*]] = fadd fast <2 x double> [[TMP6]], [[TMP9]]153; CHECK-NEXT: store <2 x double> [[TMP10]], ptr [[ARRAY]], align 8154; CHECK-NEXT: ret void155;156entry:157 %idx1 = getelementptr inbounds double, ptr %array, i64 1158 %idx2 = getelementptr inbounds double, ptr %array, i64 2159 %idx3 = getelementptr inbounds double, ptr %array, i64 3160 %idx4 = getelementptr inbounds double, ptr %array, i64 4161 %idx5 = getelementptr inbounds double, ptr %array, i64 5162 %idx6 = getelementptr inbounds double, ptr %array, i64 6163 %idx7 = getelementptr inbounds double, ptr %array, i64 7164 165 %A_0 = load double, ptr %array, align 8166 %A_1 = load double, ptr %idx1, align 8167 %B_0 = load double, ptr %idx2, align 8168 %B_1 = load double, ptr %idx3, align 8169 %C_0 = load double, ptr %idx4, align 8170 %C_1 = load double, ptr %idx5, align 8171 %D_0 = load double, ptr %idx6, align 8172 %D_1 = load double, ptr %idx7, align 8173 174 %addAB_0 = fadd fast double %A_0, %B_0175 %subCD_0 = fsub fast double %C_0, %D_0176 177 %addCD_1 = fadd fast double %C_1, %D_1178 %subAB_1 = fsub fast double %A_1, %B_1179 180 %addABCD_0 = fadd fast double %addAB_0, %subCD_0181 %addCDAB_1 = fadd fast double %addCD_1, %subAB_1182 183 store double %addABCD_0, ptr %array, align 8184 store double %addCDAB_1, ptr %idx1, align 8185 ret void186}187 188 189;190; A[0] B[0] C[0] D[0] A[1] B[2] A[2] B[1]191; \ / \ / / \ / \ /192; - - U - -193; \ / \ /194; + +195; | |196; S[0] S[1]197;198; SLP should reorder the operands of the RHS add taking into consideration the cost of external uses.199; It is more profitable to reorder the operands of the RHS add, because A[1] has an external use.200 201define void @lookahead_external_uses(ptr %A, ptr %B, ptr %C, ptr %D, ptr %S, ptr %Ext1, ptr %Ext2) {202; CHECK-LABEL: @lookahead_external_uses(203; CHECK-NEXT: entry:204; CHECK-NEXT: [[IDXA1:%.*]] = getelementptr inbounds double, ptr [[A:%.*]], i64 1205; CHECK-NEXT: [[IDXB2:%.*]] = getelementptr inbounds double, ptr [[B:%.*]], i64 2206; CHECK-NEXT: [[IDXA2:%.*]] = getelementptr inbounds double, ptr [[A]], i64 2207; CHECK-NEXT: [[C0:%.*]] = load double, ptr [[C:%.*]], align 8208; CHECK-NEXT: [[D0:%.*]] = load double, ptr [[D:%.*]], align 8209; CHECK-NEXT: [[B2:%.*]] = load double, ptr [[IDXB2]], align 8210; CHECK-NEXT: [[A2:%.*]] = load double, ptr [[IDXA2]], align 8211; CHECK-NEXT: [[A1:%.*]] = load double, ptr [[IDXA1]], align 8212; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[A]], align 8213; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[B]], align 8214; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x double> [[TMP1]], double [[B2]], i32 1215; CHECK-NEXT: [[TMP3:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP2]]216; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x double> poison, double [[C0]], i32 0217; CHECK-NEXT: [[TMP5:%.*]] = insertelement <2 x double> [[TMP4]], double [[A2]], i32 1218; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x double> [[TMP1]], double [[D0]], i32 0219; CHECK-NEXT: [[TMP7:%.*]] = fsub fast <2 x double> [[TMP5]], [[TMP6]]220; CHECK-NEXT: [[TMP8:%.*]] = fadd fast <2 x double> [[TMP3]], [[TMP7]]221; CHECK-NEXT: store <2 x double> [[TMP8]], ptr [[S:%.*]], align 8222; CHECK-NEXT: store double [[A1]], ptr [[EXT1:%.*]], align 8223; CHECK-NEXT: ret void224;225entry:226 227 %IdxA1 = getelementptr inbounds double, ptr %A, i64 1228 %IdxB2 = getelementptr inbounds double, ptr %B, i64 2229 %IdxA2 = getelementptr inbounds double, ptr %A, i64 2230 %IdxB1 = getelementptr inbounds double, ptr %B, i64 1231 232 %A0 = load double, ptr %A, align 8233 %B0 = load double, ptr %B, align 8234 %C0 = load double, ptr %C, align 8235 %D0 = load double, ptr %D, align 8236 237 %A1 = load double, ptr %IdxA1, align 8238 %B2 = load double, ptr %IdxB2, align 8239 %A2 = load double, ptr %IdxA2, align 8240 %B1 = load double, ptr %IdxB1, align 8241 242 %subA0B0 = fsub fast double %A0, %B0243 %subC0D0 = fsub fast double %C0, %D0244 245 %subA1B2 = fsub fast double %A1, %B2246 %subA2B1 = fsub fast double %A2, %B1247 248 %add0 = fadd fast double %subA0B0, %subC0D0249 %add1 = fadd fast double %subA1B2, %subA2B1250 251 %IdxS1 = getelementptr inbounds double, ptr %S, i64 1252 253 store double %add0, ptr %S, align 8254 store double %add1, ptr %IdxS1, align 8255 256 ; External use257 store double %A1, ptr %Ext1, align 8258 ret void259}260 261; A[0] B[0] C[0] D[0] A[1] B[2] A[2] B[1]262; \ / \ / / \ / \ / \263; - - U1,U2,U3 - - U4,U5264; \ / \ /265; + +266; | |267; S[0] S[1]268;269;270; If we limit the users budget for the look-ahead heuristic to 2, then the271; look-ahead heuristic has no way of choosing B[1] (with 2 external users)272; over A[1] (with 3 external users).273; The result is that the operands are of the Add not reordered and the loads274; from A get vectorized instead of the loads from B.275;276define void @lookahead_limit_users_budget(ptr %A, ptr %B, ptr %C, ptr %D, ptr %S, ptr %Ext1, ptr %Ext2, ptr %Ext3, ptr %Ext4, ptr %Ext5) {277; CHECK-LABEL: @lookahead_limit_users_budget(278; CHECK-NEXT: entry:279; CHECK-NEXT: [[IDXA1:%.*]] = getelementptr inbounds double, ptr [[A:%.*]], i64 1280; CHECK-NEXT: [[IDXB2:%.*]] = getelementptr inbounds double, ptr [[B:%.*]], i64 2281; CHECK-NEXT: [[IDXA2:%.*]] = getelementptr inbounds double, ptr [[A]], i64 2282; CHECK-NEXT: [[IDXB1:%.*]] = getelementptr inbounds double, ptr [[B]], i64 1283; CHECK-NEXT: [[C0:%.*]] = load double, ptr [[C:%.*]], align 8284; CHECK-NEXT: [[D0:%.*]] = load double, ptr [[D:%.*]], align 8285; CHECK-NEXT: [[B2:%.*]] = load double, ptr [[IDXB2]], align 8286; CHECK-NEXT: [[A2:%.*]] = load double, ptr [[IDXA2]], align 8287; CHECK-NEXT: [[A1:%.*]] = load double, ptr [[IDXA1]], align 8288; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[A]], align 8289; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[B]], align 8290; CHECK-NEXT: [[B1:%.*]] = load double, ptr [[IDXB1]], align 8291; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x double> [[TMP1]], double [[B2]], i32 1292; CHECK-NEXT: [[TMP3:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP2]]293; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x double> poison, double [[C0]], i32 0294; CHECK-NEXT: [[TMP5:%.*]] = insertelement <2 x double> [[TMP4]], double [[A2]], i32 1295; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x double> [[TMP1]], double [[D0]], i32 0296; CHECK-NEXT: [[TMP7:%.*]] = fsub fast <2 x double> [[TMP5]], [[TMP6]]297; CHECK-NEXT: [[TMP8:%.*]] = fadd fast <2 x double> [[TMP3]], [[TMP7]]298; CHECK-NEXT: store <2 x double> [[TMP8]], ptr [[S:%.*]], align 8299; CHECK-NEXT: store double [[A1]], ptr [[EXT1:%.*]], align 8300; CHECK-NEXT: store double [[A1]], ptr [[EXT2:%.*]], align 8301; CHECK-NEXT: store double [[A1]], ptr [[EXT3:%.*]], align 8302; CHECK-NEXT: store double [[B1]], ptr [[EXT4:%.*]], align 8303; CHECK-NEXT: store double [[B1]], ptr [[EXT5:%.*]], align 8304; CHECK-NEXT: ret void305;306entry:307 308 %IdxA1 = getelementptr inbounds double, ptr %A, i64 1309 %IdxB2 = getelementptr inbounds double, ptr %B, i64 2310 %IdxA2 = getelementptr inbounds double, ptr %A, i64 2311 %IdxB1 = getelementptr inbounds double, ptr %B, i64 1312 313 %A0 = load double, ptr %A, align 8314 %B0 = load double, ptr %B, align 8315 %C0 = load double, ptr %C, align 8316 %D0 = load double, ptr %D, align 8317 318 %A1 = load double, ptr %IdxA1, align 8319 %B2 = load double, ptr %IdxB2, align 8320 %A2 = load double, ptr %IdxA2, align 8321 %B1 = load double, ptr %IdxB1, align 8322 323 %subA0B0 = fsub fast double %A0, %B0324 %subC0D0 = fsub fast double %C0, %D0325 326 %subA1B2 = fsub fast double %A1, %B2327 %subA2B1 = fsub fast double %A2, %B1328 329 %add0 = fadd fast double %subA0B0, %subC0D0330 %add1 = fadd fast double %subA1B2, %subA2B1331 332 %IdxS1 = getelementptr inbounds double, ptr %S, i64 1333 334 store double %add0, ptr %S, align 8335 store double %add1, ptr %IdxS1, align 8336 337 ; External uses of A1338 store double %A1, ptr %Ext1, align 8339 store double %A1, ptr %Ext2, align 8340 store double %A1, ptr %Ext3, align 8341 342 ; External uses of B1343 store double %B1, ptr %Ext4, align 8344 store double %B1, ptr %Ext5, align 8345 346 ret void347}348 349; This checks that the lookahead code does not crash when instructions with the same opcodes have different numbers of operands (in this case the calls).350 351%Class = type { i8 }352declare double @_ZN1i2ayEv(ptr)353declare double @_ZN1i2axEv()354 355define void @lookahead_crash(ptr %A, ptr %S, ptr %Arg0) {356; CHECK-LABEL: @lookahead_crash(357; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[A:%.*]], align 8358; CHECK-NEXT: [[C0:%.*]] = call double @_ZN1i2ayEv(ptr [[ARG0:%.*]])359; CHECK-NEXT: [[C1:%.*]] = call double @_ZN1i2axEv()360; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x double> poison, double [[C0]], i32 0361; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x double> [[TMP2]], double [[C1]], i32 1362; CHECK-NEXT: [[TMP4:%.*]] = fadd fast <2 x double> [[TMP1]], [[TMP3]]363; CHECK-NEXT: store <2 x double> [[TMP4]], ptr [[S:%.*]], align 8364; CHECK-NEXT: ret void365;366 %IdxA1 = getelementptr inbounds double, ptr %A, i64 1367 368 %A0 = load double, ptr %A, align 8369 %A1 = load double, ptr %IdxA1, align 8370 371 %C0 = call double @_ZN1i2ayEv(ptr %Arg0)372 %C1 = call double @_ZN1i2axEv()373 374 %add0 = fadd fast double %A0, %C0375 %add1 = fadd fast double %A1, %C1376 377 %IdxS1 = getelementptr inbounds double, ptr %S, i64 1378 store double %add0, ptr %S, align 8379 store double %add1, ptr %IdxS1, align 8380 ret void381}382 383; This checks that we choose to group consecutive extracts from the same vectors.384define void @ChecksExtractScores(ptr %storeArray, ptr %array, ptr %vecPtr1, ptr %vecPtr2) {385; CHECK-LABEL: @ChecksExtractScores(386; CHECK-NEXT: [[IDX1:%.*]] = getelementptr inbounds double, ptr [[ARRAY:%.*]], i64 1387; CHECK-NEXT: [[LOADA0:%.*]] = load double, ptr [[ARRAY]], align 4388; CHECK-NEXT: [[LOADA1:%.*]] = load double, ptr [[IDX1]], align 4389; CHECK-NEXT: [[LOADVEC:%.*]] = load <2 x double>, ptr [[VECPTR1:%.*]], align 4390; CHECK-NEXT: [[LOADVEC2:%.*]] = load <2 x double>, ptr [[VECPTR2:%.*]], align 4391; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x double> poison, double [[LOADA0]], i32 0392; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> zeroinitializer393; CHECK-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[LOADVEC]], [[TMP2]]394; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x double> poison, double [[LOADA1]], i32 0395; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[TMP4]], <2 x double> poison, <2 x i32> zeroinitializer396; CHECK-NEXT: [[TMP6:%.*]] = fmul <2 x double> [[LOADVEC2]], [[TMP5]]397; CHECK-NEXT: [[TMP7:%.*]] = fadd <2 x double> [[TMP3]], [[TMP6]]398; CHECK-NEXT: store <2 x double> [[TMP7]], ptr [[STOREARRAY:%.*]], align 8399; CHECK-NEXT: ret void400;401 %idx1 = getelementptr inbounds double, ptr %array, i64 1402 %loadA0 = load double, ptr %array, align 4403 %loadA1 = load double, ptr %idx1, align 4404 405 %loadVec = load <2 x double>, ptr %vecPtr1, align 4406 %extrA0 = extractelement <2 x double> %loadVec, i32 0407 %extrA1 = extractelement <2 x double> %loadVec, i32 1408 %loadVec2 = load <2 x double>, ptr %vecPtr2, align 4409 %extrB0 = extractelement <2 x double> %loadVec2, i32 0410 %extrB1 = extractelement <2 x double> %loadVec2, i32 1411 412 %mul0 = fmul double %extrA0, %loadA0413 %mul1 = fmul double %extrA1, %loadA0414 %mul3 = fmul double %extrB0, %loadA1415 %mul4 = fmul double %extrB1, %loadA1416 %add0 = fadd double %mul0, %mul3417 %add1 = fadd double %mul1, %mul4418 419 %sidx1 = getelementptr inbounds double, ptr %storeArray, i64 1420 store double %add0, ptr %storeArray, align 8421 store double %add1, ptr %sidx1, align 8422 ret void423}424 425 426define i1 @ExtractIdxNotConstantInt1(float %a, float %b, float %c, <4 x float> %vec, i64 %idx2) {427; SSE-LABEL: @ExtractIdxNotConstantInt1(428; SSE-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 undef429; SSE-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]430; SSE-NEXT: [[VECEXT_I276_I169:%.*]] = extractelement <4 x float> [[VEC]], i64 [[IDX2:%.*]]431; SSE-NEXT: [[TMP1:%.*]] = insertelement <2 x float> poison, float [[A:%.*]], i32 0432; SSE-NEXT: [[TMP2:%.*]] = insertelement <2 x float> [[TMP1]], float [[C:%.*]], i32 1433; SSE-NEXT: [[TMP3:%.*]] = insertelement <2 x float> poison, float [[SUB14_I167]], i32 0434; SSE-NEXT: [[TMP4:%.*]] = insertelement <2 x float> [[TMP3]], float [[VECEXT_I276_I169]], i32 1435; SSE-NEXT: [[TMP5:%.*]] = fmul <2 x float> [[TMP2]], [[TMP4]]436; SSE-NEXT: [[TMP6:%.*]] = insertelement <2 x float> <float poison, float 3.000000e+01>, float [[B:%.*]], i32 0437; SSE-NEXT: [[TMP7:%.*]] = fsub <2 x float> [[TMP5]], [[TMP6]]438; SSE-NEXT: [[TMP8:%.*]] = fadd <2 x float> [[TMP7]], <float 1.000000e+01, float 2.000000e+00>439; SSE-NEXT: [[TMP9:%.*]] = extractelement <2 x float> [[TMP8]], i32 0440; SSE-NEXT: [[TMP10:%.*]] = extractelement <2 x float> [[TMP8]], i32 1441; SSE-NEXT: [[MUL123_I184:%.*]] = fmul float [[TMP9]], [[TMP10]]442; SSE-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00443; SSE-NEXT: ret i1 [[CMP_I185]]444;445; AVX-LABEL: @ExtractIdxNotConstantInt1(446; AVX-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 undef447; AVX-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]448; AVX-NEXT: [[FM:%.*]] = fmul float [[A:%.*]], [[SUB14_I167]]449; AVX-NEXT: [[SUB25_I168:%.*]] = fsub float [[FM]], [[B:%.*]]450; AVX-NEXT: [[VECEXT_I276_I169:%.*]] = extractelement <4 x float> [[VEC]], i64 [[IDX2:%.*]]451; AVX-NEXT: [[ADD36_I173:%.*]] = fadd float [[SUB25_I168]], 1.000000e+01452; AVX-NEXT: [[MUL72_I179:%.*]] = fmul float [[C:%.*]], [[VECEXT_I276_I169]]453; AVX-NEXT: [[ADD78_I180:%.*]] = fsub float [[MUL72_I179]], 3.000000e+01454; AVX-NEXT: [[ADD79_I181:%.*]] = fadd float 2.000000e+00, [[ADD78_I180]]455; AVX-NEXT: [[MUL123_I184:%.*]] = fmul float [[ADD36_I173]], [[ADD79_I181]]456; AVX-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00457; AVX-NEXT: ret i1 [[CMP_I185]]458;459 %vecext.i291.i166 = extractelement <4 x float> %vec, i64 undef460 %sub14.i167 = fsub float undef, %vecext.i291.i166461 %fm = fmul float %a, %sub14.i167462 %sub25.i168 = fsub float %fm, %b463 %vecext.i276.i169 = extractelement <4 x float> %vec, i64 %idx2464 %add36.i173 = fadd float %sub25.i168, 10.0465 %mul72.i179 = fmul float %c, %vecext.i276.i169466 %add78.i180 = fsub float %mul72.i179, 30.0467 %add79.i181 = fadd float 2.0, %add78.i180468 %mul123.i184 = fmul float %add36.i173, %add79.i181469 %cmp.i185 = fcmp ogt float %mul123.i184, 0.000000e+00470 ret i1 %cmp.i185471}472 473 474define i1 @ExtractIdxNotConstantInt2(float %a, float %b, float %c, <4 x float> %vec, i64 %idx2) {475; SSE-LABEL: @ExtractIdxNotConstantInt2(476; SSE-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 1477; SSE-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]478; SSE-NEXT: [[VECEXT_I276_I169:%.*]] = extractelement <4 x float> [[VEC]], i64 [[IDX2:%.*]]479; SSE-NEXT: [[TMP1:%.*]] = insertelement <2 x float> poison, float [[A:%.*]], i32 0480; SSE-NEXT: [[TMP2:%.*]] = insertelement <2 x float> [[TMP1]], float [[C:%.*]], i32 1481; SSE-NEXT: [[TMP3:%.*]] = insertelement <2 x float> poison, float [[SUB14_I167]], i32 0482; SSE-NEXT: [[TMP4:%.*]] = insertelement <2 x float> [[TMP3]], float [[VECEXT_I276_I169]], i32 1483; SSE-NEXT: [[TMP5:%.*]] = fmul <2 x float> [[TMP2]], [[TMP4]]484; SSE-NEXT: [[TMP6:%.*]] = insertelement <2 x float> <float poison, float 3.000000e+01>, float [[B:%.*]], i32 0485; SSE-NEXT: [[TMP7:%.*]] = fsub <2 x float> [[TMP5]], [[TMP6]]486; SSE-NEXT: [[TMP8:%.*]] = fadd <2 x float> [[TMP7]], <float 1.000000e+01, float 2.000000e+00>487; SSE-NEXT: [[TMP9:%.*]] = extractelement <2 x float> [[TMP8]], i32 0488; SSE-NEXT: [[TMP10:%.*]] = extractelement <2 x float> [[TMP8]], i32 1489; SSE-NEXT: [[MUL123_I184:%.*]] = fmul float [[TMP9]], [[TMP10]]490; SSE-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00491; SSE-NEXT: ret i1 [[CMP_I185]]492;493; AVX-LABEL: @ExtractIdxNotConstantInt2(494; AVX-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 1495; AVX-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]496; AVX-NEXT: [[FM:%.*]] = fmul float [[A:%.*]], [[SUB14_I167]]497; AVX-NEXT: [[SUB25_I168:%.*]] = fsub float [[FM]], [[B:%.*]]498; AVX-NEXT: [[VECEXT_I276_I169:%.*]] = extractelement <4 x float> [[VEC]], i64 [[IDX2:%.*]]499; AVX-NEXT: [[ADD36_I173:%.*]] = fadd float [[SUB25_I168]], 1.000000e+01500; AVX-NEXT: [[MUL72_I179:%.*]] = fmul float [[C:%.*]], [[VECEXT_I276_I169]]501; AVX-NEXT: [[ADD78_I180:%.*]] = fsub float [[MUL72_I179]], 3.000000e+01502; AVX-NEXT: [[ADD79_I181:%.*]] = fadd float 2.000000e+00, [[ADD78_I180]]503; AVX-NEXT: [[MUL123_I184:%.*]] = fmul float [[ADD36_I173]], [[ADD79_I181]]504; AVX-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00505; AVX-NEXT: ret i1 [[CMP_I185]]506;507 %vecext.i291.i166 = extractelement <4 x float> %vec, i64 1508 %sub14.i167 = fsub float undef, %vecext.i291.i166509 %fm = fmul float %a, %sub14.i167510 %sub25.i168 = fsub float %fm, %b511 %vecext.i276.i169 = extractelement <4 x float> %vec, i64 %idx2512 %add36.i173 = fadd float %sub25.i168, 10.0513 %mul72.i179 = fmul float %c, %vecext.i276.i169514 %add78.i180 = fsub float %mul72.i179, 30.0515 %add79.i181 = fadd float 2.0, %add78.i180516 %mul123.i184 = fmul float %add36.i173, %add79.i181517 %cmp.i185 = fcmp ogt float %mul123.i184, 0.000000e+00518 ret i1 %cmp.i185519}520 521 522define i1 @foo(float %a, float %b, float %c, <4 x float> %vec, i64 %idx2) {523; SSE-LABEL: @foo(524; SSE-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 0525; SSE-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]526; SSE-NEXT: [[TMP1:%.*]] = insertelement <2 x float> poison, float [[A:%.*]], i32 0527; SSE-NEXT: [[TMP2:%.*]] = insertelement <2 x float> [[TMP1]], float [[C:%.*]], i32 1528; SSE-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[VEC]], <4 x float> poison, <2 x i32> <i32 poison, i32 1>529; SSE-NEXT: [[TMP4:%.*]] = insertelement <2 x float> [[TMP3]], float [[SUB14_I167]], i32 0530; SSE-NEXT: [[TMP5:%.*]] = fmul <2 x float> [[TMP2]], [[TMP4]]531; SSE-NEXT: [[TMP6:%.*]] = insertelement <2 x float> <float poison, float 3.000000e+01>, float [[B:%.*]], i32 0532; SSE-NEXT: [[TMP7:%.*]] = fsub <2 x float> [[TMP5]], [[TMP6]]533; SSE-NEXT: [[TMP8:%.*]] = fadd <2 x float> [[TMP7]], <float 1.000000e+01, float 2.000000e+00>534; SSE-NEXT: [[TMP9:%.*]] = extractelement <2 x float> [[TMP8]], i32 0535; SSE-NEXT: [[TMP10:%.*]] = extractelement <2 x float> [[TMP8]], i32 1536; SSE-NEXT: [[MUL123_I184:%.*]] = fmul float [[TMP9]], [[TMP10]]537; SSE-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00538; SSE-NEXT: ret i1 [[CMP_I185]]539;540; AVX-LABEL: @foo(541; AVX-NEXT: [[VECEXT_I291_I166:%.*]] = extractelement <4 x float> [[VEC:%.*]], i64 0542; AVX-NEXT: [[SUB14_I167:%.*]] = fsub float undef, [[VECEXT_I291_I166]]543; AVX-NEXT: [[FM:%.*]] = fmul float [[A:%.*]], [[SUB14_I167]]544; AVX-NEXT: [[SUB25_I168:%.*]] = fsub float [[FM]], [[B:%.*]]545; AVX-NEXT: [[VECEXT_I276_I169:%.*]] = extractelement <4 x float> [[VEC]], i64 1546; AVX-NEXT: [[ADD36_I173:%.*]] = fadd float [[SUB25_I168]], 1.000000e+01547; AVX-NEXT: [[MUL72_I179:%.*]] = fmul float [[C:%.*]], [[VECEXT_I276_I169]]548; AVX-NEXT: [[ADD78_I180:%.*]] = fsub float [[MUL72_I179]], 3.000000e+01549; AVX-NEXT: [[ADD79_I181:%.*]] = fadd float 2.000000e+00, [[ADD78_I180]]550; AVX-NEXT: [[MUL123_I184:%.*]] = fmul float [[ADD36_I173]], [[ADD79_I181]]551; AVX-NEXT: [[CMP_I185:%.*]] = fcmp ogt float [[MUL123_I184]], 0.000000e+00552; AVX-NEXT: ret i1 [[CMP_I185]]553;554 %vecext.i291.i166 = extractelement <4 x float> %vec, i64 0555 %sub14.i167 = fsub float undef, %vecext.i291.i166556 %fm = fmul float %a, %sub14.i167557 %sub25.i168 = fsub float %fm, %b558 %vecext.i276.i169 = extractelement <4 x float> %vec, i64 1559 %add36.i173 = fadd float %sub25.i168, 10.0560 %mul72.i179 = fmul float %c, %vecext.i276.i169561 %add78.i180 = fsub float %mul72.i179, 30.0562 %add79.i181 = fadd float 2.0, %add78.i180563 %mul123.i184 = fmul float %add36.i173, %add79.i181564 %cmp.i185 = fcmp ogt float %mul123.i184, 0.000000e+00565 ret i1 %cmp.i185566}567 568; Same as @ChecksExtractScores, but the extratelement vector operands do not match.569define void @ChecksExtractScores_different_vectors(ptr %storeArray, ptr %array, ptr %vecPtr1, ptr %vecPtr2, ptr %vecPtr3, ptr %vecPtr4) {570;571; SSE-LABEL: @ChecksExtractScores_different_vectors(572; SSE-NEXT: [[LOADVEC:%.*]] = load <2 x double>, ptr [[VECPTR1:%.*]], align 4573; SSE-NEXT: [[LOADVEC2:%.*]] = load <2 x double>, ptr [[VECPTR2:%.*]], align 4574; SSE-NEXT: [[LOADVEC3:%.*]] = load <2 x double>, ptr [[VECPTR3:%.*]], align 4575; SSE-NEXT: [[LOADVEC4:%.*]] = load <2 x double>, ptr [[VECPTR4:%.*]], align 4576; SSE-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[ARRAY:%.*]], align 4577; SSE-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[LOADVEC2]], <2 x double> [[LOADVEC3]], <2 x i32> <i32 1, i32 2>578; SSE-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[TMP2]], [[TMP1]]579; SSE-NEXT: [[TMP4:%.*]] = shufflevector <2 x double> [[TMP3]], <2 x double> poison, <2 x i32> <i32 1, i32 0>580; SSE-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[LOADVEC]], <2 x double> [[LOADVEC4]], <2 x i32> <i32 0, i32 3>581; SSE-NEXT: [[TMP6:%.*]] = fmul <2 x double> [[TMP5]], [[TMP1]]582; SSE-NEXT: [[TMP7:%.*]] = fadd <2 x double> [[TMP4]], [[TMP6]]583; SSE-NEXT: store <2 x double> [[TMP7]], ptr [[STOREARRAY:%.*]], align 8584; SSE-NEXT: ret void585;586; AVX-LABEL: @ChecksExtractScores_different_vectors(587; AVX-NEXT: [[IDX1:%.*]] = getelementptr inbounds double, ptr [[ARRAY:%.*]], i64 1588; AVX-NEXT: [[LOADA0:%.*]] = load double, ptr [[ARRAY]], align 4589; AVX-NEXT: [[LOADA1:%.*]] = load double, ptr [[IDX1]], align 4590; AVX-NEXT: [[LOADVEC:%.*]] = load <2 x double>, ptr [[VECPTR1:%.*]], align 4591; AVX-NEXT: [[LOADVEC2:%.*]] = load <2 x double>, ptr [[VECPTR2:%.*]], align 4592; AVX-NEXT: [[LOADVEC3:%.*]] = load <2 x double>, ptr [[VECPTR3:%.*]], align 4593; AVX-NEXT: [[LOADVEC4:%.*]] = load <2 x double>, ptr [[VECPTR4:%.*]], align 4594; AVX-NEXT: [[TMP1:%.*]] = shufflevector <2 x double> [[LOADVEC]], <2 x double> [[LOADVEC2]], <2 x i32> <i32 0, i32 3>595; AVX-NEXT: [[TMP2:%.*]] = insertelement <2 x double> poison, double [[LOADA0]], i32 0596; AVX-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> poison, <2 x i32> zeroinitializer597; AVX-NEXT: [[TMP4:%.*]] = fmul <2 x double> [[TMP1]], [[TMP3]]598; AVX-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[LOADVEC3]], <2 x double> [[LOADVEC4]], <2 x i32> <i32 0, i32 3>599; AVX-NEXT: [[TMP6:%.*]] = insertelement <2 x double> poison, double [[LOADA1]], i32 0600; AVX-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> [[TMP6]], <2 x double> poison, <2 x i32> zeroinitializer601; AVX-NEXT: [[TMP8:%.*]] = fmul <2 x double> [[TMP5]], [[TMP7]]602; AVX-NEXT: [[TMP9:%.*]] = fadd <2 x double> [[TMP4]], [[TMP8]]603; AVX-NEXT: store <2 x double> [[TMP9]], ptr [[STOREARRAY:%.*]], align 8604; AVX-NEXT: ret void605;606 %idx1 = getelementptr inbounds double, ptr %array, i64 1607 %loadA0 = load double, ptr %array, align 4608 %loadA1 = load double, ptr %idx1, align 4609 610 %loadVec = load <2 x double>, ptr %vecPtr1, align 4611 %loadVec2 = load <2 x double>, ptr %vecPtr2, align 4612 %extrA0 = extractelement <2 x double> %loadVec, i32 0613 %extrA1 = extractelement <2 x double> %loadVec2, i32 1614 %loadVec3= load <2 x double>, ptr %vecPtr3, align 4615 %loadVec4 = load <2 x double>, ptr %vecPtr4, align 4616 %extrB0 = extractelement <2 x double> %loadVec3, i32 0617 %extrB1 = extractelement <2 x double> %loadVec4, i32 1618 619 %mul0 = fmul double %extrA0, %loadA0620 %mul1 = fmul double %extrA1, %loadA0621 %mul3 = fmul double %extrB0, %loadA1622 %mul4 = fmul double %extrB1, %loadA1623 %add0 = fadd double %mul0, %mul3624 %add1 = fadd double %mul1, %mul4625 626 %sidx1 = getelementptr inbounds double, ptr %storeArray, i64 1627 store double %add0, ptr %storeArray, align 8628 store double %add1, ptr %sidx1, align 8629 ret void630}631 632; This checks that we we prefer splats rather than reverse load vectors + shuffles.633; 2-wide splat loads in x86 use a single instruction so they are quite cheap.634define double @splat_loads(ptr %array1, ptr %array2, ptr %ptrA, ptr %ptrB) {635; SSE-LABEL: @splat_loads(636; SSE-NEXT: entry:637; SSE-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY1:%.*]], align 8638; SSE-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[ARRAY2:%.*]], align 8639; SSE-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> <i32 1, i32 0>640; SSE-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[TMP0]], [[TMP2]]641; SSE-NEXT: [[TMP4:%.*]] = fmul <2 x double> [[TMP0]], [[TMP1]]642; SSE-NEXT: [[TMP5:%.*]] = fadd <2 x double> [[TMP3]], [[TMP4]]643; SSE-NEXT: [[TMP6:%.*]] = extractelement <2 x double> [[TMP5]], i32 0644; SSE-NEXT: [[TMP7:%.*]] = extractelement <2 x double> [[TMP5]], i32 1645; SSE-NEXT: [[ADD3:%.*]] = fadd double [[TMP6]], [[TMP7]]646; SSE-NEXT: ret double [[ADD3]]647;648; AVX-LABEL: @splat_loads(649; AVX-NEXT: entry:650; AVX-NEXT: [[GEP_2_1:%.*]] = getelementptr inbounds double, ptr [[ARRAY2:%.*]], i64 1651; AVX-NEXT: [[LD_2_0:%.*]] = load double, ptr [[ARRAY2]], align 8652; AVX-NEXT: [[LD_2_1:%.*]] = load double, ptr [[GEP_2_1]], align 8653; AVX-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY1:%.*]], align 8654; AVX-NEXT: [[TMP1:%.*]] = insertelement <2 x double> poison, double [[LD_2_0]], i32 0655; AVX-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> zeroinitializer656; AVX-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[TMP0]], [[TMP2]]657; AVX-NEXT: [[TMP4:%.*]] = insertelement <2 x double> poison, double [[LD_2_1]], i32 0658; AVX-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[TMP4]], <2 x double> poison, <2 x i32> zeroinitializer659; AVX-NEXT: [[TMP6:%.*]] = fmul <2 x double> [[TMP0]], [[TMP5]]660; AVX-NEXT: [[TMP7:%.*]] = fadd <2 x double> [[TMP3]], [[TMP6]]661; AVX-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[TMP7]], i32 0662; AVX-NEXT: [[TMP9:%.*]] = extractelement <2 x double> [[TMP7]], i32 1663; AVX-NEXT: [[ADD3:%.*]] = fadd double [[TMP8]], [[TMP9]]664; AVX-NEXT: ret double [[ADD3]]665;666entry:667 %gep_1_1 = getelementptr inbounds double, ptr %array1, i64 1668 %ld_1_0 = load double, ptr %array1, align 8669 %ld_1_1 = load double, ptr %gep_1_1, align 8670 671 %gep_2_1 = getelementptr inbounds double, ptr %array2, i64 1672 %ld_2_0 = load double, ptr %array2, align 8673 %ld_2_1 = load double, ptr %gep_2_1, align 8674 675 %mul1 = fmul double %ld_1_0, %ld_2_0676 %mul2 = fmul double %ld_1_1, %ld_2_0677 678 %mul3 = fmul double %ld_1_0, %ld_2_1679 %mul4 = fmul double %ld_1_1, %ld_2_1680 681 %add1 = fadd double %mul1, %mul3682 %add2 = fadd double %mul2, %mul4683 684 %add3 = fadd double %add1, %add2685 ret double %add3686}687 688 689; Same as splat_loads() but the splat load has internal uses in the slp graph.690define double @splat_loads_with_internal_uses(ptr %array1, ptr %array2, ptr %ptrA, ptr %ptrB) {691; SSE-LABEL: @splat_loads_with_internal_uses(692; SSE-NEXT: entry:693; SSE-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY1:%.*]], align 8694; SSE-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[ARRAY2:%.*]], align 8695; SSE-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> <i32 1, i32 0>696; SSE-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[TMP0]], [[TMP2]]697; SSE-NEXT: [[TMP4:%.*]] = fmul <2 x double> [[TMP0]], [[TMP1]]698; SSE-NEXT: [[TMP5:%.*]] = fadd <2 x double> [[TMP3]], [[TMP4]]699; SSE-NEXT: [[TMP6:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> zeroinitializer700; SSE-NEXT: [[TMP7:%.*]] = fsub <2 x double> [[TMP5]], [[TMP6]]701; SSE-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[TMP7]], i32 0702; SSE-NEXT: [[TMP9:%.*]] = extractelement <2 x double> [[TMP7]], i32 1703; SSE-NEXT: [[RES:%.*]] = fadd double [[TMP8]], [[TMP9]]704; SSE-NEXT: ret double [[RES]]705;706; AVX-LABEL: @splat_loads_with_internal_uses(707; AVX-NEXT: entry:708; AVX-NEXT: [[GEP_2_1:%.*]] = getelementptr inbounds double, ptr [[ARRAY2:%.*]], i64 1709; AVX-NEXT: [[LD_2_0:%.*]] = load double, ptr [[ARRAY2]], align 8710; AVX-NEXT: [[LD_2_1:%.*]] = load double, ptr [[GEP_2_1]], align 8711; AVX-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAY1:%.*]], align 8712; AVX-NEXT: [[TMP1:%.*]] = insertelement <2 x double> poison, double [[LD_2_0]], i32 0713; AVX-NEXT: [[TMP2:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> poison, <2 x i32> zeroinitializer714; AVX-NEXT: [[TMP3:%.*]] = fmul <2 x double> [[TMP0]], [[TMP2]]715; AVX-NEXT: [[TMP4:%.*]] = insertelement <2 x double> poison, double [[LD_2_1]], i32 0716; AVX-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[TMP4]], <2 x double> poison, <2 x i32> zeroinitializer717; AVX-NEXT: [[TMP6:%.*]] = fmul <2 x double> [[TMP0]], [[TMP5]]718; AVX-NEXT: [[TMP7:%.*]] = fadd <2 x double> [[TMP3]], [[TMP6]]719; AVX-NEXT: [[TMP8:%.*]] = fsub <2 x double> [[TMP7]], [[TMP2]]720; AVX-NEXT: [[TMP9:%.*]] = extractelement <2 x double> [[TMP8]], i32 0721; AVX-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[TMP8]], i32 1722; AVX-NEXT: [[RES:%.*]] = fadd double [[TMP9]], [[TMP10]]723; AVX-NEXT: ret double [[RES]]724;725entry:726 %gep_1_1 = getelementptr inbounds double, ptr %array1, i64 1727 %ld_1_0 = load double, ptr %array1, align 8728 %ld_1_1 = load double, ptr %gep_1_1, align 8729 730 %gep_2_1 = getelementptr inbounds double, ptr %array2, i64 1731 %ld_2_0 = load double, ptr %array2, align 8732 %ld_2_1 = load double, ptr %gep_2_1, align 8733 734 %mul1 = fmul double %ld_1_0, %ld_2_0735 %mul2 = fmul double %ld_1_1, %ld_2_0736 737 %mul3 = fmul double %ld_1_0, %ld_2_1738 %mul4 = fmul double %ld_1_1, %ld_2_1739 740 %add1 = fadd double %mul1, %mul3741 %add2 = fadd double %mul2, %mul4742 743 ; One more user for the broadcast of %ld_2_0744 %sub1 = fsub double %add1, %ld_2_0745 %sub2 = fsub double %add2, %ld_2_0746 747 %res = fadd double %sub1, %sub2748 749 ret double %res750}751