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 108declare i1 @cond() 109 110define i32 @load_extract_idx_var_i64_known_valid_by_assume_in_dominating_block(<4 x i32>* %x, i64 %idx, i1 %c.1) { 111; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume_in_dominating_block( 112; CHECK-NEXT: entry: 113; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 114; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 115; CHECK-NEXT: br i1 [[C_1:%.*]], label [[LOOP:%.*]], label [[EXIT:%.*]] 116; CHECK: loop: 117; CHECK-NEXT: call void @maythrow() 118; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX]] 119; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 120; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond() 121; CHECK-NEXT: br i1 [[C_2]], label [[LOOP]], label [[EXIT]] 122; CHECK: exit: 123; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[R]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ] 124; CHECK-NEXT: ret i32 [[P]] 125; 126entry: 127 %cmp = icmp ult i64 %idx, 4 128 call void @llvm.assume(i1 %cmp) 129 br i1 %c.1, label %loop, label %exit 130 131loop: 132 %lv = load <4 x i32>, <4 x i32>* %x 133 call void @maythrow() 134 %r = extractelement <4 x i32> %lv, i64 %idx 135 %c.2 = call i1 @cond() 136 br i1 %c.2, label %loop, label %exit 137 138exit: 139 %p = phi i32 [ %r, %loop ], [ 0, %entry ] 140 ret i32 %p 141} 142 143define i32 @load_extract_idx_var_i64_known_valid_by_assume_in_non_dominating_block(<4 x i32>* %x, i64 %idx, i1 %c.1, i1 %c.2) { 144; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume_in_non_dominating_block( 145; CHECK-NEXT: entry: 146; CHECK-NEXT: br i1 [[C_1:%.*]], label [[ASSUME_CHECK:%.*]], label [[LOOP:%.*]] 147; CHECK: assume_check: 148; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 149; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 150; CHECK-NEXT: br i1 [[C_2:%.*]], label [[LOOP]], label [[EXIT:%.*]] 151; CHECK: loop: 152; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 153; CHECK-NEXT: call void @maythrow() 154; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 155; CHECK-NEXT: [[C_3:%.*]] = call i1 @cond() 156; CHECK-NEXT: br i1 [[C_3]], label [[LOOP]], label [[EXIT]] 157; CHECK: exit: 158; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[R]], [[LOOP]] ], [ 0, [[ASSUME_CHECK]] ] 159; CHECK-NEXT: ret i32 0 160; 161entry: 162 br i1 %c.1, label %assume_check, label %loop 163 164assume_check: 165 %cmp = icmp ult i64 %idx, 4 166 call void @llvm.assume(i1 %cmp) 167 br i1 %c.2, label %loop, label %exit 168 169loop: 170 %lv = load <4 x i32>, <4 x i32>* %x 171 call void @maythrow() 172 %r = extractelement <4 x i32> %lv, i64 %idx 173 %c.3 = call i1 @cond() 174 br i1 %c.3, label %loop, label %exit 175 176exit: 177 %p = phi i32 [ %r, %loop ], [ 0, %assume_check ] 178 ret i32 0 179} 180 181define i32 @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(<4 x i32>* %x, i64 %idx) { 182; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume_after_load( 183; CHECK-NEXT: entry: 184; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 185; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 186; CHECK-NEXT: call void @maythrow() 187; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 188; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 189; CHECK-NEXT: ret i32 [[R]] 190; 191entry: 192 %cmp = icmp ult i64 %idx, 4 193 %lv = load <4 x i32>, <4 x i32>* %x 194 call void @maythrow() 195 call void @llvm.assume(i1 %cmp) 196 %r = extractelement <4 x i32> %lv, i64 %idx 197 ret i32 %r 198} 199 200define i32 @load_extract_idx_var_i64_not_known_valid_by_assume(<4 x i32>* %x, i64 %idx) { 201; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume( 202; CHECK-NEXT: entry: 203; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 5 204; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 205; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 206; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 207; CHECK-NEXT: ret i32 [[R]] 208; 209entry: 210 %cmp = icmp ult i64 %idx, 5 211 call void @llvm.assume(i1 %cmp) 212 %lv = load <4 x i32>, <4 x i32>* %x 213 %r = extractelement <4 x i32> %lv, i64 %idx 214 ret i32 %r 215} 216 217declare void @llvm.assume(i1) 218 219define i32 @load_extract_idx_var_i64_known_valid_by_and(<4 x i32>* %x, i64 %idx) { 220; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and( 221; CHECK-NEXT: entry: 222; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3 223; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 224; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 225; CHECK-NEXT: ret i32 [[R]] 226; 227entry: 228 %idx.clamped = and i64 %idx, 3 229 %lv = load <4 x i32>, <4 x i32>* %x 230 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 231 ret i32 %r 232} 233 234define i32 @load_extract_idx_var_i64_known_valid_by_and_noundef(<4 x i32>* %x, i64 noundef %idx) { 235; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and_noundef( 236; CHECK-NEXT: entry: 237; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3 238; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]] 239; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 240; CHECK-NEXT: ret i32 [[R]] 241; 242entry: 243 %idx.clamped = and i64 %idx, 3 244 %lv = load <4 x i32>, <4 x i32>* %x 245 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 246 ret i32 %r 247} 248 249define i32 @load_extract_idx_var_i64_not_known_valid_by_and(<4 x i32>* %x, i64 %idx) { 250; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_and( 251; CHECK-NEXT: entry: 252; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 4 253; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 254; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 255; CHECK-NEXT: ret i32 [[R]] 256; 257entry: 258 %idx.clamped = and i64 %idx, 4 259 %lv = load <4 x i32>, <4 x i32>* %x 260 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 261 ret i32 %r 262} 263 264define i32 @load_extract_idx_var_i64_known_valid_by_urem(<4 x i32>* %x, i64 %idx) { 265; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem( 266; CHECK-NEXT: entry: 267; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4 268; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 269; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 270; CHECK-NEXT: ret i32 [[R]] 271; 272entry: 273 %idx.clamped = urem i64 %idx, 4 274 %lv = load <4 x i32>, <4 x i32>* %x 275 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 276 ret i32 %r 277} 278 279define i32 @load_extract_idx_var_i64_known_valid_by_urem_noundef(<4 x i32>* %x, i64 noundef %idx) { 280; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem_noundef( 281; CHECK-NEXT: entry: 282; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4 283; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]] 284; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP0]], align 4 285; CHECK-NEXT: ret i32 [[R]] 286; 287entry: 288 %idx.clamped = urem i64 %idx, 4 289 %lv = load <4 x i32>, <4 x i32>* %x 290 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 291 ret i32 %r 292} 293 294define i32 @load_extract_idx_var_i64_not_known_valid_by_urem(<4 x i32>* %x, i64 %idx) { 295; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_urem( 296; CHECK-NEXT: entry: 297; CHECK-NEXT: [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 5 298; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 299; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]] 300; CHECK-NEXT: ret i32 [[R]] 301; 302entry: 303 %idx.clamped = urem i64 %idx, 5 304 %lv = load <4 x i32>, <4 x i32>* %x 305 %r = extractelement <4 x i32> %lv, i64 %idx.clamped 306 ret i32 %r 307} 308 309define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) { 310; CHECK-LABEL: @load_extract_idx_var_i32( 311; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 312; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]] 313; CHECK-NEXT: ret i32 [[R]] 314; 315 %lv = load <4 x i32>, <4 x i32>* %x 316 %r = extractelement <4 x i32> %lv, i32 %idx 317 ret i32 %r 318} 319 320declare void @clobber() 321 322define i32 @load_extract_clobber_call_before(<4 x i32>* %x) { 323; CHECK-LABEL: @load_extract_clobber_call_before( 324; CHECK-NEXT: call void @clobber() 325; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 326; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 327; CHECK-NEXT: ret i32 [[R]] 328; 329 call void @clobber() 330 %lv = load <4 x i32>, <4 x i32>* %x 331 %r = extractelement <4 x i32> %lv, i32 2 332 ret i32 %r 333} 334 335define i32 @load_extract_clobber_call_between(<4 x i32>* %x) { 336; CHECK-LABEL: @load_extract_clobber_call_between( 337; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 338; CHECK-NEXT: call void @clobber() 339; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 340; CHECK-NEXT: ret i32 [[R]] 341; 342 %lv = load <4 x i32>, <4 x i32>* %x 343 call void @clobber() 344 %r = extractelement <4 x i32> %lv, i32 2 345 ret i32 %r 346} 347 348define i32 @load_extract_clobber_call_after(<4 x i32>* %x) { 349; CHECK-LABEL: @load_extract_clobber_call_after( 350; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 351; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 352; CHECK-NEXT: call void @clobber() 353; CHECK-NEXT: ret i32 [[R]] 354; 355 %lv = load <4 x i32>, <4 x i32>* %x 356 %r = extractelement <4 x i32> %lv, i32 2 357 call void @clobber() 358 ret i32 %r 359} 360 361define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) { 362; CHECK-LABEL: @load_extract_clobber_store_before( 363; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 364; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 365; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 366; CHECK-NEXT: ret i32 [[R]] 367; 368 store i8 0, i8* %y 369 %lv = load <4 x i32>, <4 x i32>* %x 370 %r = extractelement <4 x i32> %lv, i32 2 371 ret i32 %r 372} 373 374define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) { 375; CHECK-LABEL: @load_extract_clobber_store_between( 376; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 377; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 378; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 379; CHECK-NEXT: ret i32 [[R]] 380; 381 %lv = load <4 x i32>, <4 x i32>* %x 382 store i8 0, i8* %y 383 %r = extractelement <4 x i32> %lv, i32 2 384 ret i32 %r 385} 386 387define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 388; CHECK-LABEL: @load_extract_clobber_store_between_limit( 389; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 390; CHECK-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 391; CHECK-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 392; CHECK-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 393; CHECK-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 394; CHECK-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 395; CHECK-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 396; CHECK-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 397; CHECK-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 398; CHECK-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 399; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 400; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 401; CHECK-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 402; CHECK-NEXT: ret i32 [[ADD_4]] 403; 404 %lv = load <4 x i32>, <4 x i32>* %x 405 %z.0 = extractelement <8 x i32> %z, i32 0 406 %z.1 = extractelement <8 x i32> %z, i32 1 407 %add.0 = add i32 %z.0, %z.1 408 %z.2 = extractelement <8 x i32> %z, i32 2 409 %add.1 = add i32 %add.0, %z.2 410 %z.3 = extractelement <8 x i32> %z, i32 3 411 %add.2 = add i32 %add.1, %z.3 412 %z.4 = extractelement <8 x i32> %z, i32 4 413 %add.3 = add i32 %add.2, %z.4 414 store i8 0, i8* %y 415 %r = extractelement <4 x i32> %lv, i32 2 416 %add.4 = add i32 %add.3, %r 417 ret i32 %add.4 418} 419 420define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 421; LIMIT-DEFAULT-LABEL: @load_extract_clobber_store_after_limit( 422; LIMIT-DEFAULT-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 423; LIMIT-DEFAULT-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 424; LIMIT-DEFAULT-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 425; LIMIT-DEFAULT-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 426; LIMIT-DEFAULT-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 427; LIMIT-DEFAULT-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 428; LIMIT-DEFAULT-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 429; LIMIT-DEFAULT-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 430; LIMIT-DEFAULT-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 431; LIMIT-DEFAULT-NEXT: [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2 432; LIMIT-DEFAULT-NEXT: [[R:%.*]] = load i32, i32* [[TMP1]], align 8 433; LIMIT-DEFAULT-NEXT: store i8 0, i8* [[Y:%.*]], align 1 434; LIMIT-DEFAULT-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 435; LIMIT-DEFAULT-NEXT: ret i32 [[ADD_4]] 436; 437; LIMIT2-LABEL: @load_extract_clobber_store_after_limit( 438; LIMIT2-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 439; LIMIT2-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 440; LIMIT2-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 441; LIMIT2-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 442; LIMIT2-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 443; LIMIT2-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 444; LIMIT2-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 445; LIMIT2-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 446; LIMIT2-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 447; LIMIT2-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 448; LIMIT2-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 449; LIMIT2-NEXT: store i8 0, i8* [[Y:%.*]], align 1 450; LIMIT2-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 451; LIMIT2-NEXT: ret i32 [[ADD_4]] 452; 453 %lv = load <4 x i32>, <4 x i32>* %x 454 %z.0 = extractelement <8 x i32> %z, i32 0 455 %z.1 = extractelement <8 x i32> %z, i32 1 456 %add.0 = add i32 %z.0, %z.1 457 %z.2 = extractelement <8 x i32> %z, i32 2 458 %add.1 = add i32 %add.0, %z.2 459 %z.3 = extractelement <8 x i32> %z, i32 3 460 %add.2 = add i32 %add.1, %z.3 461 %z.4 = extractelement <8 x i32> %z, i32 4 462 %add.3 = add i32 %add.2, %z.4 463 %r = extractelement <4 x i32> %lv, i32 2 464 store i8 0, i8* %y 465 %add.4 = add i32 %add.3, %r 466 ret i32 %add.4 467} 468 469declare void @use.v4i32(<4 x i32>) 470 471define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) { 472; CHECK-LABEL: @load_extract_idx_different_bbs( 473; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 474; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 475; CHECK: then: 476; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1 477; CHECK-NEXT: ret i32 [[R]] 478; CHECK: else: 479; CHECK-NEXT: call void @use.v4i32(<4 x i32> [[LV]]) 480; CHECK-NEXT: ret i32 20 481; 482 %lv = load <4 x i32>, <4 x i32>* %x 483 br i1 %c, label %then, label %else 484 485then: 486 %r = extractelement <4 x i32> %lv, i32 1 487 ret i32 %r 488 489else: 490 call void @use.v4i32(<4 x i32> %lv) 491 ret i32 20 492} 493 494define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) { 495; CHECK-LABEL: @load_with_non_power_of_2_element_type( 496; CHECK-NEXT: [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16 497; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1 498; CHECK-NEXT: ret i31 [[R]] 499; 500 %lv = load <4 x i31>, <4 x i31>* %x 501 %r = extractelement <4 x i31> %lv, i32 1 502 ret i31 %r 503} 504 505; Scalarizing the load for multiple constant indices may not be profitable. 506define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) { 507; CHECK-LABEL: @load_multiple_extracts_with_constant_idx( 508; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 509; CHECK-NEXT: [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef> 510; CHECK-NEXT: [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]] 511; CHECK-NEXT: [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0 512; CHECK-NEXT: ret i32 [[RES]] 513; 514 %lv = load <4 x i32>, <4 x i32>* %x 515 %e.0 = extractelement <4 x i32> %lv, i32 0 516 %e.1 = extractelement <4 x i32> %lv, i32 1 517 %res = add i32 %e.0, %e.1 518 ret i32 %res 519} 520 521; Scalarizing the load for multiple extracts is profitable in this case, 522; because the vector large vector requires 2 vector registers. 523define i32 @load_multiple_extracts_with_constant_idx_profitable(<8 x i32>* %x) { 524; CHECK-LABEL: @load_multiple_extracts_with_constant_idx_profitable( 525; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X:%.*]], i32 0, i32 0 526; CHECK-NEXT: [[E_0:%.*]] = load i32, i32* [[TMP1]], align 16 527; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X]], i32 0, i32 6 528; CHECK-NEXT: [[E_1:%.*]] = load i32, i32* [[TMP2]], align 8 529; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 530; CHECK-NEXT: ret i32 [[RES]] 531; 532 %lv = load <8 x i32>, <8 x i32>* %x, align 16 533 %e.0 = extractelement <8 x i32> %lv, i32 0 534 %e.1 = extractelement <8 x i32> %lv, i32 6 535 %res = add i32 %e.0, %e.1 536 ret i32 %res 537} 538 539; Scalarizing may or may not be profitable, depending on the target. 540define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) { 541; CHECK-LABEL: @load_multiple_2_with_variable_indices( 542; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 543; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 544; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 545; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 546; CHECK-NEXT: ret i32 [[RES]] 547; 548 %lv = load <4 x i32>, <4 x i32>* %x 549 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 550 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 551 %res = add i32 %e.0, %e.1 552 ret i32 %res 553} 554 555define 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) { 556; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector( 557; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 558; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 559; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 560; CHECK-NEXT: [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]] 561; CHECK-NEXT: [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]] 562; CHECK-NEXT: [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]] 563; CHECK-NEXT: [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]] 564; CHECK-NEXT: [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]] 565; CHECK-NEXT: ret i32 [[RES_2]] 566; 567 %lv = load <4 x i32>, <4 x i32>* %x 568 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 569 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 570 %e.2 = extractelement <4 x i32> %lv, i64 %idx.2 571 %e.3 = extractelement <4 x i32> %lv, i64 %idx.3 572 %res.0 = add i32 %e.0, %e.1 573 %res.1 = add i32 %res.0, %e.2 574 %res.2 = add i32 %res.1, %e.3 575 ret i32 %res.2 576} 577 578define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 579; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid( 580; CHECK-NEXT: [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16 581; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_0]]) 582; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 583; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0]] 584; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]] 585; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 586; CHECK-NEXT: ret i32 [[RES]] 587; 588 %cmp.idx.0 = icmp ult i64 %idx.0, 16 589 call void @llvm.assume(i1 %cmp.idx.0) 590 591 %lv = load <16 x i32>, <16 x i32>* %x 592 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0 593 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 594 %res = add i32 %e.0, %e.1 595 ret i32 %res 596} 597 598define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 599; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid( 600; CHECK-NEXT: [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16 601; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_0]]) 602; CHECK-NEXT: [[CMP_IDX_1:%.*]] = icmp ult i64 [[IDX_1:%.*]], 16 603; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_IDX_1]]) 604; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[IDX_0]] 605; CHECK-NEXT: [[E_0:%.*]] = load i32, i32* [[TMP1]], align 4 606; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[IDX_1]] 607; CHECK-NEXT: [[E_1:%.*]] = load i32, i32* [[TMP2]], align 4 608; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 609; CHECK-NEXT: ret i32 [[RES]] 610; 611 %cmp.idx.0 = icmp ult i64 %idx.0, 16 612 call void @llvm.assume(i1 %cmp.idx.0) 613 %cmp.idx.1 = icmp ult i64 %idx.1, 16 614 call void @llvm.assume(i1 %cmp.idx.1) 615 616 %lv = load <16 x i32>, <16 x i32>* %x 617 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0 618 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 619 %res = add i32 %e.0, %e.1 620 ret i32 %res 621} 622 623define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 624; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and( 625; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 626; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 627; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 628; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]] 629; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 630; CHECK-NEXT: ret i32 [[RES]] 631; 632 %idx.0.clamped = and i64 %idx.0, 15 633 634 %lv = load <16 x i32>, <16 x i32>* %x 635 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 636 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 637 %res = add i32 %e.0, %e.1 638 ret i32 %res 639} 640 641define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 642; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and( 643; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 644; CHECK-NEXT: [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15 645; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 646; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 647; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]] 648; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 649; CHECK-NEXT: ret i32 [[RES]] 650; 651 %idx.0.clamped = and i64 %idx.0, 15 652 %idx.1.clamped = and i64 %idx.1, 15 653 654 %lv = load <16 x i32>, <16 x i32>* %x 655 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 656 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped 657 %res = add i32 %e.0, %e.1 658 ret i32 %res 659} 660 661define 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) { 662; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef( 663; CHECK-NEXT: [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15 664; CHECK-NEXT: [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15 665; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 666; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]] 667; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]] 668; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 669; CHECK-NEXT: ret i32 [[RES]] 670; 671 %idx.0.clamped = and i64 %idx.0, 15 672 %idx.1.clamped = and i64 %idx.1, 15 673 674 %lv = load <16 x i32>, <16 x i32>* %x 675 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped 676 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped 677 %res = add i32 %e.0, %e.1 678 ret i32 %res 679} 680 681