Add tests exercising the future enancement of folding library function calls with arguments involving subobjects such as elements of arrays or struct members.
164 lines
9.4 KiB
LLVM
164 lines
9.4 KiB
LLVM
; 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: [[CMP2:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A:%.*]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 2)
|
|
; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
|
|
; CHECK-NEXT: store i32 [[CMP2]], i32* [[PCMP2]], align 4
|
|
; CHECK-NEXT: [[CMP3:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 3)
|
|
; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
|
|
; CHECK-NEXT: store i32 [[CMP3]], i32* [[PCMP3]], align 4
|
|
; CHECK-NEXT: [[CMP4:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 4)
|
|
; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
|
|
; CHECK-NEXT: store i32 [[CMP4]], i32* [[PCMP4]], align 4
|
|
; CHECK-NEXT: [[CMP5:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 5)
|
|
; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
|
|
; CHECK-NEXT: store i32 [[CMP5]], i32* [[PCMP5]], align 4
|
|
; CHECK-NEXT: [[CMP6:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 6)
|
|
; CHECK-NEXT: [[PCMP6:%.*]] = getelementptr i32, i32* [[PCMP]], i64 6
|
|
; CHECK-NEXT: store i32 [[CMP6]], i32* [[PCMP6]], align 4
|
|
; CHECK-NEXT: [[CMP7:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 7)
|
|
; CHECK-NEXT: [[PCMP7:%.*]] = getelementptr i32, i32* [[PCMP]], i64 7
|
|
; CHECK-NEXT: store i32 [[CMP7]], i32* [[PCMP7]], align 4
|
|
; CHECK-NEXT: [[CMP8:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 8)
|
|
; CHECK-NEXT: [[PCMP8:%.*]] = getelementptr i32, i32* [[PCMP]], i64 8
|
|
; CHECK-NEXT: store i32 [[CMP8]], i32* [[PCMP8]], align 4
|
|
; CHECK-NEXT: [[CMP9:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 0), i64 9)
|
|
; CHECK-NEXT: [[PCMP9:%.*]] = getelementptr i32, i32* [[PCMP]], i64 9
|
|
; CHECK-NEXT: store i32 [[CMP9]], 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: [[CMP2:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A:%.*]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 2)
|
|
; CHECK-NEXT: [[PCMP2:%.*]] = getelementptr i32, i32* [[PCMP]], i64 2
|
|
; CHECK-NEXT: store i32 [[CMP2]], i32* [[PCMP2]], align 4
|
|
; CHECK-NEXT: [[CMP3:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 3)
|
|
; CHECK-NEXT: [[PCMP3:%.*]] = getelementptr i32, i32* [[PCMP]], i64 3
|
|
; CHECK-NEXT: store i32 [[CMP3]], i32* [[PCMP3]], align 4
|
|
; CHECK-NEXT: [[CMP4:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 4)
|
|
; CHECK-NEXT: [[PCMP4:%.*]] = getelementptr i32, i32* [[PCMP]], i64 4
|
|
; CHECK-NEXT: store i32 [[CMP4]], i32* [[PCMP4]], align 4
|
|
; CHECK-NEXT: [[CMP5:%.*]] = call i32 @strncmp(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 1, i64 3), i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A]], %struct.A* @a, i64 0, i32 0, i64 0), i64 5)
|
|
; CHECK-NEXT: [[PCMP5:%.*]] = getelementptr i32, i32* [[PCMP]], i64 5
|
|
; CHECK-NEXT: store i32 [[CMP5]], 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
|
|
}
|