; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that strlen calls with members of constant structs are folded.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; struct A_a4 { char a[4]; };
%struct.A_a4 = type { [4 x i8] }
; struct A_a4_a5 { char a[4], b[5]; };
%struct.A_a4_a5 = type { [4 x i8], [5 x i8] }
; struct A_a4_i32_a5 { char a[4]; int32_t i; char b[5]; };
%struct.A_a4_i32_a5 = type { [4 x i8], i32, [5 x i8] }
@a_s3 = constant %struct.A_a4 { [4 x i8 ] c"123\00" }
@a_s3_s4 = constant %struct.A_a4_a5 { [4 x i8 ] c"123\00", [5 x i8] c"1234\00" }
@a_s3_i32_s4 = constant %struct.A_a4_i32_a5 { [4 x i8 ] c"123\00", i32 -1, [5 x i8] c"1234\00" }
; Structs with flexible array members.
@ax_s3 = constant { i8, [4 x i8] } { i8 3, [4 x i8] c"123\00" }
@ax_s5 = constant { i16, [6 x i8] } { i16 5, [6 x i8] c"12345\00" }
@ax_s7 = constant { i32, i32, [8 x i8] } { i32 7, i32 0, [8 x i8] c"1234567\00" }
@ax = external global [0 x i64]
declare i64 @strlen(ptr)
; Fold strlen(a_s3.a) to 3.
define i64 @fold_strlen_a_S3_to_3() {
; CHECK-LABEL: @fold_strlen_a_S3_to_3(
; CHECK-NEXT: ret i64 3
;
%len = call i64 @strlen(ptr @a_s3)
ret i64 %len
}
; Fold strlen(&a_s3.a[1]) to 2.
define i64 @fold_strlen_a_S3_p1_to_2() {
; CHECK-LABEL: @fold_strlen_a_S3_p1_to_2(
; CHECK-NEXT: ret i64 2
;
%ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 1
%len = call i64 @strlen(ptr %ptr)
ret i64 %len
}
; Fold strlen(&a_s3.a[2]) to 1.
define i64 @fold_strlen_a_S3_p2_to_1() {
; CHECK-LABEL: @fold_strlen_a_S3_p2_to_1(
; CHECK-NEXT: ret i64 1
;
%ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 2
%len = call i64 @strlen(ptr %ptr)
ret i64 %len
}
; Fold strlen(&a_s3.a[3]) to 0.
define i64 @fold_strlen_a_S3_p3_to_0() {
; CHECK-LABEL: @fold_strlen_a_S3_p3_to_0(
; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr %struct.A_a4, ptr @a_s3, i32 0, i32 0, i32 3
%len = call i64 @strlen(ptr %ptr)
ret i64 %len
}
; Fold strlen(a_s3_s4.a) to 3.
define i64 @fold_strlen_a_S3_s4_to_3() {
; CHECK-LABEL: @fold_strlen_a_S3_s4_to_3(
; CHECK-NEXT: ret i64 3
;
%len = call i64 @strlen(ptr @a_s3_s4)
ret i64 %len
}
; Fold strlen(&a_s3_s4.a[2]) to 1.
define i64 @fold_strlen_a_S3_p2_s4_to_1() {
; CHECK-LABEL: @fold_strlen_a_S3_p2_s4_to_1(
; CHECK-NEXT: ret i64 1
;
%ptr = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 2
%len = call i64 @strlen(ptr %ptr)
ret i64 %len
}
; Fold strlen(a_s3_s4.b) to 4.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_S4_to_4() {
; CHECK-LABEL: @fold_strlen_a_s3_S4_to_4(
; CHECK-NEXT: store i64 4, ptr @ax, align 4
; CHECK-NEXT: store i64 4, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 4
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 1, i32 0
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(&a_s3_s4.b[1]) to 3.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_S4_p1_to_3() {
; CHECK-LABEL: @fold_strlen_a_s3_S4_p1_to_3(
; CHECK-NEXT: store i64 3, ptr @ax, align 4
; CHECK-NEXT: store i64 3, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 0, i32 5
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_a5, ptr @a_s3_s4, i32 0, i32 1, i32 1
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(a_s3_i32_s4.b) to 4.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_i32_S4_to_4() {
; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_to_4(
; CHECK-NEXT: store i64 4, ptr @ax, align 4
; CHECK-NEXT: store i64 4, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 8
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 0
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(&a_s3_i32_s4.b[1]) to 3.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_i32_S4_p1_to_3() {
; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p1_to_3(
; CHECK-NEXT: store i64 3, ptr @ax, align 4
; CHECK-NEXT: store i64 3, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 9
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 0
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(&a_s3_i32_s4.b[2]) to 2.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_i32_S4_p2_to_2() {
; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p2_to_2(
; CHECK-NEXT: store i64 2, ptr @ax, align 4
; CHECK-NEXT: store i64 2, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 10
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 2
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(&a_s3_i32_s4.b[3]) to 1.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_i32_S4_p3_to_1() {
; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p3_to_1(
; CHECK-NEXT: store i64 1, ptr @ax, align 4
; CHECK-NEXT: store i64 1, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 11
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 3
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(&a_s3_i32_s4.b[4]) to 0.
; Exercise both variants of the GEP index.
define void @fold_strlen_a_s3_i32_S4_p4_to_0() {
; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p4_to_0(
; CHECK-NEXT: store i64 0, ptr @ax, align 4
; CHECK-NEXT: store i64 0, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: ret void
;
%p1 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 0, i32 12
%len1 = call i64 @strlen(ptr %p1)
store i64 %len1, ptr @ax
%p2 = getelementptr %struct.A_a4_i32_a5, ptr @a_s3_i32_s4, i32 0, i32 2, i32 4
%len2 = call i64 @strlen(ptr %p2)
%pax1 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len1, ptr %pax1
ret void
}
; Fold strlen(ax_sN.a) of an constant initialized flexible array member
; to N for N in { 3, 5, 7 }.
define void @fold_strlen_ax_s() {
; CHECK-LABEL: @fold_strlen_ax_s(
; CHECK-NEXT: store i64 3, ptr @ax, align 4
; CHECK-NEXT: store i64 5, ptr getelementptr inbounds (i8, ptr @ax, i64 8), align 4
; CHECK-NEXT: store i64 7, ptr getelementptr inbounds (i8, ptr @ax, i64 16), align 4
; CHECK-NEXT: ret void
;
%pax_s3 = getelementptr { i8, [4 x i8] }, ptr @ax_s3, i64 0, i32 1, i64 0
%len3 = call i64 @strlen(ptr %pax_s3)
store i64 %len3, ptr @ax
%pax_s5 = getelementptr { i16, [6 x i8] }, ptr @ax_s5, i64 0, i32 1, i64 0
%len5 = call i64 @strlen(ptr %pax_s5)
%pax2 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 1
store i64 %len5, ptr %pax2
%pax_s7 = getelementptr { i32, i32, [8 x i8] }, ptr @ax_s7, i64 0, i32 2, i64 0
%len7 = call i64 @strlen(ptr %pax_s7)
%pax3 = getelementptr inbounds [0 x i64], ptr @ax, i64 0, i64 2
store i64 %len7, ptr %pax3
ret void
}