1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -S %s | FileCheck %s 3 4define i32 @load_extract_idx_0(<4 x i32>* %x) { 5; CHECK-LABEL: @load_extract_idx_0( 6; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 7; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 3 8; CHECK-NEXT: ret i32 [[R]] 9; 10 %lv = load <4 x i32>, <4 x i32>* %x 11 %r = extractelement <4 x i32> %lv, i32 3 12 ret i32 %r 13} 14 15define i32 @load_extract_idx_1(<4 x i32>* %x) { 16; CHECK-LABEL: @load_extract_idx_1( 17; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 18; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1 19; CHECK-NEXT: ret i32 [[R]] 20; 21 %lv = load <4 x i32>, <4 x i32>* %x 22 %r = extractelement <4 x i32> %lv, i32 1 23 ret i32 %r 24} 25 26define i32 @load_extract_idx_2(<4 x i32>* %x) { 27; CHECK-LABEL: @load_extract_idx_2( 28; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 29; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 30; CHECK-NEXT: ret i32 [[R]] 31; 32 %lv = load <4 x i32>, <4 x i32>* %x 33 %r = extractelement <4 x i32> %lv, i32 2 34 ret i32 %r 35} 36 37define i32 @load_extract_idx_3(<4 x i32>* %x) { 38; CHECK-LABEL: @load_extract_idx_3( 39; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 40; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 3 41; CHECK-NEXT: ret i32 [[R]] 42; 43 %lv = load <4 x i32>, <4 x i32>* %x 44 %r = extractelement <4 x i32> %lv, i32 3 45 ret i32 %r 46} 47 48define i32 @load_extract_idx_var_i64(<4 x i32>* %x, i64 %idx) { 49; CHECK-LABEL: @load_extract_idx_var_i64( 50; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 51; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX:%.*]] 52; CHECK-NEXT: ret i32 [[R]] 53; 54 %lv = load <4 x i32>, <4 x i32>* %x 55 %r = extractelement <4 x i32> %lv, i64 %idx 56 ret i32 %r 57} 58 59declare void @maythrow() readnone 60 61define i32 @load_extract_idx_var_i64_known_valid_by_assume(<4 x i32>* %x, i64 %idx) { 62; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume( 63; CHECK-NEXT: entry: 64; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 65; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 66; CHECK-NEXT: call void @maythrow() 67; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 68; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 69; CHECK-NEXT: ret i32 [[R]] 70; 71entry: 72 %cmp = icmp ult i64 %idx, 4 73 %lv = load <4 x i32>, <4 x i32>* %x 74 call void @maythrow() 75 call void @llvm.assume(i1 %cmp) 76 %r = extractelement <4 x i32> %lv, i64 %idx 77 ret i32 %r 78} 79 80define i32 @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(<4 x i32>* %x, i64 %idx) { 81; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume_after_load( 82; CHECK-NEXT: entry: 83; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4 84; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 85; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 86; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 87; CHECK-NEXT: ret i32 [[R]] 88; 89entry: 90 %cmp = icmp ult i64 %idx, 4 91 call void @llvm.assume(i1 %cmp) 92 %lv = load <4 x i32>, <4 x i32>* %x 93 %r = extractelement <4 x i32> %lv, i64 %idx 94 ret i32 %r 95} 96 97define i32 @load_extract_idx_var_i64_not_known_valid_by_assume(<4 x i32>* %x, i64 %idx) { 98; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume( 99; CHECK-NEXT: entry: 100; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 5 101; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) 102; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 103; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]] 104; CHECK-NEXT: ret i32 [[R]] 105; 106entry: 107 %cmp = icmp ult i64 %idx, 5 108 call void @llvm.assume(i1 %cmp) 109 %lv = load <4 x i32>, <4 x i32>* %x 110 %r = extractelement <4 x i32> %lv, i64 %idx 111 ret i32 %r 112} 113 114declare void @llvm.assume(i1) 115 116define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) { 117; CHECK-LABEL: @load_extract_idx_var_i32( 118; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 119; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]] 120; CHECK-NEXT: ret i32 [[R]] 121; 122 %lv = load <4 x i32>, <4 x i32>* %x 123 %r = extractelement <4 x i32> %lv, i32 %idx 124 ret i32 %r 125} 126 127declare void @clobber() 128 129define i32 @load_extract_clobber_call_before(<4 x i32>* %x) { 130; CHECK-LABEL: @load_extract_clobber_call_before( 131; CHECK-NEXT: call void @clobber() 132; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 133; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 134; CHECK-NEXT: ret i32 [[R]] 135; 136 call void @clobber() 137 %lv = load <4 x i32>, <4 x i32>* %x 138 %r = extractelement <4 x i32> %lv, i32 2 139 ret i32 %r 140} 141 142define i32 @load_extract_clobber_call_between(<4 x i32>* %x) { 143; CHECK-LABEL: @load_extract_clobber_call_between( 144; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 145; CHECK-NEXT: call void @clobber() 146; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 147; CHECK-NEXT: ret i32 [[R]] 148; 149 %lv = load <4 x i32>, <4 x i32>* %x 150 call void @clobber() 151 %r = extractelement <4 x i32> %lv, i32 2 152 ret i32 %r 153} 154 155define i32 @load_extract_clobber_call_after(<4 x i32>* %x) { 156; CHECK-LABEL: @load_extract_clobber_call_after( 157; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 158; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 159; CHECK-NEXT: call void @clobber() 160; CHECK-NEXT: ret i32 [[R]] 161; 162 %lv = load <4 x i32>, <4 x i32>* %x 163 %r = extractelement <4 x i32> %lv, i32 2 164 call void @clobber() 165 ret i32 %r 166} 167 168define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) { 169; CHECK-LABEL: @load_extract_clobber_store_before( 170; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 171; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 172; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 173; CHECK-NEXT: ret i32 [[R]] 174; 175 store i8 0, i8* %y 176 %lv = load <4 x i32>, <4 x i32>* %x 177 %r = extractelement <4 x i32> %lv, i32 2 178 ret i32 %r 179} 180 181define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) { 182; CHECK-LABEL: @load_extract_clobber_store_between( 183; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 184; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 185; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 186; CHECK-NEXT: ret i32 [[R]] 187; 188 %lv = load <4 x i32>, <4 x i32>* %x 189 store i8 0, i8* %y 190 %r = extractelement <4 x i32> %lv, i32 2 191 ret i32 %r 192} 193 194define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 195; CHECK-LABEL: @load_extract_clobber_store_between_limit( 196; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 197; CHECK-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 198; CHECK-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 199; CHECK-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 200; CHECK-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 201; CHECK-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 202; CHECK-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 203; CHECK-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 204; CHECK-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 205; CHECK-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 206; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 207; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 208; CHECK-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 209; CHECK-NEXT: ret i32 [[ADD_4]] 210; 211 %lv = load <4 x i32>, <4 x i32>* %x 212 %z.0 = extractelement <8 x i32> %z, i32 0 213 %z.1 = extractelement <8 x i32> %z, i32 1 214 %add.0 = add i32 %z.0, %z.1 215 %z.2 = extractelement <8 x i32> %z, i32 2 216 %add.1 = add i32 %add.0, %z.2 217 %z.3 = extractelement <8 x i32> %z, i32 3 218 %add.2 = add i32 %add.1, %z.3 219 %z.4 = extractelement <8 x i32> %z, i32 4 220 %add.3 = add i32 %add.2, %z.4 221 store i8 0, i8* %y 222 %r = extractelement <4 x i32> %lv, i32 2 223 %add.4 = add i32 %add.3, %r 224 ret i32 %add.4 225} 226 227define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) { 228; CHECK-LABEL: @load_extract_clobber_store_after_limit( 229; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 230; CHECK-NEXT: [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0 231; CHECK-NEXT: [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1 232; CHECK-NEXT: [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]] 233; CHECK-NEXT: [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2 234; CHECK-NEXT: [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]] 235; CHECK-NEXT: [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3 236; CHECK-NEXT: [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]] 237; CHECK-NEXT: [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4 238; CHECK-NEXT: [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]] 239; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2 240; CHECK-NEXT: store i8 0, i8* [[Y:%.*]], align 1 241; CHECK-NEXT: [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]] 242; CHECK-NEXT: ret i32 [[ADD_4]] 243; 244 %lv = load <4 x i32>, <4 x i32>* %x 245 %z.0 = extractelement <8 x i32> %z, i32 0 246 %z.1 = extractelement <8 x i32> %z, i32 1 247 %add.0 = add i32 %z.0, %z.1 248 %z.2 = extractelement <8 x i32> %z, i32 2 249 %add.1 = add i32 %add.0, %z.2 250 %z.3 = extractelement <8 x i32> %z, i32 3 251 %add.2 = add i32 %add.1, %z.3 252 %z.4 = extractelement <8 x i32> %z, i32 4 253 %add.3 = add i32 %add.2, %z.4 254 %r = extractelement <4 x i32> %lv, i32 2 255 store i8 0, i8* %y 256 %add.4 = add i32 %add.3, %r 257 ret i32 %add.4 258} 259 260declare void @use.v4i32(<4 x i32>) 261 262define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) { 263; CHECK-LABEL: @load_extract_idx_different_bbs( 264; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 265; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] 266; CHECK: then: 267; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1 268; CHECK-NEXT: ret i32 [[R]] 269; CHECK: else: 270; CHECK-NEXT: call void @use.v4i32(<4 x i32> [[LV]]) 271; CHECK-NEXT: ret i32 20 272; 273 %lv = load <4 x i32>, <4 x i32>* %x 274 br i1 %c, label %then, label %else 275 276then: 277 %r = extractelement <4 x i32> %lv, i32 1 278 ret i32 %r 279 280else: 281 call void @use.v4i32(<4 x i32> %lv) 282 ret i32 20 283} 284 285define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) { 286; CHECK-LABEL: @load_with_non_power_of_2_element_type( 287; CHECK-NEXT: [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16 288; CHECK-NEXT: [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1 289; CHECK-NEXT: ret i31 [[R]] 290; 291 %lv = load <4 x i31>, <4 x i31>* %x 292 %r = extractelement <4 x i31> %lv, i32 1 293 ret i31 %r 294} 295 296; Scalarizing the load for multiple constant indices may not be profitable. 297define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) { 298; CHECK-LABEL: @load_multiple_extracts_with_constant_idx( 299; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 300; CHECK-NEXT: [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef> 301; CHECK-NEXT: [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]] 302; CHECK-NEXT: [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0 303; CHECK-NEXT: ret i32 [[RES]] 304; 305 %lv = load <4 x i32>, <4 x i32>* %x 306 %e.0 = extractelement <4 x i32> %lv, i32 0 307 %e.1 = extractelement <4 x i32> %lv, i32 1 308 %res = add i32 %e.0, %e.1 309 ret i32 %res 310} 311 312; Scalarizing may or may not be profitable, depending on the target. 313define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) { 314; CHECK-LABEL: @load_multiple_2_with_variable_indices( 315; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 316; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 317; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 318; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 319; CHECK-NEXT: ret i32 [[RES]] 320; 321 %lv = load <4 x i32>, <4 x i32>* %x 322 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 323 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 324 %res = add i32 %e.0, %e.1 325 ret i32 %res 326} 327 328define 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) { 329; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector( 330; CHECK-NEXT: [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16 331; CHECK-NEXT: [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]] 332; CHECK-NEXT: [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]] 333; CHECK-NEXT: [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]] 334; CHECK-NEXT: [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]] 335; CHECK-NEXT: [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]] 336; CHECK-NEXT: [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]] 337; CHECK-NEXT: [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]] 338; CHECK-NEXT: ret i32 [[RES_2]] 339; 340 %lv = load <4 x i32>, <4 x i32>* %x 341 %e.0 = extractelement <4 x i32> %lv, i64 %idx.0 342 %e.1 = extractelement <4 x i32> %lv, i64 %idx.1 343 %e.2 = extractelement <4 x i32> %lv, i64 %idx.2 344 %e.3 = extractelement <4 x i32> %lv, i64 %idx.3 345 %res.0 = add i32 %e.0, %e.1 346 %res.1 = add i32 %res.0, %e.2 347 %res.2 = add i32 %res.1, %e.3 348 ret i32 %res.2 349} 350 351define i32 @load_multiple_extracts_with_variable_indices_large_vector(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) { 352; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector( 353; CHECK-NEXT: [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64 354; CHECK-NEXT: [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0:%.*]] 355; CHECK-NEXT: [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]] 356; CHECK-NEXT: [[RES:%.*]] = add i32 [[E_0]], [[E_1]] 357; CHECK-NEXT: ret i32 [[RES]] 358; 359 %lv = load <16 x i32>, <16 x i32>* %x 360 %e.0 = extractelement <16 x i32> %lv, i64 %idx.0 361 %e.1 = extractelement <16 x i32> %lv, i64 %idx.1 362 %res = add i32 %e.0, %e.1 363 ret i32 %res 364} 365