1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -vector-combine -data-layout=e < %s | FileCheck %s 3; RUN: opt -S -vector-combine -data-layout=E < %s | FileCheck %s 4 5define void @insert_store(<16 x i8>* %q, i8 zeroext %s) { 6; CHECK-LABEL: @insert_store( 7; CHECK-NEXT: entry: 8; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, <16 x i8>* [[Q:%.*]], i32 0, i32 3 9; CHECK-NEXT: store i8 [[S:%.*]], i8* [[TMP0]], align 1 10; CHECK-NEXT: ret void 11; 12entry: 13 %0 = load <16 x i8>, <16 x i8>* %q 14 %vecins = insertelement <16 x i8> %0, i8 %s, i32 3 15 store <16 x i8> %vecins, <16 x i8>* %q, align 16 16 ret void 17} 18 19define void @insert_store_i16_align1(<8 x i16>* %q, i16 zeroext %s) { 20; CHECK-LABEL: @insert_store_i16_align1( 21; CHECK-NEXT: entry: 22; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, <8 x i16>* [[Q:%.*]], i32 0, i32 3 23; CHECK-NEXT: store i16 [[S:%.*]], i16* [[TMP0]], align 1 24; CHECK-NEXT: ret void 25; 26entry: 27 %0 = load <8 x i16>, <8 x i16>* %q 28 %vecins = insertelement <8 x i16> %0, i16 %s, i32 3 29 store <8 x i16> %vecins, <8 x i16>* %q, align 1 30 ret void 31} 32 33; To verify case when index is out of bounds 34define void @insert_store_outofbounds(<8 x i16>* %q, i16 zeroext %s) { 35; CHECK-LABEL: @insert_store_outofbounds( 36; CHECK-NEXT: entry: 37; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[Q:%.*]], align 16 38; CHECK-NEXT: [[VECINS:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 9 39; CHECK-NEXT: store <8 x i16> [[VECINS]], <8 x i16>* [[Q]], align 16 40; CHECK-NEXT: ret void 41; 42entry: 43 %0 = load <8 x i16>, <8 x i16>* %q 44 %vecins = insertelement <8 x i16> %0, i16 %s, i32 9 45 store <8 x i16> %vecins, <8 x i16>* %q 46 ret void 47} 48 49define void @insert_store_vscale(<vscale x 8 x i16>* %q, i16 zeroext %s) { 50; CHECK-LABEL: @insert_store_vscale( 51; CHECK-NEXT: entry: 52; CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 8 x i16>, <vscale x 8 x i16>* [[Q:%.*]], align 16 53; CHECK-NEXT: [[VECINS:%.*]] = insertelement <vscale x 8 x i16> [[TMP0]], i16 [[S:%.*]], i32 3 54; CHECK-NEXT: store <vscale x 8 x i16> [[VECINS]], <vscale x 8 x i16>* [[Q]], align 16 55; CHECK-NEXT: ret void 56; 57entry: 58 %0 = load <vscale x 8 x i16>, <vscale x 8 x i16>* %q 59 %vecins = insertelement <vscale x 8 x i16> %0, i16 %s, i32 3 60 store <vscale x 8 x i16> %vecins, <vscale x 8 x i16>* %q 61 ret void 62} 63 64define void @insert_store_v9i4(<9 x i4>* %q, i4 zeroext %s) { 65; CHECK-LABEL: @insert_store_v9i4( 66; CHECK-NEXT: entry: 67; CHECK-NEXT: [[TMP0:%.*]] = load <9 x i4>, <9 x i4>* [[Q:%.*]], align 16 68; CHECK-NEXT: [[VECINS:%.*]] = insertelement <9 x i4> [[TMP0]], i4 [[S:%.*]], i32 3 69; CHECK-NEXT: store <9 x i4> [[VECINS]], <9 x i4>* [[Q]], align 1 70; CHECK-NEXT: ret void 71; 72entry: 73 %0 = load <9 x i4>, <9 x i4>* %q 74 %vecins = insertelement <9 x i4> %0, i4 %s, i32 3 75 store <9 x i4> %vecins, <9 x i4>* %q, align 1 76 ret void 77} 78 79define void @insert_store_v4i27(<4 x i27>* %q, i27 zeroext %s) { 80; CHECK-LABEL: @insert_store_v4i27( 81; CHECK-NEXT: entry: 82; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i27>, <4 x i27>* [[Q:%.*]], align 16 83; CHECK-NEXT: [[VECINS:%.*]] = insertelement <4 x i27> [[TMP0]], i27 [[S:%.*]], i32 3 84; CHECK-NEXT: store <4 x i27> [[VECINS]], <4 x i27>* [[Q]], align 1 85; CHECK-NEXT: ret void 86; 87entry: 88 %0 = load <4 x i27>, <4 x i27>* %q 89 %vecins = insertelement <4 x i27> %0, i27 %s, i32 3 90 store <4 x i27> %vecins, <4 x i27>* %q, align 1 91 ret void 92} 93 94define void @insert_store_blk_differ(<8 x i16>* %q, i16 zeroext %s) { 95; CHECK-LABEL: @insert_store_blk_differ( 96; CHECK-NEXT: entry: 97; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[Q:%.*]], align 16 98; CHECK-NEXT: br label [[CONT:%.*]] 99; CHECK: cont: 100; CHECK-NEXT: [[VECINS:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 3 101; CHECK-NEXT: store <8 x i16> [[VECINS]], <8 x i16>* [[Q]], align 16 102; CHECK-NEXT: ret void 103; 104entry: 105 %0 = load <8 x i16>, <8 x i16>* %q 106 br label %cont 107cont: 108 %vecins = insertelement <8 x i16> %0, i16 %s, i32 3 109 store <8 x i16> %vecins, <8 x i16>* %q 110 ret void 111} 112 113define void @insert_store_nonconst(<16 x i8>* %q, i8 zeroext %s, i32 %idx) { 114; CHECK-LABEL: @insert_store_nonconst( 115; CHECK-NEXT: entry: 116; CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[Q:%.*]], align 16 117; CHECK-NEXT: [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX:%.*]] 118; CHECK-NEXT: store <16 x i8> [[VECINS]], <16 x i8>* [[Q]], align 16 119; CHECK-NEXT: ret void 120; 121entry: 122 %0 = load <16 x i8>, <16 x i8>* %q 123 %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx 124 store <16 x i8> %vecins, <16 x i8>* %q 125 ret void 126} 127 128define void @insert_store_ptr_strip(<16 x i8>* %q, i8 zeroext %s) { 129; CHECK-LABEL: @insert_store_ptr_strip( 130; CHECK-NEXT: entry: 131; CHECK-NEXT: [[ADDR0:%.*]] = bitcast <16 x i8>* [[Q:%.*]] to <2 x i64>* 132; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, <16 x i8>* [[Q]], i32 0, i32 3 133; CHECK-NEXT: store i8 [[S:%.*]], i8* [[TMP0]], align 1 134; CHECK-NEXT: ret void 135; 136entry: 137 %0 = load <16 x i8>, <16 x i8>* %q 138 %vecins = insertelement <16 x i8> %0, i8 %s, i32 3 139 %addr0 = bitcast <16 x i8>* %q to <2 x i64>* 140 %addr1 = getelementptr <2 x i64>, <2 x i64>* %addr0, i64 0 141 %addr2 = bitcast <2 x i64>* %addr1 to <16 x i8>* 142 store <16 x i8> %vecins, <16 x i8>* %addr2 143 ret void 144} 145 146define void @volatile_update(<16 x i8>* %q, <16 x i8>* %p, i8 zeroext %s) { 147; CHECK-LABEL: @volatile_update( 148; CHECK-NEXT: entry: 149; CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[Q:%.*]], align 16 150; CHECK-NEXT: [[VECINS0:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 3 151; CHECK-NEXT: store volatile <16 x i8> [[VECINS0]], <16 x i8>* [[Q]], align 16 152; CHECK-NEXT: [[TMP1:%.*]] = load volatile <16 x i8>, <16 x i8>* [[P:%.*]], align 16 153; CHECK-NEXT: [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP1]], i8 [[S]], i32 1 154; CHECK-NEXT: store <16 x i8> [[VECINS1]], <16 x i8>* [[P]], align 16 155; CHECK-NEXT: ret void 156; 157entry: 158 %0 = load <16 x i8>, <16 x i8>* %q 159 %vecins0 = insertelement <16 x i8> %0, i8 %s, i32 3 160 store volatile <16 x i8> %vecins0, <16 x i8>* %q 161 162 %1 = load volatile <16 x i8>, <16 x i8>* %p 163 %vecins1 = insertelement <16 x i8> %1, i8 %s, i32 1 164 store <16 x i8> %vecins1, <16 x i8>* %p 165 ret void 166} 167 168define void @insert_store_addr_differ(<16 x i8>* %p, <16 x i8>* %q, i8 %s) { 169; CHECK-LABEL: @insert_store_addr_differ( 170; CHECK-NEXT: entry: 171; CHECK-NEXT: [[LD:%.*]] = load <16 x i8>, <16 x i8>* [[P:%.*]], align 16 172; CHECK-NEXT: [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3 173; CHECK-NEXT: store <16 x i8> [[INS]], <16 x i8>* [[Q:%.*]], align 16 174; CHECK-NEXT: ret void 175; 176entry: 177 %ld = load <16 x i8>, <16 x i8>* %p 178 %ins = insertelement <16 x i8> %ld, i8 %s, i32 3 179 store <16 x i8> %ins, <16 x i8>* %q 180 ret void 181} 182 183; We can't transform if any instr could modify memory in between. 184define void @insert_store_mem_modify(<16 x i8>* %p, <16 x i8>* %q, <16 x i8>* noalias %r, i8 %s, i32 %m) { 185; CHECK-LABEL: @insert_store_mem_modify( 186; CHECK-NEXT: entry: 187; CHECK-NEXT: [[LD:%.*]] = load <16 x i8>, <16 x i8>* [[P:%.*]], align 16 188; CHECK-NEXT: store <16 x i8> zeroinitializer, <16 x i8>* [[Q:%.*]], align 16 189; CHECK-NEXT: [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3 190; CHECK-NEXT: store <16 x i8> [[INS]], <16 x i8>* [[P]], align 16 191; CHECK-NEXT: store <16 x i8> zeroinitializer, <16 x i8>* [[R:%.*]], align 16 192; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, <16 x i8>* [[Q]], i32 0, i32 7 193; CHECK-NEXT: store i8 [[S]], i8* [[TMP0]], align 1 194; CHECK-NEXT: [[PTR0:%.*]] = bitcast <16 x i8>* [[P]] to <4 x i32>* 195; CHECK-NEXT: [[LD3:%.*]] = load <4 x i32>, <4 x i32>* [[PTR0]], align 16 196; CHECK-NEXT: store <16 x i8> zeroinitializer, <16 x i8>* [[P]], align 16 197; CHECK-NEXT: [[INS3:%.*]] = insertelement <4 x i32> [[LD3]], i32 [[M:%.*]], i32 0 198; CHECK-NEXT: store <4 x i32> [[INS3]], <4 x i32>* [[PTR0]], align 16 199; CHECK-NEXT: ret void 200; 201entry: 202 ; p may alias q 203 %ld = load <16 x i8>, <16 x i8>* %p 204 store <16 x i8> zeroinitializer, <16 x i8>* %q 205 %ins = insertelement <16 x i8> %ld, i8 %s, i32 3 206 store <16 x i8> %ins, <16 x i8>* %p 207 208 ; p never aliases r 209 %ld2 = load <16 x i8>, <16 x i8>* %q 210 store <16 x i8> zeroinitializer, <16 x i8>* %r 211 %ins2 = insertelement <16 x i8> %ld2, i8 %s, i32 7 212 store <16 x i8> %ins2, <16 x i8>* %q 213 214 ; p must alias ptr0 215 %ptr0 = bitcast <16 x i8>* %p to <4 x i32>* 216 %ld3 = load <4 x i32>, <4 x i32>* %ptr0 217 store <16 x i8> zeroinitializer, <16 x i8>* %p 218 %ins3 = insertelement <4 x i32> %ld3, i32 %m, i32 0 219 store <4 x i32> %ins3, <4 x i32>* %ptr0 220 221 ret void 222} 223 224; Check cases when calls may modify memory 225define void @insert_store_with_call(<16 x i8>* %p, <16 x i8>* %q, i8 %s) { 226; CHECK-LABEL: @insert_store_with_call( 227; CHECK-NEXT: entry: 228; CHECK-NEXT: [[LD:%.*]] = load <16 x i8>, <16 x i8>* [[P:%.*]], align 16 229; CHECK-NEXT: call void @maywrite(<16 x i8>* [[P]]) 230; CHECK-NEXT: [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3 231; CHECK-NEXT: store <16 x i8> [[INS]], <16 x i8>* [[P]], align 16 232; CHECK-NEXT: call void @foo() 233; CHECK-NEXT: call void @nowrite(<16 x i8>* [[P]]) 234; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, <16 x i8>* [[P]], i32 0, i32 7 235; CHECK-NEXT: store i8 [[S]], i8* [[TMP0]], align 1 236; CHECK-NEXT: ret void 237; 238entry: 239 %ld = load <16 x i8>, <16 x i8>* %p 240 call void @maywrite(<16 x i8>* %p) 241 %ins = insertelement <16 x i8> %ld, i8 %s, i32 3 242 store <16 x i8> %ins, <16 x i8>* %p 243 call void @foo() ; Barrier 244 %ld2 = load <16 x i8>, <16 x i8>* %p 245 call void @nowrite(<16 x i8>* %p) 246 %ins2 = insertelement <16 x i8> %ld2, i8 %s, i32 7 247 store <16 x i8> %ins2, <16 x i8>* %p 248 ret void 249} 250 251declare void @foo() 252declare void @maywrite(<16 x i8>*) 253declare void @nowrite(<16 x i8>*) readonly 254 255; To test if number of instructions in-between exceeds the limit (default 30), 256; the combine will quit. 257define i32 @insert_store_maximum_scan_instrs(i32 %arg, i16* %arg1, <16 x i8>* %arg2, i8 zeroext %arg3) { 258; CHECK-LABEL: @insert_store_maximum_scan_instrs( 259; CHECK-NEXT: bb: 260; CHECK-NEXT: [[I:%.*]] = or i32 [[ARG:%.*]], 1 261; CHECK-NEXT: [[I4:%.*]] = load <16 x i8>, <16 x i8>* [[ARG2:%.*]], align 16 262; CHECK-NEXT: [[I5:%.*]] = tail call i32 @bar(i32 [[I]], i1 true) 263; CHECK-NEXT: [[I6:%.*]] = shl i32 [[ARG]], [[I5]] 264; CHECK-NEXT: [[I7:%.*]] = lshr i32 [[I6]], 26 265; CHECK-NEXT: [[I8:%.*]] = trunc i32 [[I7]] to i8 266; CHECK-NEXT: [[I9:%.*]] = and i8 [[I8]], 31 267; CHECK-NEXT: [[I10:%.*]] = lshr i32 [[I6]], 11 268; CHECK-NEXT: [[I11:%.*]] = and i32 [[I10]], 32767 269; CHECK-NEXT: [[I12:%.*]] = zext i8 [[I9]] to i64 270; CHECK-NEXT: [[I13:%.*]] = getelementptr inbounds i16, i16* [[ARG1:%.*]], i64 [[I12]] 271; CHECK-NEXT: [[I14:%.*]] = load i16, i16* [[I13]], align 2 272; CHECK-NEXT: [[I15:%.*]] = zext i16 [[I14]] to i32 273; CHECK-NEXT: [[I16:%.*]] = add nuw nsw i8 [[I9]], 1 274; CHECK-NEXT: [[I17:%.*]] = zext i8 [[I16]] to i64 275; CHECK-NEXT: [[I18:%.*]] = getelementptr inbounds i16, i16* [[ARG1]], i64 [[I17]] 276; CHECK-NEXT: [[I19:%.*]] = load i16, i16* [[I18]], align 2 277; CHECK-NEXT: [[I20:%.*]] = zext i16 [[I19]] to i32 278; CHECK-NEXT: [[I21:%.*]] = sub nsw i32 [[I20]], [[I15]] 279; CHECK-NEXT: [[I22:%.*]] = mul nsw i32 [[I11]], [[I21]] 280; CHECK-NEXT: [[I23:%.*]] = ashr i32 [[I22]], 15 281; CHECK-NEXT: [[I24:%.*]] = shl nuw nsw i32 [[I5]], 15 282; CHECK-NEXT: [[I25:%.*]] = xor i32 [[I24]], 1015808 283; CHECK-NEXT: [[I26:%.*]] = add nuw nsw i32 [[I25]], [[I15]] 284; CHECK-NEXT: [[I27:%.*]] = add nsw i32 [[I26]], [[I23]] 285; CHECK-NEXT: [[I28:%.*]] = sitofp i32 [[ARG]] to double 286; CHECK-NEXT: [[I29:%.*]] = tail call double @llvm.log2.f64(double [[I28]]) 287; CHECK-NEXT: [[I30:%.*]] = fptosi double [[I29]] to i32 288; CHECK-NEXT: [[I31:%.*]] = shl nsw i32 [[I30]], 15 289; CHECK-NEXT: [[I32:%.*]] = or i32 [[I31]], 4 290; CHECK-NEXT: [[I33:%.*]] = icmp eq i32 [[I27]], [[I32]] 291; CHECK-NEXT: [[I34:%.*]] = select i1 [[I33]], i32 [[ARG]], i32 [[I31]] 292; CHECK-NEXT: [[I35:%.*]] = lshr i32 [[I34]], 1 293; CHECK-NEXT: [[I36:%.*]] = insertelement <16 x i8> [[I4]], i8 [[ARG3:%.*]], i32 3 294; CHECK-NEXT: store <16 x i8> [[I36]], <16 x i8>* [[ARG2]], align 16 295; CHECK-NEXT: ret i32 [[I35]] 296; 297bb: 298 %i = or i32 %arg, 1 299 %i4 = load <16 x i8>, <16 x i8>* %arg2, align 16 300 %i5 = tail call i32 @bar(i32 %i, i1 true) 301 %i6 = shl i32 %arg, %i5 302 %i7 = lshr i32 %i6, 26 303 %i8 = trunc i32 %i7 to i8 304 %i9 = and i8 %i8, 31 305 %i10 = lshr i32 %i6, 11 306 %i11 = and i32 %i10, 32767 307 %i12 = zext i8 %i9 to i64 308 %i13 = getelementptr inbounds i16, i16* %arg1, i64 %i12 309 %i14 = load i16, i16* %i13, align 2 310 %i15 = zext i16 %i14 to i32 311 %i16 = add nuw nsw i8 %i9, 1 312 %i17 = zext i8 %i16 to i64 313 %i18 = getelementptr inbounds i16, i16* %arg1, i64 %i17 314 %i19 = load i16, i16* %i18, align 2 315 %i20 = zext i16 %i19 to i32 316 %i21 = sub nsw i32 %i20, %i15 317 %i22 = mul nsw i32 %i11, %i21 318 %i23 = ashr i32 %i22, 15 319 %i24 = shl nuw nsw i32 %i5, 15 320 %i25 = xor i32 %i24, 1015808 321 %i26 = add nuw nsw i32 %i25, %i15 322 %i27 = add nsw i32 %i26, %i23 323 %i28 = sitofp i32 %arg to double 324 %i29 = tail call double @llvm.log2.f64(double %i28) 325 %i30 = fptosi double %i29 to i32 326 %i31 = shl nsw i32 %i30, 15 327 %i32 = or i32 %i31, 4 328 %i33 = icmp eq i32 %i27, %i32 329 %i34 = select i1 %i33, i32 %arg, i32 %i31 330 %i35 = lshr i32 %i34, 1 331 %i36 = insertelement <16 x i8> %i4, i8 %arg3, i32 3 332 store <16 x i8> %i36, <16 x i8>* %arg2, align 16 333 ret i32 %i35 334} 335 336declare i32 @bar(i32, i1) readonly 337declare double @llvm.log2.f64(double) 338