1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=sse4.1 | FileCheck %s --check-prefix=SSE 3; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=avx2 | FileCheck %s --check-prefix=AVX2 4; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=avx512f | FileCheck %s --check-prefix=AVX512 5 6; Verify that we don't scalarize a packed vector shift left of 16-bit 7; signed integers if the amount is a constant build_vector. 8; Check that we produce a SSE2 packed integer multiply (pmullw) instead. 9 10define <8 x i16> @test1(<8 x i16> %a) { 11; SSE-LABEL: test1: 12; SSE: # %bb.0: 13; SSE-NEXT: pmullw {{.*}}(%rip), %xmm0 14; SSE-NEXT: retq 15; 16; AVX2-LABEL: test1: 17; AVX2: # %bb.0: 18; AVX2-NEXT: vpmullw {{.*}}(%rip), %xmm0, %xmm0 19; AVX2-NEXT: retq 20; 21; AVX512-LABEL: test1: 22; AVX512: # %bb.0: 23; AVX512-NEXT: vpmullw {{.*}}(%rip), %xmm0, %xmm0 24; AVX512-NEXT: retq 25 %shl = shl <8 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> 26 ret <8 x i16> %shl 27} 28 29define <8 x i16> @test2(<8 x i16> %a) { 30; SSE-LABEL: test2: 31; SSE: # %bb.0: 32; SSE-NEXT: pmullw {{.*}}(%rip), %xmm0 33; SSE-NEXT: retq 34; 35; AVX2-LABEL: test2: 36; AVX2: # %bb.0: 37; AVX2-NEXT: vpmullw {{.*}}(%rip), %xmm0, %xmm0 38; AVX2-NEXT: retq 39; 40; AVX512-LABEL: test2: 41; AVX512: # %bb.0: 42; AVX512-NEXT: vpmullw {{.*}}(%rip), %xmm0, %xmm0 43; AVX512-NEXT: retq 44 %shl = shl <8 x i16> %a, <i16 0, i16 undef, i16 0, i16 0, i16 1, i16 undef, i16 -1, i16 1> 45 ret <8 x i16> %shl 46} 47 48; Verify that a vector shift left of 32-bit signed integers is simply expanded 49; into a SSE4.1 pmulld (instead of cvttps2dq + pmulld) if the vector of shift 50; counts is a constant build_vector. 51 52define <4 x i32> @test3(<4 x i32> %a) { 53; SSE-LABEL: test3: 54; SSE: # %bb.0: 55; SSE-NEXT: pmulld {{.*}}(%rip), %xmm0 56; SSE-NEXT: retq 57; 58; AVX2-LABEL: test3: 59; AVX2: # %bb.0: 60; AVX2-NEXT: vpsllvd {{.*}}(%rip), %xmm0, %xmm0 61; AVX2-NEXT: retq 62; 63; AVX512-LABEL: test3: 64; AVX512: # %bb.0: 65; AVX512-NEXT: vpsllvd {{.*}}(%rip), %xmm0, %xmm0 66; AVX512-NEXT: retq 67 %shl = shl <4 x i32> %a, <i32 1, i32 -1, i32 2, i32 -3> 68 ret <4 x i32> %shl 69} 70 71define <4 x i32> @test4(<4 x i32> %a) { 72; SSE-LABEL: test4: 73; SSE: # %bb.0: 74; SSE-NEXT: pmulld {{.*}}(%rip), %xmm0 75; SSE-NEXT: retq 76; 77; AVX2-LABEL: test4: 78; AVX2: # %bb.0: 79; AVX2-NEXT: vpsllvd {{.*}}(%rip), %xmm0, %xmm0 80; AVX2-NEXT: retq 81; 82; AVX512-LABEL: test4: 83; AVX512: # %bb.0: 84; AVX512-NEXT: vpsllvd {{.*}}(%rip), %xmm0, %xmm0 85; AVX512-NEXT: retq 86 %shl = shl <4 x i32> %a, <i32 0, i32 0, i32 1, i32 1> 87 ret <4 x i32> %shl 88} 89 90; If we have AVX/SSE2 but not AVX2, verify that the following shift is split 91; into two pmullw instructions. With AVX2, the test case below would produce 92; a single vpmullw. 93 94define <16 x i16> @test5(<16 x i16> %a) { 95; SSE-LABEL: test5: 96; SSE: # %bb.0: 97; SSE-NEXT: movdqa {{.*#+}} xmm2 = [2,2,4,8,128,1,512,2048] 98; SSE-NEXT: pmullw %xmm2, %xmm0 99; SSE-NEXT: pmullw %xmm2, %xmm1 100; SSE-NEXT: retq 101; 102; AVX2-LABEL: test5: 103; AVX2: # %bb.0: 104; AVX2-NEXT: vpmullw {{.*}}(%rip), %ymm0, %ymm0 105; AVX2-NEXT: retq 106; 107; AVX512-LABEL: test5: 108; AVX512: # %bb.0: 109; AVX512-NEXT: vpmullw {{.*}}(%rip), %ymm0, %ymm0 110; AVX512-NEXT: retq 111 %shl = shl <16 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> 112 ret <16 x i16> %shl 113} 114 115; If we have AVX/SSE4.1 but not AVX2, verify that the following shift is split 116; into two pmulld instructions. With AVX2, the test case below would produce 117; a single vpsllvd instead. 118 119define <8 x i32> @test6(<8 x i32> %a) { 120; SSE-LABEL: test6: 121; SSE: # %bb.0: 122; SSE-NEXT: movdqa {{.*#+}} xmm2 = [2,2,4,8] 123; SSE-NEXT: pmulld %xmm2, %xmm0 124; SSE-NEXT: pmulld %xmm2, %xmm1 125; SSE-NEXT: retq 126; 127; AVX2-LABEL: test6: 128; AVX2: # %bb.0: 129; AVX2-NEXT: vpsllvd {{.*}}(%rip), %ymm0, %ymm0 130; AVX2-NEXT: retq 131; 132; AVX512-LABEL: test6: 133; AVX512: # %bb.0: 134; AVX512-NEXT: vpsllvd {{.*}}(%rip), %ymm0, %ymm0 135; AVX512-NEXT: retq 136 %shl = shl <8 x i32> %a, <i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3> 137 ret <8 x i32> %shl 138} 139 140; With AVX2 and AVX512, the test case below should produce a sequence of 141; two vpmullw instructions. On SSE2 instead, we split the shift in four 142; parts and then we convert each part into a pmullw. 143 144define <32 x i16> @test7(<32 x i16> %a) { 145; SSE-LABEL: test7: 146; SSE: # %bb.0: 147; SSE-NEXT: movdqa {{.*#+}} xmm4 = [2,2,4,8,128,1,512,2048] 148; SSE-NEXT: pmullw %xmm4, %xmm0 149; SSE-NEXT: pmullw %xmm4, %xmm1 150; SSE-NEXT: pmullw %xmm4, %xmm2 151; SSE-NEXT: pmullw %xmm4, %xmm3 152; SSE-NEXT: retq 153; 154; AVX2-LABEL: test7: 155; AVX2: # %bb.0: 156; AVX2-NEXT: vbroadcasti128 {{.*#+}} ymm2 = [2,2,4,8,128,1,512,2048,2,2,4,8,128,1,512,2048] 157; AVX2-NEXT: # ymm2 = mem[0,1,0,1] 158; AVX2-NEXT: vpmullw %ymm2, %ymm0, %ymm0 159; AVX2-NEXT: vpmullw %ymm2, %ymm1, %ymm1 160; AVX2-NEXT: retq 161; 162; AVX512-LABEL: test7: 163; AVX512: # %bb.0: 164; AVX512-NEXT: vbroadcasti128 {{.*#+}} ymm2 = [2,2,4,8,128,1,512,2048,2,2,4,8,128,1,512,2048] 165; AVX512-NEXT: # ymm2 = mem[0,1,0,1] 166; AVX512-NEXT: vpmullw %ymm2, %ymm0, %ymm0 167; AVX512-NEXT: vpmullw %ymm2, %ymm1, %ymm1 168; AVX512-NEXT: retq 169 %shl = shl <32 x i16> %a, <i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11, i16 1, i16 1, i16 2, i16 3, i16 7, i16 0, i16 9, i16 11> 170 ret <32 x i16> %shl 171} 172 173; Similar to test7; the difference is that with AVX512 support 174; we only produce a single vpsllvd/vpsllvq instead of a pair of vpsllvd/vpsllvq. 175 176define <16 x i32> @test8(<16 x i32> %a) { 177; SSE-LABEL: test8: 178; SSE: # %bb.0: 179; SSE-NEXT: movdqa {{.*#+}} xmm4 = [2,2,4,8] 180; SSE-NEXT: pmulld %xmm4, %xmm0 181; SSE-NEXT: pmulld %xmm4, %xmm1 182; SSE-NEXT: pmulld %xmm4, %xmm2 183; SSE-NEXT: pmulld %xmm4, %xmm3 184; SSE-NEXT: retq 185; 186; AVX2-LABEL: test8: 187; AVX2: # %bb.0: 188; AVX2-NEXT: vbroadcasti128 {{.*#+}} ymm2 = [1,1,2,3,1,1,2,3] 189; AVX2-NEXT: # ymm2 = mem[0,1,0,1] 190; AVX2-NEXT: vpsllvd %ymm2, %ymm0, %ymm0 191; AVX2-NEXT: vpsllvd %ymm2, %ymm1, %ymm1 192; AVX2-NEXT: retq 193; 194; AVX512-LABEL: test8: 195; AVX512: # %bb.0: 196; AVX512-NEXT: vpsllvd {{.*}}(%rip), %zmm0, %zmm0 197; AVX512-NEXT: retq 198 %shl = shl <16 x i32> %a, <i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3, i32 1, i32 1, i32 2, i32 3> 199 ret <16 x i32> %shl 200} 201 202; The shift from 'test9' gets shifted separately and blended if we don't have AVX2/AVX512f support. 203 204define <8 x i64> @test9(<8 x i64> %a) { 205; SSE-LABEL: test9: 206; SSE: # %bb.0: 207; SSE-NEXT: movdqa %xmm1, %xmm4 208; SSE-NEXT: psllq $3, %xmm4 209; SSE-NEXT: psllq $2, %xmm1 210; SSE-NEXT: pblendw {{.*#+}} xmm1 = xmm1[0,1,2,3],xmm4[4,5,6,7] 211; SSE-NEXT: movdqa %xmm3, %xmm4 212; SSE-NEXT: psllq $3, %xmm4 213; SSE-NEXT: psllq $2, %xmm3 214; SSE-NEXT: pblendw {{.*#+}} xmm3 = xmm3[0,1,2,3],xmm4[4,5,6,7] 215; SSE-NEXT: paddq %xmm0, %xmm0 216; SSE-NEXT: paddq %xmm2, %xmm2 217; SSE-NEXT: retq 218; 219; AVX2-LABEL: test9: 220; AVX2: # %bb.0: 221; AVX2-NEXT: vmovdqa {{.*#+}} ymm2 = [1,1,2,3] 222; AVX2-NEXT: vpsllvq %ymm2, %ymm0, %ymm0 223; AVX2-NEXT: vpsllvq %ymm2, %ymm1, %ymm1 224; AVX2-NEXT: retq 225; 226; AVX512-LABEL: test9: 227; AVX512: # %bb.0: 228; AVX512-NEXT: vpsllvq {{.*}}(%rip), %zmm0, %zmm0 229; AVX512-NEXT: retq 230 %shl = shl <8 x i64> %a, <i64 1, i64 1, i64 2, i64 3, i64 1, i64 1, i64 2, i64 3> 231 ret <8 x i64> %shl 232} 233