; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Verify that strncmp calls with members of constant structs are folded. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s ; struct A { char a[3], b[4], c[4]; }; %struct.A = type { [3 x i8], [4 x i8], [4 x i8] } @a = constant %struct.A { [3 x i8] c"123", [4 x i8] c"1231", [4 x i8] c"2345" } declare i32 @strncmp(i8*, i8*, i64) define void @fold_strncmp_Aa_b(i32* %pcmp) { ; CHECK-LABEL: @fold_strncmp_Aa_b( ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 ; CHECK-NEXT: [[PCMP1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 ; CHECK-NEXT: store i32 0, i32* [[PCMP1]], align 4 ; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 ; CHECK-NEXT: store i32 0, i32* [[PCMP2]], align 4 ; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 ; CHECK-NEXT: store i32 0, i32* [[PCMP3]], align 4 ; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 ; CHECK-NEXT: store i32 0, i32* [[PCMP4]], align 4 ; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 ; CHECK-NEXT: store i32 0, i32* [[PCMP5]], align 4 ; CHECK-NEXT: [[PCMP6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6 ; CHECK-NEXT: store i32 0, i32* [[PCMP6]], align 4 ; CHECK-NEXT: [[PCMP7:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7 ; CHECK-NEXT: store i32 -1, i32* [[PCMP7]], align 4 ; CHECK-NEXT: [[PCMP8:%.*]] = getelementptr i32, i32* [[PCMP]], i64 8 ; CHECK-NEXT: store i32 -1, i32* [[PCMP8]], align 4 ; CHECK-NEXT: [[PCMP9:%.*]] = getelementptr i32, i32* [[PCMP]], i64 9 ; CHECK-NEXT: store i32 -1, i32* [[PCMP9]], align 4 ; CHECK-NEXT: ret void ; ; p1 = a.a %p1 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 0, i32 0 ; p2 = a.b %p2 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 1, i32 0 ; Fold strncmp(a.a = "123", a.b = "1231", 0) to 0. %cmp0 = call i32 @strncmp(i8* %p1, i8* %p2, i64 0) %pcmp0 = getelementptr i32, i32* %pcmp, i64 0 store i32 %cmp0, i32* %pcmp0 ; Fold strncmp(a.a = "123", a.b = "1231", 1) to 0. %cmp1 = call i32 @strncmp(i8* %p1, i8* %p2, i64 1) %pcmp1 = getelementptr i32, i32* %pcmp, i64 1 store i32 %cmp1, i32* %pcmp1 ; Fold strncmp(a.a = "123", a.b = "1231", 2) to 0. %cmp2 = call i32 @strncmp(i8* %p1, i8* %p2, i64 2) %pcmp2 = getelementptr i32, i32* %pcmp, i64 2 store i32 %cmp2, i32* %pcmp2 ; Fold strncmp(a.a = "123", a.b = "1231", 3) to 0. %cmp3 = call i32 @strncmp(i8* %p1, i8* %p2, i64 3) %pcmp3 = getelementptr i32, i32* %pcmp, i64 3 store i32 %cmp3, i32* %pcmp3 ; Fold strncmp(a.a = "123", a.b = "1231", 4) to 0. ; In this and the subsequent tests, reading past the end of a.a is ; strictly undefined in C/C++ (because it forms a pointer to a distinct ; subobject) but handling such cases as if they were well-defined is ; simpler than trying to exclude them. %cmp4 = call i32 @strncmp(i8* %p1, i8* %p2, i64 4) %pcmp4 = getelementptr i32, i32* %pcmp, i64 4 store i32 %cmp4, i32* %pcmp4 ; Fold strncmp("123", "1231" "2", 5) to 0. %cmp5 = call i32 @strncmp(i8* %p1, i8* %p2, i64 5) %pcmp5 = getelementptr i32, i32* %pcmp, i64 5 store i32 %cmp5, i32* %pcmp5 ; Fold strncmp("123", "1231" "23", 6) to 0. %cmp6 = call i32 @strncmp(i8* %p1, i8* %p2, i64 6) %pcmp6 = getelementptr i32, i32* %pcmp, i64 6 store i32 %cmp6, i32* %pcmp6 ; Fold strncmp("123", "1231" "2345", 7) to 1. %cmp7 = call i32 @strncmp(i8* %p1, i8* %p2, i64 7) %pcmp7 = getelementptr i32, i32* %pcmp, i64 7 store i32 %cmp7, i32* %pcmp7 ; Fold strncmp("123", "1231" "2345", 8) to 1. %cmp8 = call i32 @strncmp(i8* %p1, i8* %p2, i64 8) %pcmp8 = getelementptr i32, i32* %pcmp, i64 8 store i32 %cmp8, i32* %pcmp8 ; Fold strncmp("123", "1231" "2345", 9) to 1. %cmp9 = call i32 @strncmp(i8* %p1, i8* %p2, i64 9) %pcmp9 = getelementptr i32, i32* %pcmp, i64 9 store i32 %cmp9, i32* %pcmp9 ret void } define void @fold_strncmp_Ab_a(i32* %pcmp) { ; CHECK-LABEL: @fold_strncmp_Ab_a( ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 ; CHECK-NEXT: [[PCMP1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 ; CHECK-NEXT: store i32 0, i32* [[PCMP1]], align 4 ; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 ; CHECK-NEXT: store i32 0, i32* [[PCMP2]], align 4 ; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 ; CHECK-NEXT: store i32 0, i32* [[PCMP3]], align 4 ; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 ; CHECK-NEXT: store i32 1, i32* [[PCMP4]], align 4 ; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 ; CHECK-NEXT: store i32 1, i32* [[PCMP5]], align 4 ; CHECK-NEXT: ret void ; ; p1 = &a.b[3] %p1 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 1, i32 3 ; p2 = &a.a %p2 = getelementptr %struct.A, %struct.A* @a, i32 0, i32 0, i32 0 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 0) to 0. %cmp0 = call i32 @strncmp(i8* %p1, i8* %p2, i64 0) %pcmp0 = getelementptr i32, i32* %pcmp, i64 0 store i32 %cmp0, i32* %pcmp0 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 1) to 0. %cmp1 = call i32 @strncmp(i8* %p1, i8* %p2, i64 1) %pcmp1 = getelementptr i32, i32* %pcmp, i64 1 store i32 %cmp1, i32* %pcmp1 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 2) to 0. %cmp2 = call i32 @strncmp(i8* %p1, i8* %p2, i64 2) %pcmp2 = getelementptr i32, i32* %pcmp, i64 2 store i32 %cmp2, i32* %pcmp2 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 3) to 0. %cmp3 = call i32 @strncmp(i8* %p1, i8* %p2, i64 3) %pcmp3 = getelementptr i32, i32* %pcmp, i64 3 store i32 %cmp3, i32* %pcmp3 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 4) to 1. %cmp4 = call i32 @strncmp(i8* %p1, i8* %p2, i64 4) %pcmp4 = getelementptr i32, i32* %pcmp, i64 4 store i32 %cmp4, i32* %pcmp4 ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 5) to 1. %cmp5 = call i32 @strncmp(i8* %p1, i8* %p2, i64 5) %pcmp5 = getelementptr i32, i32* %pcmp, i64 5 store i32 %cmp5, i32* %pcmp5 ret void }