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(ptr) 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: ret i64 3 35; 36 %len = call i64 @strlen(ptr @a_s3) 37 ret i64 %len 38} 39 40 41; Fold strlen(&a_s3.a[1]) to 2. 42 43define i64 @fold_strlen_a_S3_p1_to_2() { 44; CHECK-LABEL: @fold_strlen_a_S3_p1_to_2( 45; CHECK-NEXT: ret i64 2 46; 47 %ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 1 48 %len = call i64 @strlen(ptr %ptr) 49 ret i64 %len 50} 51 52 53; Fold strlen(&a_s3.a[2]) to 1. 54 55define i64 @fold_strlen_a_S3_p2_to_1() { 56; CHECK-LABEL: @fold_strlen_a_S3_p2_to_1( 57; CHECK-NEXT: ret i64 1 58; 59 %ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 2 60 %len = call i64 @strlen(ptr %ptr) 61 ret i64 %len 62} 63 64 65; Fold strlen(&a_s3.a[3]) to 0. 66 67define i64 @fold_strlen_a_S3_p3_to_0() { 68; CHECK-LABEL: @fold_strlen_a_S3_p3_to_0( 69; CHECK-NEXT: ret i64 0 70; 71 %ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 3 72 %len = call i64 @strlen(ptr %ptr) 73 ret i64 %len 74} 75 76 77; Fold strlen(a_s3_s4.a) to 3. 78 79define i64 @fold_strlen_a_S3_s4_to_3() { 80; CHECK-LABEL: @fold_strlen_a_S3_s4_to_3( 81; CHECK-NEXT: ret i64 3 82; 83 %len = call i64 @strlen(ptr @a_s3_s4) 84 ret i64 %len 85} 86 87 88; Fold strlen(&a_s3_s4.a[2]) to 1. 89 90define i64 @fold_strlen_a_S3_p2_s4_to_1() { 91; CHECK-LABEL: @fold_strlen_a_S3_p2_s4_to_1( 92; CHECK-NEXT: ret i64 1 93; 94 %ptr = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 2 95 %len = call i64 @strlen(ptr %ptr) 96 ret i64 %len 97} 98 99 100; Fold strlen(a_s3_s4.b) to 4. 101; Exercise both variants of the GEP index. 102 103define void @fold_strlen_a_s3_S4_to_4() { 104; CHECK-LABEL: @fold_strlen_a_s3_S4_to_4( 105; CHECK-NEXT: store i64 4, ptr @ax, align 4 106; CHECK-NEXT: store i64 4, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 107; CHECK-NEXT: ret void 108; 109 %p1 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 4 110 %len1 = call i64 @strlen(ptr %p1) 111 store i64 %len1, ptr @ax 112 113 %p2 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 1, i32 0 114 %len2 = call i64 @strlen(ptr %p2) 115 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 116 store i64 %len1, ptr %pax1 117 118 ret void 119} 120 121 122; Fold strlen(&a_s3_s4.b[1]) to 3. 123; Exercise both variants of the GEP index. 124 125define void @fold_strlen_a_s3_S4_p1_to_3() { 126; CHECK-LABEL: @fold_strlen_a_s3_S4_p1_to_3( 127; CHECK-NEXT: store i64 3, ptr @ax, align 4 128; CHECK-NEXT: store i64 3, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 129; CHECK-NEXT: ret void 130; 131 %p1 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 5 132 %len1 = call i64 @strlen(ptr %p1) 133 store i64 %len1, ptr @ax 134 135 %p2 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 1, i32 1 136 %len2 = call i64 @strlen(ptr %p2) 137 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 138 store i64 %len1, ptr %pax1 139 140 ret void 141} 142 143 144; Fold strlen(a_s3_i32_s4.b) to 4. 145; Exercise both variants of the GEP index. 146 147define void @fold_strlen_a_s3_i32_S4_to_4() { 148; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_to_4( 149; CHECK-NEXT: store i64 4, ptr @ax, align 4 150; CHECK-NEXT: store i64 4, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 151; CHECK-NEXT: ret void 152; 153 %p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 8 154 %len1 = call i64 @strlen(ptr %p1) 155 store i64 %len1, ptr @ax 156 157 %p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 0 158 %len2 = call i64 @strlen(ptr %p2) 159 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 160 store i64 %len1, ptr %pax1 161 162 ret void 163} 164 165 166; Fold strlen(&a_s3_i32_s4.b[1]) to 3. 167; Exercise both variants of the GEP index. 168 169define void @fold_strlen_a_s3_i32_S4_p1_to_3() { 170; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p1_to_3( 171; CHECK-NEXT: store i64 3, ptr @ax, align 4 172; CHECK-NEXT: store i64 3, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 173; CHECK-NEXT: ret void 174; 175 %p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 9 176 %len1 = call i64 @strlen(ptr %p1) 177 store i64 %len1, ptr @ax 178 179 %p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 0 180 %len2 = call i64 @strlen(ptr %p2) 181 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 182 store i64 %len1, ptr %pax1 183 184 ret void 185} 186 187 188; Fold strlen(&a_s3_i32_s4.b[2]) to 2. 189; Exercise both variants of the GEP index. 190 191define void @fold_strlen_a_s3_i32_S4_p2_to_2() { 192; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p2_to_2( 193; CHECK-NEXT: store i64 2, ptr @ax, align 4 194; CHECK-NEXT: store i64 2, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 195; CHECK-NEXT: ret void 196; 197 %p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 10 198 %len1 = call i64 @strlen(ptr %p1) 199 store i64 %len1, ptr @ax 200 201 %p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 2 202 %len2 = call i64 @strlen(ptr %p2) 203 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 204 store i64 %len1, ptr %pax1 205 206 ret void 207} 208 209 210; Fold strlen(&a_s3_i32_s4.b[3]) to 1. 211; Exercise both variants of the GEP index. 212 213define void @fold_strlen_a_s3_i32_S4_p3_to_1() { 214; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p3_to_1( 215; CHECK-NEXT: store i64 1, ptr @ax, align 4 216; CHECK-NEXT: store i64 1, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 217; CHECK-NEXT: ret void 218; 219 %p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 11 220 %len1 = call i64 @strlen(ptr %p1) 221 store i64 %len1, ptr @ax 222 223 %p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 3 224 %len2 = call i64 @strlen(ptr %p2) 225 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 226 store i64 %len1, ptr %pax1 227 228 ret void 229} 230 231 232; Fold strlen(&a_s3_i32_s4.b[4]) to 0. 233; Exercise both variants of the GEP index. 234 235define void @fold_strlen_a_s3_i32_S4_p4_to_0() { 236; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p4_to_0( 237; CHECK-NEXT: store i64 0, ptr @ax, align 4 238; CHECK-NEXT: store i64 0, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 239; CHECK-NEXT: ret void 240; 241 %p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 12 242 %len1 = call i64 @strlen(ptr %p1) 243 store i64 %len1, ptr @ax 244 245 %p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 4 246 %len2 = call i64 @strlen(ptr %p2) 247 %pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 248 store i64 %len1, ptr %pax1 249 250 ret void 251} 252 253 254; Fold strlen(ax_sN.a) of an constant initialized flexible array member 255; to N for N in { 3, 5, 7 }. 256 257define void @fold_strlen_ax_s() { 258; CHECK-LABEL: @fold_strlen_ax_s( 259; CHECK-NEXT: store i64 3, ptr @ax, align 4 260; CHECK-NEXT: store i64 5, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 8), align 4 261; CHECK-NEXT: store i64 7, ptr getelementptr inbounds nuw (i8, ptr @ax, i64 16), align 4 262; CHECK-NEXT: ret void 263; 264 %pax_s3 = getelementptr { i8, [4 x i8] }, ptr @ax_s3, i64 0, i32 1, i64 0 265 %len3 = call i64 @strlen(ptr %pax_s3) 266 store i64 %len3, ptr @ax 267 268 %pax_s5 = getelementptr { i16, [6 x i8] }, ptr @ax_s5, i64 0, i32 1, i64 0 269 %len5 = call i64 @strlen(ptr %pax_s5) 270 %pax2 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1 271 store i64 %len5, ptr %pax2 272 273 %pax_s7 = getelementptr { i32, i32, [8 x i8] }, ptr @ax_s7, i64 0, i32 2, i64 0 274 %len7 = call i64 @strlen(ptr %pax_s7) 275 %pax3 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 2 276 store i64 %len7, ptr %pax3 277 278 ret void 279} 280