1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; Verify that strlen calls with members of constant structs are folded. 3; 4; RUN: opt < %s -passes=instcombine -S | FileCheck %s 5 6; struct A_a4 { char a[4]; }; 7%struct.A_a4 = type { [4 x i8] } 8 9; struct A_a4_a5 { char a[4], b[5]; }; 10%struct.A_a4_a5 = type { [4 x i8], [5 x i8] } 11 12; struct A_a4_i32_a5 { char a[4]; int32_t i; char b[5]; }; 13%struct.A_a4_i32_a5 = type { [4 x i8], i32, [5 x i8] } 14 15@a_s3 = constant %struct.A_a4 { [4 x i8 ] c"123\00" } 16@a_s3_s4 = constant %struct.A_a4_a5 { [4 x i8 ] c"123\00", [5 x i8] c"1234\00" } 17@a_s3_i32_s4 = constant %struct.A_a4_i32_a5 { [4 x i8 ] c"123\00", i32 -1, [5 x i8] c"1234\00" } 18 19; Structs with flexible array members. 20@ax_s3 = constant { i8, [4 x i8] } { i8 3, [4 x i8] c"123\00" } 21@ax_s5 = constant { i16, [6 x i8] } { i16 5, [6 x i8] c"12345\00" } 22@ax_s7 = constant { i32, i32, [8 x i8] } { i32 7, i32 0, [8 x i8] c"1234567\00" } 23 24@ax = external global [0 x i64] 25 26 27declare i64 @strlen(i8*) 28 29 30; Fold strlen(a_s3.a) to 3. 31 32define i64 @fold_strlen_a_S3_to_3() { 33; CHECK-LABEL: @fold_strlen_a_S3_to_3( 34; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 0)) 35; CHECK-NEXT: ret i64 [[LEN]] 36; 37 %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 0 38 %len = call i64 @strlen(i8* %ptr) 39 ret i64 %len 40} 41 42 43; Fold strlen(&a_s3.a[1]) to 2. 44 45define i64 @fold_strlen_a_S3_p1_to_2() { 46; CHECK-LABEL: @fold_strlen_a_S3_p1_to_2( 47; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 1)) 48; CHECK-NEXT: ret i64 [[LEN]] 49; 50 %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 1 51 %len = call i64 @strlen(i8* %ptr) 52 ret i64 %len 53} 54 55 56; Fold strlen(&a_s3.a[2]) to 1. 57 58define i64 @fold_strlen_a_S3_p2_to_1() { 59; CHECK-LABEL: @fold_strlen_a_S3_p2_to_1( 60; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 2)) 61; CHECK-NEXT: ret i64 [[LEN]] 62; 63 %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 2 64 %len = call i64 @strlen(i8* %ptr) 65 ret i64 %len 66} 67 68 69; Fold strlen(&a_s3.a[3]) to 0. 70 71define i64 @fold_strlen_a_S3_p3_to_0() { 72; CHECK-LABEL: @fold_strlen_a_S3_p3_to_0( 73; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 3)) 74; CHECK-NEXT: ret i64 [[LEN]] 75; 76 %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 3 77 %len = call i64 @strlen(i8* %ptr) 78 ret i64 %len 79} 80 81 82; Fold strlen(a_s3_s4.a) to 3. 83 84define i64 @fold_strlen_a_S3_s4_to_3() { 85; CHECK-LABEL: @fold_strlen_a_S3_s4_to_3( 86; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 0)) 87; CHECK-NEXT: ret i64 [[LEN]] 88; 89 %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 0 90 %len = call i64 @strlen(i8* %ptr) 91 ret i64 %len 92} 93 94 95; Fold strlen(&a_s3_s4.a[2]) to 1. 96 97define i64 @fold_strlen_a_S3_p2_s4_to_1() { 98; CHECK-LABEL: @fold_strlen_a_S3_p2_s4_to_1( 99; CHECK-NEXT: [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 2)) 100; CHECK-NEXT: ret i64 [[LEN]] 101; 102 %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 2 103 %len = call i64 @strlen(i8* %ptr) 104 ret i64 %len 105} 106 107 108; Fold strlen(a_s3_s4.b) to 4. 109; Exercise both variants of the GEP index. 110 111define void @fold_strlen_a_s3_S4_to_4() { 112; CHECK-LABEL: @fold_strlen_a_s3_S4_to_4( 113; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0)) 114; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 115; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0)) 116; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 117; CHECK-NEXT: ret void 118; 119 %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 4 120 %len1 = call i64 @strlen(i8* %p1) 121 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 122 store i64 %len1, i64* %pax0 123 124 %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 0 125 %len2 = call i64 @strlen(i8* %p2) 126 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 127 store i64 %len1, i64* %pax1 128 129 ret void 130} 131 132 133; Fold strlen(&a_s3_s4.b[1]) to 3. 134; Exercise both variants of the GEP index. 135 136define void @fold_strlen_a_s3_S4_p1_to_3() { 137; CHECK-LABEL: @fold_strlen_a_s3_S4_p1_to_3( 138; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1)) 139; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 140; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1)) 141; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 142; CHECK-NEXT: ret void 143; 144 %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 5 145 %len1 = call i64 @strlen(i8* %p1) 146 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 147 store i64 %len1, i64* %pax0 148 149 %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 1 150 %len2 = call i64 @strlen(i8* %p2) 151 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 152 store i64 %len1, i64* %pax1 153 154 ret void 155} 156 157 158; Fold strlen(a_s3_i32_s4.b) to 4. 159; Exercise both variants of the GEP index. 160 161define void @fold_strlen_a_s3_i32_S4_to_4() { 162; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_to_4( 163; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0)) 164; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 165; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0)) 166; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 167; CHECK-NEXT: ret void 168; 169 %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 8 170 %len1 = call i64 @strlen(i8* %p1) 171 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 172 store i64 %len1, i64* %pax0 173 174 %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0 175 %len2 = call i64 @strlen(i8* %p2) 176 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 177 store i64 %len1, i64* %pax1 178 179 ret void 180} 181 182 183; Fold strlen(&a_s3_i32_s4.b[1]) to 3. 184; Exercise both variants of the GEP index. 185 186define void @fold_strlen_a_s3_i32_S4_p1_to_3() { 187; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p1_to_3( 188; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 1)) 189; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 190; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0)) 191; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 192; CHECK-NEXT: ret void 193; 194 %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 9 195 %len1 = call i64 @strlen(i8* %p1) 196 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 197 store i64 %len1, i64* %pax0 198 199 %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0 200 %len2 = call i64 @strlen(i8* %p2) 201 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 202 store i64 %len1, i64* %pax1 203 204 ret void 205} 206 207 208; Fold strlen(&a_s3_i32_s4.b[2]) to 2. 209; Exercise both variants of the GEP index. 210 211define void @fold_strlen_a_s3_i32_S4_p2_to_2() { 212; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p2_to_2( 213; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2)) 214; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 215; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2)) 216; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 217; CHECK-NEXT: ret void 218; 219 %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 10 220 %len1 = call i64 @strlen(i8* %p1) 221 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 222 store i64 %len1, i64* %pax0 223 224 %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 2 225 %len2 = call i64 @strlen(i8* %p2) 226 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 227 store i64 %len1, i64* %pax1 228 229 ret void 230} 231 232 233; Fold strlen(&a_s3_i32_s4.b[3]) to 1. 234; Exercise both variants of the GEP index. 235 236define void @fold_strlen_a_s3_i32_S4_p3_to_1() { 237; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p3_to_1( 238; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3)) 239; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 240; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3)) 241; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 242; CHECK-NEXT: ret void 243; 244 %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 11 245 %len1 = call i64 @strlen(i8* %p1) 246 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 247 store i64 %len1, i64* %pax0 248 249 %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 3 250 %len2 = call i64 @strlen(i8* %p2) 251 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 252 store i64 %len1, i64* %pax1 253 254 ret void 255} 256 257 258; Fold strlen(&a_s3_i32_s4.b[4]) to 0. 259; Exercise both variants of the GEP index. 260 261define void @fold_strlen_a_s3_i32_S4_p4_to_0() { 262; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p4_to_0( 263; CHECK-NEXT: [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4)) 264; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 265; CHECK-NEXT: [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4)) 266; CHECK-NEXT: store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 267; CHECK-NEXT: ret void 268; 269 %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 12 270 %len1 = call i64 @strlen(i8* %p1) 271 %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 272 store i64 %len1, i64* %pax0 273 274 %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 4 275 %len2 = call i64 @strlen(i8* %p2) 276 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 277 store i64 %len1, i64* %pax1 278 279 ret void 280} 281 282 283; Fold strlen(ax_sN.a) of an constant initialized flexible array member 284; to N for N in { 3, 5, 7 }. 285 286define void @fold_strlen_ax_s() { 287; CHECK-LABEL: @fold_strlen_ax_s( 288; CHECK-NEXT: [[LEN3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0)) 289; CHECK-NEXT: store i64 [[LEN3]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4 290; CHECK-NEXT: [[LEN5:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0)) 291; CHECK-NEXT: store i64 [[LEN5]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4 292; CHECK-NEXT: [[LEN7:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0)) 293; CHECK-NEXT: store i64 [[LEN7]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 2), align 4 294; CHECK-NEXT: ret void 295; 296 %pax_s3 = getelementptr { i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0 297 %len3 = call i64 @strlen(i8* %pax_s3) 298 %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0 299 store i64 %len3, i64* %pax1 300 301 %pax_s5 = getelementptr { i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0 302 %len5 = call i64 @strlen(i8* %pax_s5) 303 %pax2 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1 304 store i64 %len5, i64* %pax2 305 306 %pax_s7 = getelementptr { i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0 307 %len7 = call i64 @strlen(i8* %pax_s7) 308 %pax3 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 2 309 store i64 %len7, i64* %pax3 310 311 ret void 312} 313