1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt < %s -passes=slsr,gvn -S | FileCheck %s 3 4target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64-p:64:64:64-p1:32:32:32-p2:128:128:128:32" 5 6; foo(input[0]); 7; foo(input[s]); 8; foo(input[s * 2]); 9; => 10; p0 = &input[0]; 11; foo(*p); 12; p1 = p0 + s; 13; foo(*p1); 14; p2 = p1 + s; 15; foo(*p2); 16define void @slsr_gep(ptr %input, i64 %s) { 17; CHECK-LABEL: define void @slsr_gep( 18; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]]) { 19; CHECK-NEXT: call void @foo(ptr [[INPUT]]) 20; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i64 [[S]] 21; CHECK-NEXT: call void @foo(ptr [[P1]]) 22; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[S]], 2 23; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]] 24; CHECK-NEXT: call void @foo(ptr [[P2]]) 25; CHECK-NEXT: ret void 26; 27 ; v0 = input[0]; 28 call void @foo(ptr %input) 29 30 ; v1 = input[s]; 31 %p1 = getelementptr inbounds i32, ptr %input, i64 %s 32 call void @foo(ptr %p1) 33 34 ; v2 = input[s * 2]; 35 %s2 = shl nsw i64 %s, 1 36 %p2 = getelementptr inbounds i32, ptr %input, i64 %s2 37 call void @foo(ptr %p2) 38 39 ret void 40} 41 42; foo(input[0]); 43; foo(input[(long)s]); 44; foo(input[(long)(s * 2)]); 45; => 46; p0 = &input[0]; 47; foo(*p); 48; p1 = p0 + (long)s; 49; foo(*p1); 50; p2 = p1 + (long)s; 51; foo(*p2); 52define void @slsr_gep_sext(ptr %input, i32 %s) { 53; CHECK-LABEL: define void @slsr_gep_sext( 54; CHECK-SAME: ptr [[INPUT:%.*]], i32 [[S:%.*]]) { 55; CHECK-NEXT: call void @foo(ptr [[INPUT]]) 56; CHECK-NEXT: [[T:%.*]] = sext i32 [[S]] to i64 57; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i64 [[T]] 58; CHECK-NEXT: call void @foo(ptr [[P1]]) 59; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[T]], 2 60; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]] 61; CHECK-NEXT: call void @foo(ptr [[P2]]) 62; CHECK-NEXT: ret void 63; 64 ; v0 = input[0]; 65 call void @foo(ptr %input) 66 67 ; v1 = input[s]; 68 %t = sext i32 %s to i64 69 %p1 = getelementptr inbounds i32, ptr %input, i64 %t 70 call void @foo(ptr %p1) 71 72 ; v2 = input[s * 2]; 73 %s2 = shl nsw i32 %s, 1 74 %t2 = sext i32 %s2 to i64 75 %p2 = getelementptr inbounds i32, ptr %input, i64 %t2 76 call void @foo(ptr %p2) 77 78 ret void 79} 80 81; int input[10][5]; 82; foo(input[s][t]); 83; foo(input[s * 2][t]); 84; foo(input[s * 3][t]); 85; => 86; p0 = &input[s][t]; 87; foo(*p0); 88; p1 = p0 + 5s; 89; foo(*p1); 90; p2 = p1 + 5s; 91; foo(*p2); 92define void @slsr_gep_2d(ptr %input, i64 %s, i64 %t) { 93; CHECK-LABEL: define void @slsr_gep_2d( 94; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]], i64 [[T:%.*]]) { 95; CHECK-NEXT: [[P0:%.*]] = getelementptr inbounds [10 x [5 x i32]], ptr [[INPUT]], i64 0, i64 [[S]], i64 [[T]] 96; CHECK-NEXT: call void @foo(ptr [[P0]]) 97; CHECK-NEXT: [[TMP1:%.*]] = mul i64 [[S]], 20 98; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P0]], i64 [[TMP1]] 99; CHECK-NEXT: call void @foo(ptr [[P1]]) 100; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]] 101; CHECK-NEXT: call void @foo(ptr [[P2]]) 102; CHECK-NEXT: ret void 103; 104 ; v0 = input[s][t]; 105 %p0 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s, i64 %t 106 call void @foo(ptr %p0) 107 108 ; v1 = input[s * 2][t]; 109 %s2 = shl nsw i64 %s, 1 110 %p1 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s2, i64 %t 111 call void @foo(ptr %p1) 112 113 ; v3 = input[s * 3][t]; 114 %s3 = mul nsw i64 %s, 3 115 %p2 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s3, i64 %t 116 call void @foo(ptr %p2) 117 118 ret void 119} 120 121%struct.S = type <{ i64, i32 }> 122 123; In this case, the bump 124; = (char *)&input[s * 2][t].f1 - (char *)&input[s][t].f1 125; = 60 * s 126; which may not be divisible by typeof(input[s][t].f1) = 8. Therefore, we 127; rewrite the candidates using byte offset instead of index offset as in 128; @slsr_gep_2d. 129define void @slsr_gep_uglygep(ptr %input, i64 %s, i64 %t) { 130; CHECK-LABEL: define void @slsr_gep_uglygep( 131; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]], i64 [[T:%.*]]) { 132; CHECK-NEXT: [[P0:%.*]] = getelementptr inbounds [10 x [5 x %struct.S]], ptr [[INPUT]], i64 0, i64 [[S]], i64 [[T]], i32 0 133; CHECK-NEXT: call void @bar(ptr [[P0]]) 134; CHECK-NEXT: [[TMP1:%.*]] = mul i64 [[S]], 60 135; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P0]], i64 [[TMP1]] 136; CHECK-NEXT: call void @bar(ptr [[P1]]) 137; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]] 138; CHECK-NEXT: call void @bar(ptr [[P2]]) 139; CHECK-NEXT: ret void 140; 141 ; v0 = input[s][t].f1; 142 %p0 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s, i64 %t, i32 0 143 call void @bar(ptr %p0) 144 145 ; v1 = input[s * 2][t].f1; 146 %s2 = shl nsw i64 %s, 1 147 %p1 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s2, i64 %t, i32 0 148 call void @bar(ptr %p1) 149 150 ; v2 = input[s * 3][t].f1; 151 %s3 = mul nsw i64 %s, 3 152 %p2 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s3, i64 %t, i32 0 153 call void @bar(ptr %p2) 154 155 ret void 156} 157 158define void @slsr_out_of_bounds_gep(ptr %input, i32 %s) { 159; CHECK-LABEL: define void @slsr_out_of_bounds_gep( 160; CHECK-SAME: ptr [[INPUT:%.*]], i32 [[S:%.*]]) { 161; CHECK-NEXT: call void @foo(ptr [[INPUT]]) 162; CHECK-NEXT: [[T:%.*]] = sext i32 [[S]] to i64 163; CHECK-NEXT: [[P1:%.*]] = getelementptr i32, ptr [[INPUT]], i64 [[T]] 164; CHECK-NEXT: call void @foo(ptr [[P1]]) 165; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[T]], 2 166; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P1]], i64 [[TMP1]] 167; CHECK-NEXT: call void @foo(ptr [[P2]]) 168; CHECK-NEXT: ret void 169; 170 ; v0 = input[0]; 171 call void @foo(ptr %input) 172 173 ; v1 = input[(long)s]; 174 %t = sext i32 %s to i64 175 %p1 = getelementptr i32, ptr %input, i64 %t 176 call void @foo(ptr %p1) 177 178 ; v2 = input[(long)(s * 2)]; 179 %s2 = shl nsw i32 %s, 1 180 %t2 = sext i32 %s2 to i64 181 %p2 = getelementptr i32, ptr %input, i64 %t2 182 call void @foo(ptr %p2) 183 184 ret void 185} 186 187define void @slsr_gep_128bit_index(ptr %input, i128 %s) { 188; CHECK-LABEL: define void @slsr_gep_128bit_index( 189; CHECK-SAME: ptr [[INPUT:%.*]], i128 [[S:%.*]]) { 190; CHECK-NEXT: call void @foo(ptr [[INPUT]]) 191; CHECK-NEXT: [[S125:%.*]] = shl nsw i128 [[S]], 125 192; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i128 [[S125]] 193; CHECK-NEXT: call void @foo(ptr [[P1]]) 194; CHECK-NEXT: [[S126:%.*]] = shl nsw i128 [[S]], 126 195; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i128 [[S126]] 196; CHECK-NEXT: call void @foo(ptr [[P2]]) 197; CHECK-NEXT: ret void 198; 199 ; p0 = &input[0] 200 call void @foo(ptr %input) 201 202 ; p1 = &input[s << 125] 203 %s125 = shl nsw i128 %s, 125 204 %p1 = getelementptr inbounds i32, ptr %input, i128 %s125 205 call void @foo(ptr %p1) 206 207 ; p2 = &input[s << 126] 208 %s126 = shl nsw i128 %s, 126 209 %p2 = getelementptr inbounds i32, ptr %input, i128 %s126 210 call void @foo(ptr %p2) 211 212 ret void 213} 214 215define void @slsr_gep_32bit_pointer(ptr addrspace(1) %input, i64 %s) { 216; CHECK-LABEL: define void @slsr_gep_32bit_pointer( 217; CHECK-SAME: ptr addrspace(1) [[INPUT:%.*]], i64 [[S:%.*]]) { 218; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i32, ptr addrspace(1) [[INPUT]], i64 [[S]] 219; CHECK-NEXT: call void @baz(ptr addrspace(1) [[P1]]) 220; CHECK-NEXT: [[S2:%.*]] = mul nsw i64 [[S]], 2 221; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i32, ptr addrspace(1) [[INPUT]], i64 [[S2]] 222; CHECK-NEXT: call void @baz(ptr addrspace(1) [[P2]]) 223; CHECK-NEXT: ret void 224; 225 ; p1 = &input[s] 226 %p1 = getelementptr inbounds i32, ptr addrspace(1) %input, i64 %s 227 call void @baz(ptr addrspace(1) %p1) 228 229 ; p2 = &input[s * 2] 230 %s2 = mul nsw i64 %s, 2 231 %p2 = getelementptr inbounds i32, ptr addrspace(1) %input, i64 %s2 232 ; %s2 is wider than the pointer size of addrspace(1), so do not factor it. 233 call void @baz(ptr addrspace(1) %p2) 234 235 ret void 236} 237 238define void @slsr_gep_fat_pointer(ptr addrspace(2) %input, i32 %s) { 239 ; p1 = &input[s] 240; CHECK-LABEL: define void @slsr_gep_fat_pointer( 241; CHECK-SAME: ptr addrspace(2) [[INPUT:%.*]], i32 [[S:%.*]]) { 242; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i32, ptr addrspace(2) [[INPUT]], i32 [[S]] 243; CHECK-NEXT: call void @baz2(ptr addrspace(2) [[P1]]) 244; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[S]], 2 245; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(2) [[P1]], i32 [[TMP1]] 246; CHECK-NEXT: call void @baz2(ptr addrspace(2) [[P2]]) 247; CHECK-NEXT: ret void 248; 249 %p1 = getelementptr inbounds i32, ptr addrspace(2) %input, i32 %s 250 call void @baz2(ptr addrspace(2) %p1) 251 252 ; p2 = &input[s * 2] 253 %s2 = mul nsw i32 %s, 2 254 %p2 = getelementptr inbounds i32, ptr addrspace(2) %input, i32 %s2 255 ; Use index bitwidth, not pointer size (i128) 256 call void @baz2(ptr addrspace(2) %p2) 257 258 ret void 259} 260 261 262declare void @foo(ptr) 263declare void @bar(ptr) 264declare void @baz(ptr addrspace(1)) 265declare void @baz2(ptr addrspace(2)) 266