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