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