| ; 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(ptr, ptr, i64) |
| |
| define void @fold_strncmp_Aa_b(ptr %pcmp) { |
| ; CHECK-LABEL: @fold_strncmp_Aa_b( |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP:%.*]], align 4 |
| ; CHECK-NEXT: [[PCMP1:%.*]] = getelementptr i32, ptr [[PCMP]], i64 1 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP1]], align 4 |
| ; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, ptr [[PCMP]], i64 2 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP2]], align 4 |
| ; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, ptr [[PCMP]], i64 3 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP3]], align 4 |
| ; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, ptr [[PCMP]], i64 4 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP4]], align 4 |
| ; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, ptr [[PCMP]], i64 5 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP5]], align 4 |
| ; CHECK-NEXT: [[PCMP6:%.*]] = getelementptr i32, ptr [[PCMP]], i64 6 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP6]], align 4 |
| ; CHECK-NEXT: [[PCMP7:%.*]] = getelementptr i32, ptr [[PCMP]], i64 7 |
| ; CHECK-NEXT: store i32 -1, ptr [[PCMP7]], align 4 |
| ; CHECK-NEXT: [[PCMP8:%.*]] = getelementptr i32, ptr [[PCMP]], i64 8 |
| ; CHECK-NEXT: store i32 -1, ptr [[PCMP8]], align 4 |
| ; CHECK-NEXT: [[PCMP9:%.*]] = getelementptr i32, ptr [[PCMP]], i64 9 |
| ; CHECK-NEXT: store i32 -1, ptr [[PCMP9]], align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| ; p1 = a.a |
| ; p2 = a.b |
| %p2 = getelementptr %struct.A, ptr @a, i32 0, i32 1, i32 0 |
| |
| ; Fold strncmp(a.a = "123", a.b = "1231", 0) to 0. |
| %cmp0 = call i32 @strncmp(ptr @a, ptr %p2, i64 0) |
| store i32 %cmp0, ptr %pcmp |
| |
| ; Fold strncmp(a.a = "123", a.b = "1231", 1) to 0. |
| %cmp1 = call i32 @strncmp(ptr @a, ptr %p2, i64 1) |
| %pcmp1 = getelementptr i32, ptr %pcmp, i64 1 |
| store i32 %cmp1, ptr %pcmp1 |
| |
| ; Fold strncmp(a.a = "123", a.b = "1231", 2) to 0. |
| %cmp2 = call i32 @strncmp(ptr @a, ptr %p2, i64 2) |
| %pcmp2 = getelementptr i32, ptr %pcmp, i64 2 |
| store i32 %cmp2, ptr %pcmp2 |
| |
| ; Fold strncmp(a.a = "123", a.b = "1231", 3) to 0. |
| %cmp3 = call i32 @strncmp(ptr @a, ptr %p2, i64 3) |
| %pcmp3 = getelementptr i32, ptr %pcmp, i64 3 |
| store i32 %cmp3, ptr %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(ptr @a, ptr %p2, i64 4) |
| %pcmp4 = getelementptr i32, ptr %pcmp, i64 4 |
| store i32 %cmp4, ptr %pcmp4 |
| |
| ; Fold strncmp("123", "1231" "2", 5) to 0. |
| %cmp5 = call i32 @strncmp(ptr @a, ptr %p2, i64 5) |
| %pcmp5 = getelementptr i32, ptr %pcmp, i64 5 |
| store i32 %cmp5, ptr %pcmp5 |
| |
| ; Fold strncmp("123", "1231" "23", 6) to 0. |
| %cmp6 = call i32 @strncmp(ptr @a, ptr %p2, i64 6) |
| %pcmp6 = getelementptr i32, ptr %pcmp, i64 6 |
| store i32 %cmp6, ptr %pcmp6 |
| |
| ; Fold strncmp("123", "1231" "2345", 7) to 1. |
| %cmp7 = call i32 @strncmp(ptr @a, ptr %p2, i64 7) |
| %pcmp7 = getelementptr i32, ptr %pcmp, i64 7 |
| store i32 %cmp7, ptr %pcmp7 |
| |
| ; Fold strncmp("123", "1231" "2345", 8) to 1. |
| %cmp8 = call i32 @strncmp(ptr @a, ptr %p2, i64 8) |
| %pcmp8 = getelementptr i32, ptr %pcmp, i64 8 |
| store i32 %cmp8, ptr %pcmp8 |
| |
| ; Fold strncmp("123", "1231" "2345", 9) to 1. |
| %cmp9 = call i32 @strncmp(ptr @a, ptr %p2, i64 9) |
| %pcmp9 = getelementptr i32, ptr %pcmp, i64 9 |
| store i32 %cmp9, ptr %pcmp9 |
| |
| ret void |
| } |
| |
| |
| define void @fold_strncmp_Ab_a(ptr %pcmp) { |
| ; CHECK-LABEL: @fold_strncmp_Ab_a( |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP:%.*]], align 4 |
| ; CHECK-NEXT: [[PCMP1:%.*]] = getelementptr i32, ptr [[PCMP]], i64 1 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP1]], align 4 |
| ; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, ptr [[PCMP]], i64 2 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP2]], align 4 |
| ; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, ptr [[PCMP]], i64 3 |
| ; CHECK-NEXT: store i32 0, ptr [[PCMP3]], align 4 |
| ; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, ptr [[PCMP]], i64 4 |
| ; CHECK-NEXT: store i32 1, ptr [[PCMP4]], align 4 |
| ; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, ptr [[PCMP]], i64 5 |
| ; CHECK-NEXT: store i32 1, ptr [[PCMP5]], align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| ; p1 = &a.b[3] |
| %p1 = getelementptr %struct.A, ptr @a, i32 0, i32 1, i32 3 |
| ; p2 = &a.a |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 0) to 0. |
| %cmp0 = call i32 @strncmp(ptr %p1, ptr @a, i64 0) |
| store i32 %cmp0, ptr %pcmp |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 1) to 0. |
| %cmp1 = call i32 @strncmp(ptr %p1, ptr @a, i64 1) |
| %pcmp1 = getelementptr i32, ptr %pcmp, i64 1 |
| store i32 %cmp1, ptr %pcmp1 |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 2) to 0. |
| %cmp2 = call i32 @strncmp(ptr %p1, ptr @a, i64 2) |
| %pcmp2 = getelementptr i32, ptr %pcmp, i64 2 |
| store i32 %cmp2, ptr %pcmp2 |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 3) to 0. |
| %cmp3 = call i32 @strncmp(ptr %p1, ptr @a, i64 3) |
| %pcmp3 = getelementptr i32, ptr %pcmp, i64 3 |
| store i32 %cmp3, ptr %pcmp3 |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 4) to 1. |
| %cmp4 = call i32 @strncmp(ptr %p1, ptr @a, i64 4) |
| %pcmp4 = getelementptr i32, ptr %pcmp, i64 4 |
| store i32 %cmp4, ptr %pcmp4 |
| |
| ; Fold strncmp(a.a = "123", &a.b[3] = "1" "2345", 5) to 1. |
| %cmp5 = call i32 @strncmp(ptr %p1, ptr @a, i64 5) |
| %pcmp5 = getelementptr i32, ptr %pcmp, i64 5 |
| store i32 %cmp5, ptr %pcmp5 |
| |
| ret void |
| } |