| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Exercise folding of memcmp calls with addition expressions involving | ||
| ; pointers into constant arrays of types larger than char and fractional | ||
| ; offsets. | ||
|
|
||
| declare i32 @memcmp(i8*, i8*, i64) | ||
|
|
||
| @i32a = constant [2 x i16] [i16 4386, i16 13124] | ||
| @i32b = constant [2 x i16] [i16 4386, i16 13124] | ||
|
|
||
|
|
||
| define void @fold_memcmp_i32a_i32b_pIb(i32 %I, i32* %pcmp) | ||
| ; CHECK-LABEL: @fold_memcmp_i32a_i32b_pIb( | ||
| ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PST_1_1_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PST_1_1_2]], align 4 | ||
| ; CHECK-NEXT: [[PST_1_1_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PST_1_1_3]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| { | ||
| %pi32a = getelementptr [2 x i16], [2 x i16]* @i32a, i32 0, i32 0 | ||
| %pi32b = getelementptr [2 x i16], [2 x i16]* @i32b, i32 0, i32 0 | ||
|
|
||
| %pi8a = bitcast i16* %pi32a to i8* | ||
| %pi8b = bitcast i16* %pi32b to i8* | ||
|
|
||
| %pi8ap1 = getelementptr i8, i8* %pi8a, i32 1 | ||
| %pi8bp1 = getelementptr i8, i8* %pi8b, i32 1 | ||
|
|
||
| %pst_1_1_1 = getelementptr i32, i32* %pcmp, i32 0 | ||
| %cmp_1_1_1 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8ap1, i64 1) | ||
| store i32 %cmp_1_1_1, i32* %pst_1_1_1 | ||
|
|
||
| %pst_1_1_2 = getelementptr i32, i32* %pcmp, i32 1 | ||
| %cmp_1_1_2 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8ap1, i64 2) | ||
| store i32 %cmp_1_1_2, i32* %pst_1_1_2 | ||
|
|
||
| %pst_1_1_3 = getelementptr i32, i32* %pcmp, i32 2 | ||
| %cmp_1_1_3 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8ap1, i64 3) | ||
| store i32 %cmp_1_1_3, i32* %pst_1_1_3 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| %struct.A = type { [4 x i8] } | ||
| %struct.B = type { [2 x i8], [2 x i8] } | ||
|
|
||
| @a = constant [1 x %struct.A] [%struct.A { [4 x i8] [i8 1, i8 2, i8 3, i8 4] }] | ||
| @b = constant [1 x %struct.B] [%struct.B { [2 x i8] [i8 1, i8 2], [2 x i8] [i8 3, i8 4]}] | ||
|
|
||
| define void @fold_memcmp_A_B_pIb(i32 %I, i32* %pcmp) { | ||
| ; CHECK-LABEL: @fold_memcmp_A_B_pIb( | ||
| ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_0_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PST_0_0_2]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_0_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PST_0_0_3]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_0_4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PST_0_0_4]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_1_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PST_0_1_1]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_1_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PST_0_1_2]], align 4 | ||
| ; CHECK-NEXT: [[PST_0_1_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PST_0_1_3]], align 4 | ||
| ; CHECK-NEXT: [[PST_1_0_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 | ||
| ; CHECK-NEXT: store i32 1, i32* [[PST_1_0_1]], align 4 | ||
| ; CHECK-NEXT: [[PST_1_0_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 | ||
| ; CHECK-NEXT: store i32 1, i32* [[PST_1_0_2]], align 4 | ||
| ; CHECK-NEXT: [[PST_1_0_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6 | ||
| ; CHECK-NEXT: store i32 1, i32* [[PST_1_0_3]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %pa = getelementptr [1 x %struct.A], [1 x %struct.A]* @a, i64 0, i64 0 | ||
| %pb = getelementptr [1 x %struct.B], [1 x %struct.B]* @b, i64 0, i64 0 | ||
|
|
||
| %pi8a = bitcast %struct.A* %pa to i8* | ||
| %pi8b = bitcast %struct.B* %pb to i8* | ||
|
|
||
| %pi8ap0 = getelementptr i8, i8* %pi8a, i32 0 | ||
| %pi8bp0 = getelementptr i8, i8* %pi8b, i32 0 | ||
|
|
||
| ; Fold memcmp(&a, &b, 1) to 0; | ||
| %pst_0_0_1 = getelementptr i32, i32* %pcmp, i32 0 | ||
| %cmp_0_0_1 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp0, i64 1) | ||
| store i32 %cmp_0_0_1, i32* %pst_0_0_1 | ||
|
|
||
| ; Fold memcmp(&a, &b, 2) to 0; | ||
| %pst_0_0_2 = getelementptr i32, i32* %pcmp, i32 1 | ||
| %cmp_0_0_2 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp0, i64 2) | ||
| store i32 %cmp_0_0_2, i32* %pst_0_0_2 | ||
|
|
||
| ; Fold memcmp(&a, &b, 3) to 0; | ||
| %pst_0_0_3 = getelementptr i32, i32* %pcmp, i32 2 | ||
| %cmp_0_0_3 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp0, i64 3) | ||
| store i32 %cmp_0_0_3, i32* %pst_0_0_3 | ||
|
|
||
| ; Fold memcmp(&a, &b, 4) to 0; | ||
| %pst_0_0_4 = getelementptr i32, i32* %pcmp, i32 3 | ||
| %cmp_0_0_4 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp0, i64 4) | ||
| store i32 %cmp_0_0_4, i32* %pst_0_0_4 | ||
|
|
||
|
|
||
| %pi8bp1 = getelementptr i8, i8* %pi8b, i32 1 | ||
|
|
||
| ; Fold memcmp(&a, (char*)&b + 1, 1) to -1; | ||
| %pst_0_1_1 = getelementptr i32, i32* %pcmp, i32 4 | ||
| %cmp_0_1_1 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp1, i64 1) | ||
| store i32 %cmp_0_1_1, i32* %pst_0_1_1 | ||
|
|
||
| ; Fold memcmp(&a, (char*)&b + 1, 2) to -1; | ||
| %pst_0_1_2 = getelementptr i32, i32* %pcmp, i32 5 | ||
| %cmp_0_1_2 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp1, i64 2) | ||
| store i32 %cmp_0_1_2, i32* %pst_0_1_2 | ||
|
|
||
| ; Fold memcmp(&a, (char*)&b + 1, 3) to -1; | ||
| %pst_0_1_3 = getelementptr i32, i32* %pcmp, i32 6 | ||
| %cmp_0_1_3 = call i32 @memcmp(i8* %pi8ap0, i8* %pi8bp1, i64 3) | ||
| store i32 %cmp_0_1_3, i32* %pst_0_1_3 | ||
|
|
||
|
|
||
| %pi8ap1 = getelementptr i8, i8* %pi8a, i32 1 | ||
|
|
||
| ; Fold memcmp((char*)&a + 1, &b, 1) to +1; | ||
| %pst_1_0_1 = getelementptr i32, i32* %pcmp, i32 4 | ||
| %cmp_1_0_1 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8bp0, i64 1) | ||
| store i32 %cmp_1_0_1, i32* %pst_1_0_1 | ||
|
|
||
| ; Fold memcmp((char*)&a + 1, &b, 2) to +1; | ||
| %pst_1_0_2 = getelementptr i32, i32* %pcmp, i32 5 | ||
| %cmp_1_0_2 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8bp0, i64 2) | ||
| store i32 %cmp_1_0_2, i32* %pst_1_0_2 | ||
|
|
||
| ; Fold memcmp((char*)&a + 1, &b, 3) to +1; | ||
| %pst_1_0_3 = getelementptr i32, i32* %pcmp, i32 6 | ||
| %cmp_1_0_3 = call i32 @memcmp(i8* %pi8ap1, i8* %pi8bp0, i64 3) | ||
| store i32 %cmp_1_0_3, i32* %pst_1_0_3 | ||
|
|
||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Verify that the result of memrchr calls with past-the-end pointers used | ||
| ; don't cause trouble and are optimally folded. | ||
|
|
||
| declare i32 @memcmp(i8*, i8*, i64) | ||
|
|
||
|
|
||
| @a5 = constant [5 x i8] c"12345"; | ||
|
|
||
|
|
||
| ; Fold memcmp(a5, a5 + 5, n) to 0 on the assumption that n is 0 otherwise | ||
| ; the call would be undefined. | ||
|
|
||
| define i32 @fold_memcmp_a5_a5p5_n(i64 %n) { | ||
| ; CHECK-LABEL: @fold_memcmp_a5_a5p5_n( | ||
| ; CHECK-NEXT: ret i32 0 | ||
| ; | ||
| %pa5_p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %pa5_p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %cmp = call i32 @memcmp(i8* %pa5_p0, i8* %pa5_p5, i64 %n) | ||
| ret i32 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; Same as above but for memcmp(a5 + 5, a5 + 5, n). | ||
|
|
||
| define i32 @fold_memcmp_a5p5_a5p5_n(i64 %n) { | ||
| ; CHECK-LABEL: @fold_memcmp_a5p5_a5p5_n( | ||
| ; CHECK-NEXT: ret i32 0 | ||
| ; | ||
| %pa5_p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %qa5_p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %cmp = call i32 @memcmp(i8* %pa5_p5, i8* %qa5_p5, i64 %n) | ||
| ret i32 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; TODO: Likewise, fold memcmp(a5 + i, a5 + 5, n) to 0 on same basis. | ||
|
|
||
| define i32 @fold_memcmp_a5pi_a5p5_n(i32 %i, i64 %n) { | ||
| ; CHECK-LABEL: @fold_memcmp_a5pi_a5p5_n( | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[I:%.*]] to i64 | ||
| ; CHECK-NEXT: [[PA5_PI:%.*]] = getelementptr [5 x i8], [5 x i8]* @a5, i64 0, i64 [[TMP1]] | ||
| ; CHECK-NEXT: [[CMP:%.*]] = call i32 @memcmp(i8* [[PA5_PI]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0), i64 [[N:%.*]]) | ||
| ; CHECK-NEXT: ret i32 [[CMP]] | ||
| ; | ||
| %pa5_pi = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 %i | ||
| %pa5_p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %cmp = call i32 @memcmp(i8* %pa5_pi, i8* %pa5_p5, i64 %n) | ||
| ret i32 %cmp | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Verify that the result of memrchr calls with past-the-end pointers used | ||
| ; in equality expressions don't cause trouble and either are folded when | ||
| ; they might be valid or not when they're provably undefined. | ||
|
|
||
| declare i8* @memrchr(i8*, i32, i64) | ||
|
|
||
|
|
||
| @a5 = constant [5 x i8] c"12345" | ||
|
|
||
|
|
||
| ; Fold memrchr(a5 + 5, c, 1) == a5 + 5 to an arbitrary constant. | ||
| ; The call is transformed to a5[5] == c by the memrchr simplifier, with | ||
| ; a5[5] being indeterminate. The equality then is the folded with | ||
| ; an undefined/arbitrary result. | ||
|
|
||
| define i1 @call_memrchr_ap5_c_1_eq_a(i32 %c, i64 %n) { | ||
| ; CHECK-LABEL: @call_memrchr_ap5_c_1_eq_a( | ||
| ; CHECK-NEXT: ret i1 | ||
| ; | ||
| %pap5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %qap5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 1, i32 0 | ||
| %q = call i8* @memrchr(i8* %pap5, i32 %c, i64 1) | ||
| %cmp = icmp eq i8* %q, %qap5 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; Fold memrchr(a5 + 5, c, 5) == a5 + 5 to an arbitrary constant. | ||
|
|
||
| define i1 @call_memrchr_ap5_c_5_eq_a(i32 %c, i64 %n) { | ||
| ; CHECK-LABEL: @call_memrchr_ap5_c_5_eq_a( | ||
| ; CHECK-NEXT: ret i1 | ||
| ; | ||
| %pap5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %qap5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 1, i32 0 | ||
| %q = call i8* @memrchr(i8* %pap5, i32 %c, i64 5) | ||
| %cmp = icmp eq i8* %q, %qap5 | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; Fold memrchr(a5 + 5, c, n) == a5 to false. | ||
|
|
||
| define i1 @fold_memrchr_ap5_c_n_eq_a(i32 %c, i64 %n) { | ||
| ; CHECK-LABEL: @fold_memrchr_ap5_c_n_eq_a( | ||
| ; CHECK-NEXT: ret i1 false | ||
| ; | ||
| %pa = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %pap5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %q = call i8* @memrchr(i8* %pap5, i32 %c, i64 %n) | ||
| %cmp = icmp eq i8* %q, %pa | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; Fold memrchr(a5 + 5, c, n) == null to true on the basis that n must | ||
| ; be zero in order for the call to be valid. | ||
|
|
||
| define i1 @fold_memrchr_ap5_c_n_eqz(i32 %c, i64 %n) { | ||
| ; CHECK-LABEL: @fold_memrchr_ap5_c_n_eqz( | ||
| ; CHECK-NEXT: ret i1 true | ||
| ; | ||
| %p = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %q = call i8* @memrchr(i8* %p, i32 %c, i64 %n) | ||
| %cmp = icmp eq i8* %q, null | ||
| ret i1 %cmp | ||
| } | ||
|
|
||
|
|
||
| ; Fold memrchr(a5 + 5, '\0', n) == null to true again on the basis that | ||
| ; n must be zero in order for the call to be valid. | ||
|
|
||
| define i1 @fold_memrchr_a_nul_n_eqz(i64 %n) { | ||
| ; CHECK-LABEL: @fold_memrchr_a_nul_n_eqz( | ||
| ; CHECK-NEXT: ret i1 true | ||
| ; | ||
| %p = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %q = call i8* @memrchr(i8* %p, i32 0, i64 %n) | ||
| %cmp = icmp eq i8* %q, null | ||
| ret i1 %cmp | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,319 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Verify that calls with arguments with pointers just past the end of | ||
| ; a string to [a subset of] library functions that expect nul-terminated | ||
| ; strings as arguments are folded to safe values. The rationale is that | ||
| ; since they are undefined and even though folding them isn't important | ||
| ; for efficiency and prevents sanitizers from detecting and reporting | ||
| ; them, sanitizers usually don't run, and transforming such invalid | ||
| ; calls to something valid is safer than letting the program run off | ||
| ; the rails. See the Safe Optimizations for Sanitizers RFC for | ||
| ; an in-depth discussion of the trade-offs: | ||
| ; https://discourse.llvm.org/t/rfc-safe-optimizations-for-sanitizers | ||
|
|
||
| declare i8* @strchr(i8*, i32) | ||
| declare i8* @strrchr(i8*, i32) | ||
| declare i32 @strcmp(i8*, i8*) | ||
| declare i32 @strncmp(i8*, i8*, i64) | ||
| declare i8* @strstr(i8*, i8*) | ||
|
|
||
| declare i8* @stpcpy(i8*, i8*) | ||
| declare i8* @strcpy(i8*, i8*) | ||
| declare i8* @stpncpy(i8*, i8*, i64) | ||
| declare i8* @strncpy(i8*, i8*, i64) | ||
|
|
||
| declare i64 @strlen(i8*) | ||
| declare i64 @strnlen(i8*, i64) | ||
|
|
||
| declare i8* @strpbrk(i8*, i8*) | ||
|
|
||
| declare i64 @strspn(i8*, i8*) | ||
| declare i64 @strcspn(i8*, i8*) | ||
|
|
||
| declare i32 @sprintf(i8*, i8*, ...) | ||
| declare i32 @snprintf(i8*, i64, i8*, ...) | ||
|
|
||
|
|
||
| @a5 = constant [5 x i8] c"%s\0045"; | ||
|
|
||
|
|
||
| ; Fold strchr(a5 + 5, '\0') to null. | ||
|
|
||
| define i8* @fold_strchr_past_end() { | ||
| ; CHECK-LABEL: @fold_strchr_past_end( | ||
| ; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0) | ||
| ; | ||
| %p = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %q = call i8* @strchr(i8* %p, i32 0) | ||
| ret i8* %q | ||
| } | ||
|
|
||
| ; Fold strcmp(a5, a5 + 5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strcmp_past_end(i32* %pcmp) { | ||
| ; CHECK-LABEL: @fold_strcmp_past_end( | ||
| ; CHECK-NEXT: store i32 1, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PC50:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PC50]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %c05 = call i32 @strcmp(i8* %p0, i8* %p5) | ||
| %pc05 = getelementptr i32, i32* %pcmp, i32 0 | ||
| store i32 %c05, i32* %pc05 | ||
|
|
||
| %c50 = call i32 @strcmp(i8* %p5, i8* %p0) | ||
| %pc50 = getelementptr i32, i32* %pcmp, i32 1 | ||
| store i32 %c50, i32* %pc50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Likewise, fold strncmp(a5, a5 + 5, 5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strncmp_past_end(i32* %pcmp) { | ||
| ; CHECK-LABEL: @fold_strncmp_past_end( | ||
| ; CHECK-NEXT: store i32 1, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PC50:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PC50]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %c05 = call i32 @strncmp(i8* %p0, i8* %p5, i64 5) | ||
| %pc05 = getelementptr i32, i32* %pcmp, i32 0 | ||
| store i32 %c05, i32* %pc05 | ||
|
|
||
| %c50 = call i32 @strncmp(i8* %p5, i8* %p0, i64 5) | ||
| %pc50 = getelementptr i32, i32* %pcmp, i32 1 | ||
| store i32 %c50, i32* %pc50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold strrchr(a5 + 5, '\0') to null. | ||
|
|
||
| define i8* @fold_strrchr_past_end(i32 %c) { | ||
| ; CHECK-LABEL: @fold_strrchr_past_end( | ||
| ; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0) | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i8* @strrchr(i8* %p5, i32 0) | ||
| ret i8* %r | ||
| } | ||
|
|
||
|
|
||
| ; Fold strstr(a5 + 5, a5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strstr_past_end(i8** %psub) { | ||
| ; CHECK-LABEL: @fold_strstr_past_end( | ||
| ; CHECK-NEXT: store i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 0, i64 0), i8** [[PSUB:%.*]], align 8 | ||
| ; CHECK-NEXT: [[PS50:%.*]] = getelementptr i8*, i8** [[PSUB]], i64 1 | ||
| ; CHECK-NEXT: store i8* null, i8** [[PS50]], align 8 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %s05 = call i8* @strstr(i8* %p0, i8* %p5) | ||
| %ps05 = getelementptr i8*, i8** %psub, i32 0 | ||
| store i8* %s05, i8** %ps05 | ||
|
|
||
| %s50 = call i8* @strstr(i8* %p5, i8* %p0) | ||
| %ps50 = getelementptr i8*, i8** %psub, i32 1 | ||
| store i8* %s50, i8** %ps50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold strlen(a5 + 5) to 0. | ||
|
|
||
| define i64 @fold_strlen_past_end() { | ||
| ; CHECK-LABEL: @fold_strlen_past_end( | ||
| ; CHECK-NEXT: ret i64 0 | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i64 @strlen(i8* %p5) | ||
| ret i64 %r | ||
| } | ||
|
|
||
|
|
||
| ; TODO: Fold stpcpy(dst, a5 + 5) to (*dst = '\0', dst). | ||
|
|
||
| define i8* @fold_stpcpy_past_end(i8* %dst) { | ||
| ; CHECK-LABEL: @fold_stpcpy_past_end( | ||
| ; CHECK-NEXT: ret i8* [[DST:%.*]] | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i8* @strcpy(i8* %dst, i8* %p5) | ||
| ret i8* %r | ||
| } | ||
|
|
||
|
|
||
| ; TODO: Fold strcpy(dst, a5 + 5) to (*dst = '\0', dst). | ||
|
|
||
| define i8* @fold_strcpy_past_end(i8* %dst) { | ||
| ; CHECK-LABEL: @fold_strcpy_past_end( | ||
| ; CHECK-NEXT: ret i8* [[DST:%.*]] | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i8* @strcpy(i8* %dst, i8* %p5) | ||
| ret i8* %r | ||
| } | ||
|
|
||
|
|
||
| ; TODO: Fold stpncpy(dst, a5 + 5, 5) to (memset(dst, 0, 5), dst + 5). | ||
|
|
||
| define i8* @fold_stpncpy_past_end(i8* %dst) { | ||
| ; CHECK-LABEL: @fold_stpncpy_past_end( | ||
| ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(5) [[DST:%.*]], i8 0, i64 5, i1 false) | ||
| ; CHECK-NEXT: ret i8* [[DST]] | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i8* @strncpy(i8* %dst, i8* %p5, i64 5) | ||
| ret i8* %r | ||
| } | ||
|
|
||
|
|
||
| ; TODO: Fold strncpy(dst, a5 + 5, 5) to memset(dst, 0, 5). | ||
|
|
||
| define i8* @fold_strncpy_past_end(i8* %dst) { | ||
| ; CHECK-LABEL: @fold_strncpy_past_end( | ||
| ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(5) [[DST:%.*]], i8 0, i64 5, i1 false) | ||
| ; CHECK-NEXT: ret i8* [[DST]] | ||
| ; | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %r = call i8* @strncpy(i8* %dst, i8* %p5, i64 5) | ||
| ret i8* %r | ||
| } | ||
|
|
||
|
|
||
| ; Fold strpbrk(a5, a5 + 5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strpbrk_past_end(i8** %psub) { | ||
| ; CHECK-LABEL: @fold_strpbrk_past_end( | ||
| ; CHECK-NEXT: store i8* null, i8** [[PSUB:%.*]], align 8 | ||
| ; CHECK-NEXT: [[PS50:%.*]] = getelementptr i8*, i8** [[PSUB]], i64 1 | ||
| ; CHECK-NEXT: store i8* null, i8** [[PS50]], align 8 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %s05 = call i8* @strpbrk(i8* %p0, i8* %p5) | ||
| %ps05 = getelementptr i8*, i8** %psub, i32 0 | ||
| store i8* %s05, i8** %ps05 | ||
|
|
||
| %s50 = call i8* @strpbrk(i8* %p5, i8* %p0) | ||
| %ps50 = getelementptr i8*, i8** %psub, i32 1 | ||
| store i8* %s50, i8** %ps50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold strspn(a5, a5 + 5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strspn_past_end(i64* %poff) { | ||
| ; CHECK-LABEL: @fold_strspn_past_end( | ||
| ; CHECK-NEXT: store i64 0, i64* [[POFF:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PO50:%.*]] = getelementptr i64, i64* [[POFF]], i64 1 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PO50]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %o05 = call i64 @strspn(i8* %p0, i8* %p5) | ||
| %po05 = getelementptr i64, i64* %poff, i32 0 | ||
| store i64 %o05, i64* %po05 | ||
|
|
||
| %o50 = call i64 @strspn(i8* %p5, i8* %p0) | ||
| %po50 = getelementptr i64, i64* %poff, i32 1 | ||
| store i64 %o50, i64* %po50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold strcspn(a5, a5 + 5) (and vice versa) to null. | ||
|
|
||
| define void @fold_strcspn_past_end(i64* %poff) { | ||
| ; CHECK-LABEL: @fold_strcspn_past_end( | ||
| ; CHECK-NEXT: store i64 2, i64* [[POFF:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PO50:%.*]] = getelementptr i64, i64* [[POFF]], i64 1 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PO50]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %o05 = call i64 @strcspn(i8* %p0, i8* %p5) | ||
| %po05 = getelementptr i64, i64* %poff, i32 0 | ||
| store i64 %o05, i64* %po05 | ||
|
|
||
| %o50 = call i64 @strcspn(i8* %p5, i8* %p0) | ||
| %po50 = getelementptr i64, i64* %poff, i32 1 | ||
| store i64 %o50, i64* %po50 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold sprintf(dst, a5 + 5) to zero, and also | ||
| ; TODO: fold sprintf(dst, "%s", a5 + 5) to zero. | ||
|
|
||
| define void @fold_sprintf_past_end(i32* %pcnt, i8* %dst) { | ||
| ; CHECK-LABEL: @fold_sprintf_past_end( | ||
| ; CHECK-NEXT: store i32 0, i32* [[PCNT:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PN05:%.*]] = getelementptr i32, i32* [[PCNT]], i64 1 | ||
| ; CHECK-NEXT: store i32 0, i32* [[PN05]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %n5_ = call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %p5) | ||
| %pn5_ = getelementptr i32, i32* %pcnt, i32 0 | ||
| store i32 %n5_, i32* %pn5_ | ||
|
|
||
| %n05 = call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %p0, i8* %p5) | ||
| %pn05 = getelementptr i32, i32* %pcnt, i32 1 | ||
| store i32 %n05, i32* %pn05 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Fold snprintf(dst, n, a5 + 5) to zero, and also | ||
| ; TODO: fold snprintf(dst, n, "%s", a5 + 5) to zero. | ||
|
|
||
| define void @fold_snprintf_past_end(i32* %pcnt, i8* %dst, i64 %n) { | ||
| ; CHECK-LABEL: @fold_snprintf_past_end( | ||
| ; CHECK-NEXT: [[N5_:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[DST:%.*]], i64 [[N:%.*]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0)) | ||
| ; CHECK-NEXT: store i32 [[N5_]], i32* [[PCNT:%.*]], align 4 | ||
| ; CHECK-NEXT: [[N05:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* [[DST]], i64 [[N]], i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a5, i64 1, i64 0)) | ||
| ; CHECK-NEXT: [[PN05:%.*]] = getelementptr i32, i32* [[PCNT]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[N05]], i32* [[PN05]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
|
|
||
| %n5_ = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %dst, i64 %n, i8* %p5) | ||
| %pn5_ = getelementptr i32, i32* %pcnt, i32 0 | ||
| store i32 %n5_, i32* %pn5_ | ||
|
|
||
| %n05 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %dst, i64 %n, i8* %p0, i8* %p5) | ||
| %pn05 = getelementptr i32, i32* %pcnt, i32 1 | ||
| store i32 %n05, i32* %pn05 | ||
|
|
||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; | ||
| ; Verify that strlen calls with unterminated constant arrays or with | ||
| ; just past-the-end pointers to strings are not folded. | ||
| ; | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
|
|
||
| declare i64 @strlen(i8*) | ||
|
|
||
| @a5 = constant [5 x i8] c"12345" | ||
| @s5 = constant [6 x i8] c"12345\00" | ||
| @z0 = constant [0 x i8] zeroinitializer | ||
| @z5 = constant [5 x i8] zeroinitializer | ||
|
|
||
|
|
||
| ; Verify that all the invalid calls below are folded. This is safer than | ||
| ; making the library calls even though it prevents sanitizers from reporting | ||
| ; the bugs. | ||
|
|
||
| define void @fold_strlen_no_nul(i64* %plen, i32 %i) { | ||
| ; CHECK-LABEL: @fold_strlen_no_nul( | ||
| ; CHECK-NEXT: store i64 5, i64* [[PLEN:%.*]], align 4 | ||
| ; CHECK-NEXT: [[PNA5_P5:%.*]] = getelementptr i64, i64* [[PLEN]], i64 1 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PNA5_P5]], align 4 | ||
| ; CHECK-NEXT: [[PNS5_P6:%.*]] = getelementptr i64, i64* [[PLEN]], i64 2 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PNS5_P6]], align 4 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[I:%.*]] to i64 | ||
| ; CHECK-NEXT: [[PA5_PI:%.*]] = getelementptr [5 x i8], [5 x i8]* @a5, i64 0, i64 [[TMP1]] | ||
| ; CHECK-NEXT: [[NA5_PI:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA5_PI]]) | ||
| ; CHECK-NEXT: [[PNA5_PI:%.*]] = getelementptr i64, i64* [[PLEN]], i64 3 | ||
| ; CHECK-NEXT: store i64 [[NA5_PI]], i64* [[PNA5_PI]], align 4 | ||
| ; CHECK-NEXT: [[PNZ0_P0:%.*]] = getelementptr i64, i64* [[PLEN]], i64 4 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PNZ0_P0]], align 4 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[I]] to i64 | ||
| ; CHECK-NEXT: [[PZ0_PI:%.*]] = getelementptr [0 x i8], [0 x i8]* @z0, i64 0, i64 [[TMP2]] | ||
| ; CHECK-NEXT: [[NZ0_PI:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PZ0_PI]]) | ||
| ; CHECK-NEXT: [[PNZ0_PI:%.*]] = getelementptr i64, i64* [[PLEN]], i64 5 | ||
| ; CHECK-NEXT: store i64 [[NZ0_PI]], i64* [[PNZ0_PI]], align 4 | ||
| ; CHECK-NEXT: [[PNZ5_P5:%.*]] = getelementptr i64, i64* [[PLEN]], i64 6 | ||
| ; CHECK-NEXT: store i64 0, i64* [[PNZ5_P5]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| ; Verify that strlen(a5) is folded to 5. | ||
| %pa0_p0 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 0 | ||
| %na5_p0 = call i64 @strlen(i8* %pa0_p0) | ||
| %pna5_p0 = getelementptr i64, i64* %plen, i64 0 | ||
| store i64 %na5_p0, i64* %pna5_p0 | ||
|
|
||
| ; Verify that strlen(a5 + 5) is folded to 0. | ||
| %pa5_p5 = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 5 | ||
| %na5_p5 = call i64 @strlen(i8* %pa5_p5) | ||
| %pna5_p5 = getelementptr i64, i64* %plen, i64 1 | ||
| store i64 %na5_p5, i64* %pna5_p5 | ||
|
|
||
| ; Verify that strlen(s5 + 6) is folded to 0. | ||
| %ps5_p6 = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 6 | ||
| %ns5_p6 = call i64 @strlen(i8* %ps5_p6) | ||
| %pns5_p6 = getelementptr i64, i64* %plen, i64 2 | ||
| store i64 %ns5_p6, i64* %pns5_p6 | ||
|
|
||
| ; TODO: Verify that strlen(a5 + i) is folded to 5 - i? It's currently | ||
| ; not folded because the variable offset makes getConstantDataArrayInfo | ||
| ; fail. | ||
| %pa5_pi = getelementptr [5 x i8], [5 x i8]* @a5, i32 0, i32 %i | ||
| %na5_pi = call i64 @strlen(i8* %pa5_pi) | ||
| %pna5_pi = getelementptr i64, i64* %plen, i64 3 | ||
| store i64 %na5_pi, i64* %pna5_pi | ||
|
|
||
| ; Verify that strlen(z0) is folded to 0. | ||
| %pz0_p0 = getelementptr [0 x i8], [0 x i8]* @z0, i32 0, i32 0 | ||
| %nz0_p0 = call i64 @strlen(i8* %pz0_p0) | ||
| %pnz0_p0 = getelementptr i64, i64* %plen, i64 4 | ||
| store i64 %nz0_p0, i64* %pnz0_p0 | ||
|
|
||
| ; TODO: Verify that strlen(z0 + i) is folded to 0. As the case above, | ||
| ; this one is not folded either because the variable offset makes | ||
| ; getConstantDataArrayInfo fail. | ||
|
|
||
| %pz0_pi = getelementptr [0 x i8], [0 x i8]* @z0, i32 0, i32 %i | ||
| %nz0_pi = call i64 @strlen(i8* %pz0_pi) | ||
| %pnz0_pi = getelementptr i64, i64* %plen, i64 5 | ||
| store i64 %nz0_pi, i64* %pnz0_pi | ||
|
|
||
| ; Verify that strlen(z5 + 5) is folded to 0. | ||
| %pz5_p5 = getelementptr [5 x i8], [5 x i8]* @z5, i32 0, i32 5 | ||
| %nz5_p5 = call i64 @strlen(i8* %pz5_p5) | ||
| %pnz5_p5 = getelementptr i64, i64* %plen, i64 6 | ||
| store i64 %nz5_p5, i64* %pnz5_p5 | ||
|
|
||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,357 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Exercise folding of strncmp calls with constant arrays and nonconstant | ||
| ; sizes. | ||
|
|
||
| declare i32 @strncmp(i8*, i8*, i64) | ||
|
|
||
| @ax = external constant [8 x i8] | ||
| @a01230123 = constant [8 x i8] c"01230123" | ||
| @b01230123 = constant [8 x i8] c"01230123" | ||
| @c01230129 = constant [8 x i8] c"01230129" | ||
| @d9123_12 = constant [7 x i8] c"9123\0012" | ||
| @e9123_34 = constant [7 x i8] c"9123\0034" | ||
|
|
||
|
|
||
| ; Exercise strncmp(A, B, N) folding of arrays with the same bytes. | ||
|
|
||
| define void @fold_strncmp_a_b_n(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_a_b_n( | ||
| ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[N:%.*]], 0 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: [[S0_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[TMP2]], i32* [[S0_1]], align 4 | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP3]] to i32 | ||
| ; CHECK-NEXT: [[S0_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 [[TMP4]], i32* [[S0_2]], align 4 | ||
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP6:%.*]] = sext i1 [[TMP5]] to i32 | ||
| ; CHECK-NEXT: [[S0_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 [[TMP6]], i32* [[S0_3]], align 4 | ||
| ; CHECK-NEXT: [[S0_4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 | ||
| ; CHECK-NEXT: store i32 0, i32* [[S0_4]], align 4 | ||
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP8:%.*]] = sext i1 [[TMP7]] to i32 | ||
| ; CHECK-NEXT: [[S0_5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 | ||
| ; CHECK-NEXT: store i32 [[TMP8]], i32* [[S0_5]], align 4 | ||
| ; CHECK-NEXT: [[TMP9:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP10:%.*]] = zext i1 [[TMP9]] to i32 | ||
| ; CHECK-NEXT: [[S5_0:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6 | ||
| ; CHECK-NEXT: store i32 [[TMP10]], i32* [[S5_0]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 0 | ||
|
|
||
| %q0 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 0 | ||
| %q1 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 1 | ||
| %q2 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 2 | ||
| %q3 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 3 | ||
| %q4 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 4 | ||
| %q5 = getelementptr [8 x i8], [8 x i8]* @b01230123, i64 0, i64 5 | ||
|
|
||
| ; Fold strncmp(a, b, n) to 0. | ||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ; Fold strncmp(a, b + 1, n) to N != 0 ? -1 : 0. | ||
| %c0_1 = call i32 @strncmp(i8* %p0, i8* %q1, i64 %n) | ||
| %s0_1 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %c0_1, i32* %s0_1 | ||
|
|
||
| ; Fold strncmp(a, b + 2, n) to N != 0 ? -1 : 0. | ||
| %c0_2 = call i32 @strncmp(i8* %p0, i8* %q2, i64 %n) | ||
| %s0_2 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %c0_2, i32* %s0_2 | ||
|
|
||
| ; Fold strncmp(a, b + 3, n) to N != 0 ? -1 : 0. | ||
| %c0_3 = call i32 @strncmp(i8* %p0, i8* %q3, i64 %n) | ||
| %s0_3 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %c0_3, i32* %s0_3 | ||
|
|
||
| ; Fold strncmp(a, b + 4, n) to 0. | ||
| %c0_4 = call i32 @strncmp(i8* %p0, i8* %q4, i64 %n) | ||
| %s0_4 = getelementptr i32, i32* %pcmp, i64 4 | ||
| store i32 %c0_4, i32* %s0_4 | ||
|
|
||
| ; Fold strncmp(a, b + 5, n) to N != 0 ? -1 : 0. | ||
| %c0_5 = call i32 @strncmp(i8* %p0, i8* %q5, i64 %n) | ||
| %s0_5 = getelementptr i32, i32* %pcmp, i64 5 | ||
| store i32 %c0_5, i32* %s0_5 | ||
|
|
||
| ; Fold strncmp(b + 5, a, n) to N != 0 ? +1 : 0. | ||
| %c5_0 = call i32 @strncmp(i8* %q5, i8* %p0, i64 %n) | ||
| %s5_0 = getelementptr i32, i32* %pcmp, i64 6 | ||
| store i32 %c5_0, i32* %s5_0 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
| ; Vefify that a strncmp() call involving a constant array with unknown | ||
| ; contents is not folded. | ||
|
|
||
| define void @call_strncmp_a_ax_n(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @call_strncmp_a_ax_n( | ||
| ; CHECK-NEXT: [[C0_0:%.*]] = call i32 @strncmp(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @a01230123, i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @ax, i64 0, i64 0), i64 [[N:%.*]]) | ||
| ; CHECK-NEXT: store i32 [[C0_0]], i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 0 | ||
| %q0 = getelementptr [8 x i8], [8 x i8]* @ax, i64 0, i64 0 | ||
|
|
||
| ; Do not fold strncmp(a, ax, n). | ||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Exercise strncmp(A, C, N) folding of arrays with the same leading bytes | ||
| ; but a difference in the trailing byte. | ||
|
|
||
| define void @fold_strncmp_a_c_n(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_a_c_n( | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[N:%.*]], 7 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: store i32 [[TMP2]], i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP3]] to i32 | ||
| ; CHECK-NEXT: [[S0_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[TMP4]], i32* [[S0_1]], align 4 | ||
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP6:%.*]] = sext i1 [[TMP5]] to i32 | ||
| ; CHECK-NEXT: [[S0_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 [[TMP6]], i32* [[S0_2]], align 4 | ||
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP8:%.*]] = sext i1 [[TMP7]] to i32 | ||
| ; CHECK-NEXT: [[S0_3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 [[TMP8]], i32* [[S0_3]], align 4 | ||
| ; CHECK-NEXT: [[TMP9:%.*]] = icmp ugt i64 [[N]], 3 | ||
| ; CHECK-NEXT: [[TMP10:%.*]] = sext i1 [[TMP9]] to i32 | ||
| ; CHECK-NEXT: [[S0_4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 | ||
| ; CHECK-NEXT: store i32 [[TMP10]], i32* [[S0_4]], align 4 | ||
| ; CHECK-NEXT: [[TMP11:%.*]] = icmp ugt i64 [[N]], 3 | ||
| ; CHECK-NEXT: [[TMP12:%.*]] = sext i1 [[TMP11]] to i32 | ||
| ; CHECK-NEXT: [[S0_5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 | ||
| ; CHECK-NEXT: store i32 [[TMP12]], i32* [[S0_5]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 0 | ||
|
|
||
| %q0 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 0 | ||
| %q1 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 1 | ||
| %q2 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 2 | ||
| %q3 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 3 | ||
| %q4 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 4 | ||
| %q5 = getelementptr [8 x i8], [8 x i8]* @c01230129, i64 0, i64 5 | ||
|
|
||
| ; Fold strncmp(a, c, n) to N > 7 ? -1 : 0. | ||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ; Fold strncmp(a, c + 1, n) to N != 0 ? -1 : 0. | ||
| %c0_1 = call i32 @strncmp(i8* %p0, i8* %q1, i64 %n) | ||
| %s0_1 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %c0_1, i32* %s0_1 | ||
|
|
||
| ; Fold strncmp(a, c + 2, n) to N != 0 ? -1 : 0. | ||
| %c0_2 = call i32 @strncmp(i8* %p0, i8* %q2, i64 %n) | ||
| %s0_2 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %c0_2, i32* %s0_2 | ||
|
|
||
| ; Fold strncmp(a, c + 3, n) to N != 0 ? -1 : 0. | ||
| %c0_3 = call i32 @strncmp(i8* %p0, i8* %q3, i64 %n) | ||
| %s0_3 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %c0_3, i32* %s0_3 | ||
|
|
||
| ; Fold strncmp(a, c + 4, n) to N > 3 ? -1 : 0. | ||
| %c0_4 = call i32 @strncmp(i8* %p0, i8* %q4, i64 %n) | ||
| %s0_4 = getelementptr i32, i32* %pcmp, i64 4 | ||
| store i32 %c0_4, i32* %s0_4 | ||
|
|
||
| ; Fold strncmp(a, c + 5, n) to N != 0 ? -1 : 0. | ||
| %c0_5 = call i32 @strncmp(i8* %p0, i8* %q4, i64 %n) | ||
| %s0_5 = getelementptr i32, i32* %pcmp, i64 5 | ||
| store i32 %c0_5, i32* %s0_5 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Exercise strncmp(A, D, N) folding of arrays of different sizes and | ||
| ; a difference in the leading byte. | ||
|
|
||
| define void @fold_strncmp_a_d_n(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_a_d_n( | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[N:%.*]], 0 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: store i32 [[TMP2]], i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP3]] to i32 | ||
| ; CHECK-NEXT: [[S0_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[TMP4]], i32* [[S0_1]], align 4 | ||
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[N]], 3 | ||
| ; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32 | ||
| ; CHECK-NEXT: [[S1_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 [[TMP6]], i32* [[S1_1]], align 4 | ||
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[N]], 2 | ||
| ; CHECK-NEXT: [[TMP8:%.*]] = zext i1 [[TMP7]] to i32 | ||
| ; CHECK-NEXT: [[S2_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 [[TMP8]], i32* [[S2_2]], align 4 | ||
| ; CHECK-NEXT: [[TMP9:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP10:%.*]] = zext i1 [[TMP9]] to i32 | ||
| ; CHECK-NEXT: [[S4_4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4 | ||
| ; CHECK-NEXT: store i32 [[TMP10]], i32* [[S4_4]], align 4 | ||
| ; CHECK-NEXT: [[TMP11:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP12:%.*]] = sext i1 [[TMP11]] to i32 | ||
| ; CHECK-NEXT: [[S4_4_2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5 | ||
| ; CHECK-NEXT: store i32 [[TMP12]], i32* [[S4_4_2]], align 4 | ||
| ; CHECK-NEXT: [[S5_5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6 | ||
| ; CHECK-NEXT: store i32 0, i32* [[S5_5]], align 4 | ||
| ; CHECK-NEXT: [[S6_6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7 | ||
| ; CHECK-NEXT: store i32 0, i32* [[S6_6]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 0 | ||
| %p1 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 1 | ||
| %p2 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 2 | ||
| %p3 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 3 | ||
| %p4 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 4 | ||
| %p5 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 5 | ||
| %p6 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 6 | ||
|
|
||
| %q0 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 0 | ||
| %q1 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 1 | ||
| %q2 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 2 | ||
| %q3 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 3 | ||
| %q4 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 4 | ||
| %q5 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 5 | ||
| %q6 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 6 | ||
|
|
||
| ; Fold strncmp(a, d, n) to N != 0 ? -1 : 0. | ||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ; Fold strncmp(a, d + 1, n) to N != 0 ? -1 : 0. | ||
| %c0_1 = call i32 @strncmp(i8* %p0, i8* %q1, i64 %n) | ||
| %s0_1 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %c0_1, i32* %s0_1 | ||
|
|
||
| ; Fold strncmp(a + 1, d + 1, n) N > 3 ? +1 : 0. | ||
| %c1_1 = call i32 @strncmp(i8* %p1, i8* %q1, i64 %n) | ||
| %s1_1 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %c1_1, i32* %s1_1 | ||
|
|
||
| ; Fold strncmp(a + 2, d + 2, n) N > 2 ? +1 : 0. | ||
| %c2_2 = call i32 @strncmp(i8* %p2, i8* %q2, i64 %n) | ||
| %s2_2 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %c2_2, i32* %s2_2 | ||
|
|
||
| ; Fold strncmp(a + 3, d + 3, n) N > 1 ? +1 : 0. | ||
| %c3_3 = call i32 @strncmp(i8* %p3, i8* %q3, i64 %n) | ||
| %s3_3 = getelementptr i32, i32* %pcmp, i64 4 | ||
| store i32 %c3_3, i32* %s3_3 | ||
|
|
||
| ; Fold strncmp(a + 4, d + 4, n) N != 0 ? +1 : 0. | ||
| %c4_4 = call i32 @strncmp(i8* %p4, i8* %q4, i64 %n) | ||
| %s4_4 = getelementptr i32, i32* %pcmp, i64 4 | ||
| store i32 %c4_4, i32* %s4_4 | ||
|
|
||
| ; Fold strncmp(d + 4, a + 4, n) N != 0 ? -1 : 0 (same as above but | ||
| ; with the array arguments reversed). | ||
| %c4_4_2 = call i32 @strncmp(i8* %q4, i8* %p4, i64 %n) | ||
| %s4_4_2 = getelementptr i32, i32* %pcmp, i64 5 | ||
| store i32 %c4_4_2, i32* %s4_4_2 | ||
|
|
||
| ; Fold strncmp(a + 5, d + 5, n) to 0. | ||
| %c5_5 = call i32 @strncmp(i8* %p5, i8* %q5, i64 %n) | ||
| %s5_5 = getelementptr i32, i32* %pcmp, i64 6 | ||
| store i32 %c5_5, i32* %s5_5 | ||
|
|
||
| ; Fold strncmp(a + 6, d + 6, n) to 0. | ||
| %c6_6 = call i32 @strncmp(i8* %p6, i8* %q6, i64 %n) | ||
| %s6_6 = getelementptr i32, i32* %pcmp, i64 7 | ||
| store i32 %c6_6, i32* %s6_6 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Exercise strncmp(A, D, N) folding of arrays with the same bytes and | ||
| ; a nonzero size. | ||
|
|
||
| define void @fold_strncmp_a_d_nz(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_a_d_nz( | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [8 x i8], [8 x i8]* @a01230123, i64 0, i64 0 | ||
| %q0 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 0 | ||
| %nz = or i64 %n, 1 | ||
|
|
||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %nz) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Exercise strncmp(D, E, N) folding of equal strings but unequal arrays. | ||
|
|
||
| define void @fold_strncmp_d_e_n(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_d_e_n( | ||
| ; CHECK-NEXT: store i32 0, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[N:%.*]], 0 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = zext i1 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: [[S0_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[TMP2]], i32* [[S0_1]], align 4 | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP3]] to i32 | ||
| ; CHECK-NEXT: [[S1_0:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 [[TMP4]], i32* [[S1_0]], align 4 | ||
| ; CHECK-NEXT: [[S1_1:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 0, i32* [[S1_1]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
|
|
||
| %p0 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 0 | ||
| %p1 = getelementptr [7 x i8], [7 x i8]* @d9123_12, i64 0, i64 1 | ||
|
|
||
| %q0 = getelementptr [7 x i8], [7 x i8]* @e9123_34, i64 0, i64 0 | ||
| %q1 = getelementptr [7 x i8], [7 x i8]* @e9123_34, i64 0, i64 1 | ||
|
|
||
| ; Fold to 0. | ||
| %c0_0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %s0_0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %c0_0, i32* %s0_0 | ||
|
|
||
| ; Fold to N ? +1 : 0. | ||
| %c0_1 = call i32 @strncmp(i8* %p0, i8* %q1, i64 %n) | ||
| %s0_1 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %c0_1, i32* %s0_1 | ||
|
|
||
| ; Fold to N ? -1 : 0. | ||
| %c1_0 = call i32 @strncmp(i8* %p1, i8* %q0, i64 %n) | ||
| %s1_0 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %c1_0, i32* %s1_0 | ||
|
|
||
| ; Fold to 0. | ||
| %c1_1 = call i32 @strncmp(i8* %p1, i8* %q1, i64 %n) | ||
| %s1_1 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %c1_1, i32* %s1_1 | ||
|
|
||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
| ; | ||
| ; Exercise folding of strncmp calls with constant arrays including both | ||
| ; negative and positive characters and both constant and nonconstant sizes. | ||
|
|
||
| declare i32 @strncmp(i8*, i8*, i64) | ||
|
|
||
| @a = constant [7 x i8] c"abcdef\7f" | ||
| @b = constant [7 x i8] c"abcdef\80" | ||
|
|
||
|
|
||
| ; Exercise strncmp(A + C, B + C, 2) folding of small arrays that differ in | ||
| ; a character with the opposite sign and a constant size. | ||
|
|
||
| define void @fold_strncmp_cst_cst(i32* %pcmp) { | ||
| ; CHECK-LABEL: @fold_strncmp_cst_cst( | ||
| ; CHECK-NEXT: store i32 -1, i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[SB5_A5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 1, i32* [[SB5_A5]], align 4 | ||
| ; CHECK-NEXT: [[SA6_B6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 -1, i32* [[SA6_B6]], align 4 | ||
| ; CHECK-NEXT: [[SB6_A6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 1, i32* [[SB6_A6]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p5 = getelementptr [7 x i8], [7 x i8]* @a, i64 0, i64 5 | ||
| %p6 = getelementptr [7 x i8], [7 x i8]* @a, i64 0, i64 6 | ||
|
|
||
| %q5 = getelementptr [7 x i8], [7 x i8]* @b, i64 0, i64 5 | ||
| %q6 = getelementptr [7 x i8], [7 x i8]* @b, i64 0, i64 6 | ||
|
|
||
| ; Fold strncmp(a + 5, b + 5, 2) to -1. | ||
| %ca5_b5 = call i32 @strncmp(i8* %p5, i8* %q5, i64 2) | ||
| %sa5_b5 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %ca5_b5, i32* %sa5_b5 | ||
|
|
||
| ; Fold strncmp(b + 5, a + 5, 2) to +1. | ||
| %cb5_a5 = call i32 @strncmp(i8* %q5, i8* %p5, i64 2) | ||
| %sb5_a5 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %cb5_a5, i32* %sb5_a5 | ||
|
|
||
| ; Fold strncmp(a + 6, b + 6, 1) to -1. | ||
| %ca6_b6 = call i32 @strncmp(i8* %p6, i8* %q6, i64 1) | ||
| %sa6_b6 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %ca6_b6, i32* %sa6_b6 | ||
|
|
||
| ; Fold strncmp(b + 6, a + 6, 1) to +1. | ||
| %cb6_a6 = call i32 @strncmp(i8* %q6, i8* %p6, i64 1) | ||
| %sb6_a6 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %cb6_a6, i32* %sb6_a6 | ||
|
|
||
| ret void | ||
| } | ||
|
|
||
|
|
||
| ; Exercise strncmp(A, B, N) folding of arrays that differ in a character | ||
| ; with the opposite sign and a variable size | ||
|
|
||
| define void @fold_strncmp_cst_var(i32* %pcmp, i64 %n) { | ||
| ; CHECK-LABEL: @fold_strncmp_cst_var( | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[N:%.*]], 6 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: store i32 [[TMP2]], i32* [[PCMP:%.*]], align 4 | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ugt i64 [[N]], 6 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 | ||
| ; CHECK-NEXT: [[SB0_A0:%.*]] = getelementptr i32, i32* [[PCMP]], i64 1 | ||
| ; CHECK-NEXT: store i32 [[TMP4]], i32* [[SB0_A0]], align 4 | ||
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP6:%.*]] = sext i1 [[TMP5]] to i32 | ||
| ; CHECK-NEXT: [[SA6_B6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2 | ||
| ; CHECK-NEXT: store i32 [[TMP6]], i32* [[SA6_B6]], align 4 | ||
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp ne i64 [[N]], 0 | ||
| ; CHECK-NEXT: [[TMP8:%.*]] = zext i1 [[TMP7]] to i32 | ||
| ; CHECK-NEXT: [[SB6_A6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3 | ||
| ; CHECK-NEXT: store i32 [[TMP8]], i32* [[SB6_A6]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %p0 = getelementptr [7 x i8], [7 x i8]* @a, i64 0, i64 0 | ||
| %p6 = getelementptr [7 x i8], [7 x i8]* @a, i64 0, i64 6 | ||
|
|
||
| %q0 = getelementptr [7 x i8], [7 x i8]* @b, i64 0, i64 0 | ||
| %q6 = getelementptr [7 x i8], [7 x i8]* @b, i64 0, i64 6 | ||
|
|
||
| ; Fold strncmp(a, b, n) to -1. | ||
| %ca0_b0 = call i32 @strncmp(i8* %p0, i8* %q0, i64 %n) | ||
| %sa0_b0 = getelementptr i32, i32* %pcmp, i64 0 | ||
| store i32 %ca0_b0, i32* %sa0_b0 | ||
|
|
||
| ; Fold strncmp(b, a, n) to +1. | ||
| %cb0_a0 = call i32 @strncmp(i8* %q0, i8* %p0, i64 %n) | ||
| %sb0_a0 = getelementptr i32, i32* %pcmp, i64 1 | ||
| store i32 %cb0_a0, i32* %sb0_a0 | ||
|
|
||
| ; Fold strncmp(a + 6, b + 6, n) to -1. | ||
| %ca6_b6 = call i32 @strncmp(i8* %p6, i8* %q6, i64 %n) | ||
| %sa6_b6 = getelementptr i32, i32* %pcmp, i64 2 | ||
| store i32 %ca6_b6, i32* %sa6_b6 | ||
|
|
||
| ; Fold strncmp(b + 6, a + 6, n) to +1. | ||
| %cb6_a6 = call i32 @strncmp(i8* %q6, i8* %p6, i64 %n) | ||
| %sb6_a6 = getelementptr i32, i32* %pcmp, i64 3 | ||
| store i32 %cb6_a6, i32* %sb6_a6 | ||
|
|
||
| ret void | ||
| } |