1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -S %s | FileCheck --check-prefixes=CHECK,LIMIT-DEFAULT %s 3; RUN: opt -vector-combine -enable-new-pm=false -mtriple=arm64-apple-darwinos -S %s | FileCheck --check-prefixes=CHECK,LIMIT-DEFAULT %s 4; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -vector-combine-max-scan-instrs=2 -S %s | FileCheck --check-prefixes=CHECK,LIMIT2 %s 5 6define i32 @load_extract_idx_0(<4 x i32>* %x) { 7; CHECK-LABEL: @load_extract_idx_0( 8; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3 9; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 4 10; CHECK-NEXT: ret i32 [[R]] 11; 12 %lv = load <4 x i32>, <4 x i32>* %x 13 %r = extractelement <4 x i32> %lv, i32 3 14 ret i32 %r 15} 16 17; If the original load had a smaller alignment than the scalar type, the 18; smaller alignment should be used. 19define i32 @load_extract_idx_0_small_alignment(<4 x i32>* %x) { 20; CHECK-LABEL: @load_extract_idx_0_small_alignment( 21; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3 22; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 2 23; CHECK-NEXT: ret i32 [[R]] 24; 25 %lv = load <4 x i32>, <4 x i32>* %x, align 2 26 %r = extractelement <4 x i32> %lv, i32 3 27 ret i32 %r 28} 29 30define i32 @load_extract_idx_1(<4 x i32>* %x) { 31; CHECK-LABEL: @load_extract_idx_1( 32; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 1 33; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 4 34; CHECK-NEXT: ret i32 [[R]] 35; 36 %lv = load <4 x i32>, <4 x i32>* %x 37 %r = extractelement <4 x i32> %lv, i32 1 38 ret i32 %r 39} 40 41define i32 @load_extract_idx_2(<4 x i32>* %x) { 42; CHECK-LABEL: @load_extract_idx_2( 43; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 44; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 45; CHECK-NEXT: ret i32 [[R]] 46; 47 %lv = load <4 x i32>, <4 x i32>* %x 48 %r = extractelement <4 x i32> %lv, i32 2 49 ret i32 %r 50} 51 52define i32 @load_extract_idx_3(<4 x i32>* %x) { 53; CHECK-LABEL: @load_extract_idx_3( 54; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3 55; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 4 56; CHECK-NEXT: ret i32 [[R]] 57; 58 %lv = load <4 x i32>, <4 x i32>* %x 59 %r = extractelement <4 x i32> %lv, i32 3 60 ret i32 %r 61} 62 63; Out-of-bounds index for extractelement, should not be converted to narrow 64; load, because it would introduce a dereference of a poison pointer. 65define i32 @load_extract_idx_4(<4 x i32>* %x) { 66; CHECK-LABEL: @load_extract_idx_4( 67; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 68; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 4 69; CHECK-NEXT: ret i32 [[R]] 70; 71 %lv = load <4 x i32>, <4 x i32>* %x 72 %r = extractelement <4 x i32> %lv, i32 4 73 ret i32 %r 74} 75 76define i32 @load_extract_idx_var_i64(<4 x i32>* %x, i64 %idx) { 77; CHECK-LABEL: @load_extract_idx_var_i64( 78; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 79; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX:%.*]] 80; CHECK-NEXT: ret i32 [[R]] 81; 82 %lv = load <4 x i32>, <4 x i32>* %x 83 %r = extractelement <4 x i32> %lv, i64 %idx 84 ret i32 %r 85} 86 87declare void @maythrow() readnone 88 89define i32 @load_extract_idx_var_i64_known_valid_by_assume(<4 x i32>* %x, i64 %idx) { 90; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume( 91; CHECK-NEXT: entry: 92; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 93; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 94; CHECK-NEXT: call void @maythrow() 95; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX]] 96; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 97; CHECK-NEXT: ret i32 [[R]] 98; 99entry: 100 %cmp = icmp ult i64 %idx, 4 101 call void @llvm.assume(i1 %cmp) 102 %lv = load <4 x i32>, <4 x i32>* %x 103 call void @maythrow() 104 %r = extractelement <4 x i32> %lv, i64 %idx 105 ret i32 %r 106} 107 108define i32 @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(<4 x i32>* %x, i64 %idx) { 109; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume_after_load( 110; CHECK-NEXT: entry: 111; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 112; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 113; CHECK-NEXT: call void @maythrow() 114; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 115; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 116; CHECK-NEXT: ret i32 [[R]] 117; 118entry: 119 %cmp = icmp ult i64 %idx, 4 120 %lv = load <4 x i32>, <4 x i32>* %x 121 call void @maythrow() 122 call void @llvm.assume(i1 %cmp) 123 %r = extractelement <4 x i32> %lv, i64 %idx 124 ret i32 %r 125} 126 127define i32 @load_extract_idx_var_i64_not_known_valid_by_assume(<4 x i32>* %x, i64 %idx) { 128; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume( 129; CHECK-NEXT: entry: 130; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 5 131; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 132; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 133; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 134; CHECK-NEXT: ret i32 [[R]] 135; 136entry: 137 %cmp = icmp ult i64 %idx, 5 138 call void @llvm.assume(i1 %cmp) 139 %lv = load <4 x i32>, <4 x i32>* %x 140 %r = extractelement <4 x i32> %lv, i64 %idx 141 ret i32 %r 142} 143 144declare void @llvm.assume(i1) 145 146define i32 @load_extract_idx_var_i64_known_valid_by_and(<4 x i32>* %x, i64 %idx) { 147; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and( 148; CHECK-NEXT: entry: 149; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3 150; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 151; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 152; CHECK-NEXT: ret i32 [[R]] 153; 154entry: 155 %idx.clamped = and i64 %idx, 3 156 %lv = load <4 x i32>, <4 x i32>* %x 157 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 158 ret i32 %r 159} 160 161define i32 @load_extract_idx_var_i64_known_valid_by_and_noundef(<4 x i32>* %x, i64 noundef %idx) { 162; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and_noundef( 163; CHECK-NEXT: entry: 164; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3 165; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]] 166; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 167; CHECK-NEXT: ret i32 [[R]] 168; 169entry: 170 %idx.clamped = and i64 %idx, 3 171 %lv = load <4 x i32>, <4 x i32>* %x 172 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 173 ret i32 %r 174} 175 176define i32 @load_extract_idx_var_i64_not_known_valid_by_and(<4 x i32>* %x, i64 %idx) { 177; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_and( 178; CHECK-NEXT: entry: 179; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 4 180; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 181; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 182; CHECK-NEXT: ret i32 [[R]] 183; 184entry: 185 %idx.clamped = and i64 %idx, 4 186 %lv = load <4 x i32>, <4 x i32>* %x 187 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 188 ret i32 %r 189} 190 191define i32 @load_extract_idx_var_i64_known_valid_by_urem(<4 x i32>* %x, i64 %idx) { 192; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem( 193; CHECK-NEXT: entry: 194; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4 195; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 196; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 197; CHECK-NEXT: ret i32 [[R]] 198; 199entry: 200 %idx.clamped = urem i64 %idx, 4 201 %lv = load <4 x i32>, <4 x i32>* %x 202 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 203 ret i32 %r 204} 205 206define i32 @load_extract_idx_var_i64_known_valid_by_urem_noundef(<4 x i32>* %x, i64 noundef %idx) { 207; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem_noundef( 208; CHECK-NEXT: entry: 209; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4 210; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]] 211; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 212; CHECK-NEXT: ret i32 [[R]] 213; 214entry: 215 %idx.clamped = urem i64 %idx, 4 216 %lv = load <4 x i32>, <4 x i32>* %x 217 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 218 ret i32 %r 219} 220 221define i32 @load_extract_idx_var_i64_not_known_valid_by_urem(<4 x i32>* %x, i64 %idx) { 222; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_urem( 223; CHECK-NEXT: entry: 224; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 5 225; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 226; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 227; CHECK-NEXT: ret i32 [[R]] 228; 229entry: 230 %idx.clamped = urem i64 %idx, 5 231 %lv = load <4 x i32>, <4 x i32>* %x 232 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 233 ret i32 %r 234} 235 236define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) { 237; CHECK-LABEL: @load_extract_idx_var_i32( 238; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 239; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]] 240; CHECK-NEXT: ret i32 [[R]] 241; 242 %lv = load <4 x i32>, <4 x i32>* %x 243 %r = extractelement <4 x i32> %lv, i32 %idx 244 ret i32 %r 245} 246 247declare void @clobber() 248 249define i32 @load_extract_clobber_call_before(<4 x i32>* %x) { 250; CHECK-LABEL: @load_extract_clobber_call_before( 251; CHECK-NEXT: call void @clobber() 252; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 253; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 254; CHECK-NEXT: ret i32 [[R]] 255; 256 call void @clobber() 257 %lv = load <4 x i32>, <4 x i32>* %x 258 %r = extractelement <4 x i32> %lv, i32 2 259 ret i32 %r 260} 261 262define i32 @load_extract_clobber_call_between(<4 x i32>* %x) { 263; CHECK-LABEL: @load_extract_clobber_call_between( 264; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 265; CHECK-NEXT: call void @clobber() 266; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 267; CHECK-NEXT: ret i32 [[R]] 268; 269 %lv = load <4 x i32>, <4 x i32>* %x 270 call void @clobber() 271 %r = extractelement <4 x i32> %lv, i32 2 272 ret i32 %r 273} 274 275define i32 @load_extract_clobber_call_after(<4 x i32>* %x) { 276; CHECK-LABEL: @load_extract_clobber_call_after( 277; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 278; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 279; CHECK-NEXT: call void @clobber() 280; CHECK-NEXT: ret i32 [[R]] 281; 282 %lv = load <4 x i32>, <4 x i32>* %x 283 %r = extractelement <4 x i32> %lv, i32 2 284 call void @clobber() 285 ret i32 %r 286} 287 288define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) { 289; CHECK-LABEL: @load_extract_clobber_store_before( 290; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 291; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 292; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 293; CHECK-NEXT: ret i32 [[R]] 294; 295 store i8 0, i8* %y 296 %lv = load <4 x i32>, <4 x i32>* %x 297 %r = extractelement <4 x i32> %lv, i32 2 298 ret i32 %r 299} 300 301define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) { 302; CHECK-LABEL: @load_extract_clobber_store_between( 303; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 304; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 305; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 306; CHECK-NEXT: ret i32 [[R]] 307; 308 %lv = load <4 x i32>, <4 x i32>* %x 309 store i8 0, i8* %y 310 %r = extractelement <4 x i32> %lv, i32 2 311 ret i32 %r 312} 313 314define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 315; CHECK-LABEL: @load_extract_clobber_store_between_limit( 316; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 317; CHECK-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 318; CHECK-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 319; CHECK-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 320; CHECK-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 321; CHECK-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 322; CHECK-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 323; CHECK-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 324; CHECK-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 325; CHECK-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 326; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 327; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 328; CHECK-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 329; CHECK-NEXT: ret i32 [[ADD_4]] 330; 331 %lv = load <4 x i32>, <4 x i32>* %x 332 %z.0 = extractelement <8 x i32> %z, i32 0 333 %z.1 = extractelement <8 x i32> %z, i32 1 334 %add.0 = add i32 %z.0, %z.1 335 %z.2 = extractelement <8 x i32> %z, i32 2 336 %add.1 = add i32 %add.0, %z.2 337 %z.3 = extractelement <8 x i32> %z, i32 3 338 %add.2 = add i32 %add.1, %z.3 339 %z.4 = extractelement <8 x i32> %z, i32 4 340 %add.3 = add i32 %add.2, %z.4 341 store i8 0, i8* %y 342 %r = extractelement <4 x i32> %lv, i32 2 343 %add.4 = add i32 %add.3, %r 344 ret i32 %add.4 345} 346 347define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 348; LIMIT-DEFAULT-LABEL: @load_extract_clobber_store_after_limit( 349; LIMIT-DEFAULT-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 350; LIMIT-DEFAULT-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 351; LIMIT-DEFAULT-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 352; LIMIT-DEFAULT-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 353; LIMIT-DEFAULT-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 354; LIMIT-DEFAULT-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 355; LIMIT-DEFAULT-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 356; LIMIT-DEFAULT-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 357; LIMIT-DEFAULT-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 358; LIMIT-DEFAULT-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 359; LIMIT-DEFAULT-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 360; LIMIT-DEFAULT-NEXT: store i8 0, i8* [[Y:%.*]], align 1 361; LIMIT-DEFAULT-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 362; LIMIT-DEFAULT-NEXT: ret i32 [[ADD_4]] 363; 364; LIMIT2-LABEL: @load_extract_clobber_store_after_limit( 365; LIMIT2-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 366; LIMIT2-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 367; LIMIT2-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 368; LIMIT2-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 369; LIMIT2-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 370; LIMIT2-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 371; LIMIT2-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 372; LIMIT2-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 373; LIMIT2-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 374; LIMIT2-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 375; LIMIT2-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 376; LIMIT2-NEXT: store i8 0, i8* [[Y:%.*]], align 1 377; LIMIT2-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 378; LIMIT2-NEXT: ret i32 [[ADD_4]] 379; 380 %lv = load <4 x i32>, <4 x i32>* %x 381 %z.0 = extractelement <8 x i32> %z, i32 0 382 %z.1 = extractelement <8 x i32> %z, i32 1 383 %add.0 = add i32 %z.0, %z.1 384 %z.2 = extractelement <8 x i32> %z, i32 2 385 %add.1 = add i32 %add.0, %z.2 386 %z.3 = extractelement <8 x i32> %z, i32 3 387 %add.2 = add i32 %add.1, %z.3 388 %z.4 = extractelement <8 x i32> %z, i32 4 389 %add.3 = add i32 %add.2, %z.4 390 %r = extractelement <4 x i32> %lv, i32 2 391 store i8 0, i8* %y 392 %add.4 = add i32 %add.3, %r 393 ret i32 %add.4 394} 395 396declare void @use.v4i32(<4 x i32>) 397 398define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) { 399; CHECK-LABEL: @load_extract_idx_different_bbs( 400; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 401; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 402; CHECK: then: 403; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1 404; CHECK-NEXT: ret i32 [[R]] 405; CHECK: else: 406; CHECK-NEXT: call void @use.v4i32(<4 x i32> [[LV]]) 407; CHECK-NEXT: ret i32 20 408; 409 %lv = load <4 x i32>, <4 x i32>* %x 410 br i1 %c, label %then, label %else 411 412then: 413 %r = extractelement <4 x i32> %lv, i32 1 414 ret i32 %r 415 416else: 417 call void @use.v4i32(<4 x i32> %lv) 418 ret i32 20 419} 420 421define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) { 422; CHECK-LABEL: @load_with_non_power_of_2_element_type( 423; CHECK-NEXT: [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16 424; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1 425; CHECK-NEXT: ret i31 [[R]] 426; 427 %lv = load <4 x i31>, <4 x i31>* %x 428 %r = extractelement <4 x i31> %lv, i32 1 429 ret i31 %r 430} 431 432; Scalarizing the load for multiple constant indices may not be profitable. 433define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) { 434; CHECK-LABEL: @load_multiple_extracts_with_constant_idx( 435; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 436; CHECK-NEXT: [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef> 437; CHECK-NEXT: [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]] 438; CHECK-NEXT: [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0 439; CHECK-NEXT: ret i32 [[RES]] 440; 441 %lv = load <4 x i32>, <4 x i32>* %x 442 %e.0 = extractelement <4 x i32> %lv, i32 0 443 %e.1 = extractelement <4 x i32> %lv, i32 1 444 %res = add i32 %e.0, %e.1 445 ret i32 %res 446} 447 448; Scalarizing the load for multiple extracts is profitable in this case, 449; because the vector large vector requires 2 vector registers. 450define i32 @load_multiple_extracts_with_constant_idx_profitable(<8 x i32>* %x) { 451; CHECK-LABEL: @load_multiple_extracts_with_constant_idx_profitable( 452; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X:%.*]], i32 0, i32 0 453; CHECK-NEXT: [[E_0:%.*]] = load i32, i32* [[TMP1]], align 16 454; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X]], i32 0, i32 6 455; CHECK-NEXT: [[E_1:%.*]] = load i32, i32* [[TMP2]], align 8 456; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 457; CHECK-NEXT: ret i32 [[RES]] 458; 459 %lv = load <8 x i32>, <8 x i32>* %x, align 16 460 %e.0 = extractelement <8 x i32> %lv, i32 0 461 %e.1 = extractelement <8 x i32> %lv, i32 6 462 %res = add i32 %e.0, %e.1 463 ret i32 %res 464} 465 466; Scalarizing may or may not be profitable, depending on the target. 467define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) { 468; CHECK-LABEL: @load_multiple_2_with_variable_indices( 469; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 470; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 471; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 472; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 473; CHECK-NEXT: ret i32 [[RES]] 474; 475 %lv = load <4 x i32>, <4 x i32>* %x 476 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 477 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 478 %res = add i32 %e.0, %e.1 479 ret i32 %res 480} 481 482define i32 @load_4_extracts_with_variable_indices_short_vector(<4 x i32>* %x, i64 %idx.0, i64 %idx.1, i64 %idx.2, i64 %idx.3) { 483; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector( 484; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 485; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 486; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 487; CHECK-NEXT: [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]] 488; CHECK-NEXT: [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]] 489; CHECK-NEXT: [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]] 490; CHECK-NEXT: [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]] 491; CHECK-NEXT: [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]] 492; CHECK-NEXT: ret i32 [[RES_2]] 493; 494 %lv = load <4 x i32>, <4 x i32>* %x 495 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 496 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 497 %e.2 = extractelement <4 x i32> %lv, i64 %idx.2 498 %e.3 = extractelement <4 x i32> %lv, i64 %idx.3 499 %res.0 = add i32 %e.0, %e.1 500 %res.1 = add i32 %res.0, %e.2 501 %res.2 = add i32 %res.1, %e.3 502 ret i32 %res.2 503} 504 505define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 506; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid( 507; CHECK-NEXT: [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16 508; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_0]]) 509; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 510; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0]] 511; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]] 512; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 513; CHECK-NEXT: ret i32 [[RES]] 514; 515 %cmp.idx.0 = icmp ult i64 %idx.0, 16 516 call void @llvm.assume(i1 %cmp.idx.0) 517 518 %lv = load <16 x i32>, <16 x i32>* %x 519 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0 520 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 521 %res = add i32 %e.0, %e.1 522 ret i32 %res 523} 524 525define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 526; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid( 527; CHECK-NEXT: [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16 528; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_0]]) 529; CHECK-NEXT: [[CMP_IDX_1:%.*]] = icmp ult i64 [[IDX_1:%.*]], 16 530; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_1]]) 531; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[IDX_0]] 532; CHECK-NEXT: [[E_0:%.*]] = load i32, i32* [[TMP1]], align 4 533; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[IDX_1]] 534; CHECK-NEXT: [[E_1:%.*]] = load i32, i32* [[TMP2]], align 4 535; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 536; CHECK-NEXT: ret i32 [[RES]] 537; 538 %cmp.idx.0 = icmp ult i64 %idx.0, 16 539 call void @llvm.assume(i1 %cmp.idx.0) 540 %cmp.idx.1 = icmp ult i64 %idx.1, 16 541 call void @llvm.assume(i1 %cmp.idx.1) 542 543 %lv = load <16 x i32>, <16 x i32>* %x 544 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0 545 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 546 %res = add i32 %e.0, %e.1 547 ret i32 %res 548} 549 550define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 551; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and( 552; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 553; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 554; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 555; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]] 556; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 557; CHECK-NEXT: ret i32 [[RES]] 558; 559 %idx.0.clamped = and i64 %idx.0, 15 560 561 %lv = load <16 x i32>, <16 x i32>* %x 562 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 563 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 564 %res = add i32 %e.0, %e.1 565 ret i32 %res 566} 567 568define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 569; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and( 570; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 571; CHECK-NEXT: [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15 572; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 573; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 574; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]] 575; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 576; CHECK-NEXT: ret i32 [[RES]] 577; 578 %idx.0.clamped = and i64 %idx.0, 15 579 %idx.1.clamped = and i64 %idx.1, 15 580 581 %lv = load <16 x i32>, <16 x i32>* %x 582 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 583 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped 584 %res = add i32 %e.0, %e.1 585 ret i32 %res 586} 587 588define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef(<16 x i32>* %x, i64 %idx.0, i64 noundef %idx.1) { 589; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef( 590; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 591; CHECK-NEXT: [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15 592; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 593; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 594; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]] 595; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 596; CHECK-NEXT: ret i32 [[RES]] 597; 598 %idx.0.clamped = and i64 %idx.0, 15 599 %idx.1.clamped = and i64 %idx.1, 15 600 601 %lv = load <16 x i32>, <16 x i32>* %x 602 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 603 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped 604 %res = add i32 %e.0, %e.1 605 ret i32 %res 606} 607