blob: cc90f19fe02af847ed39ceb63935ee0fccf26720 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -mtriple=x86_64-unknown-linux-gnu -passes=load-store-vectorizer,dce %s -S -o - | FileCheck %s
;
; Test that LoadStoreVectorizer handles `or disjoint` in nested add sequences
; within checkIfSafeAddSequence. Unlike or-disjoint-zext.ll which exercises the
; "first attempt" path in getConstantOffsetComplexAddrs, these tests force the
; "second attempt" through checkIfSafeAddSequence where `or disjoint` is used as
; an inner operation, exercising the PossiblyDisjointInst check in
; checkNoWrapFlags.
;
; The use of sext (not zext) in the GEP index prevents SCEV from resolving the
; pointer-level difference, forcing getConstantOffsetComplexAddrs.
target triple = "x86_64-unknown-linux-gnu"
; Pattern 1 in checkIfSafeAddSequence: x +nsw y and x +nsw (y |disj K).
; The or-disjoint is the inner operation (OtherInstrB) and checkNoWrapFlags
; is called on it via the PossiblyDisjointInst path.
define void @or_disjoint_inner(i32 %v0, i32 %v1, ptr %src, ptr %dst) {
; CHECK-LABEL: define void @or_disjoint_inner(
; CHECK-SAME: i32 [[V0:%.*]], i32 [[V1:%.*]], ptr [[SRC:%.*]], ptr [[DST:%.*]]) {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[V1]], [[V0]]
; CHECK-NEXT: [[EA:%.*]] = sext i32 [[A]] to i64
; CHECK-NEXT: [[GA:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[EA]]
; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[GA]], align 1
; CHECK-NEXT: [[LA1:%.*]] = extractelement <4 x i8> [[TMP0]], i64 0
; CHECK-NEXT: [[LB2:%.*]] = extractelement <4 x i8> [[TMP0]], i64 1
; CHECK-NEXT: [[LC3:%.*]] = extractelement <4 x i8> [[TMP0]], i64 2
; CHECK-NEXT: [[LD4:%.*]] = extractelement <4 x i8> [[TMP0]], i64 3
; CHECK-NEXT: [[R0:%.*]] = insertelement <4 x i8> poison, i8 [[LA1]], i32 0
; CHECK-NEXT: [[R1:%.*]] = insertelement <4 x i8> [[R0]], i8 [[LB2]], i32 1
; CHECK-NEXT: [[R2:%.*]] = insertelement <4 x i8> [[R1]], i8 [[LC3]], i32 2
; CHECK-NEXT: [[R3:%.*]] = insertelement <4 x i8> [[R2]], i8 [[LD4]], i32 3
; CHECK-NEXT: store <4 x i8> [[R3]], ptr [[DST]], align 4
; CHECK-NEXT: ret void
;
bb:
%a = add nsw i32 %v1, %v0
%ea = sext i32 %a to i64
%ga = getelementptr inbounds i8, ptr %src, i64 %ea
%la = load i8, ptr %ga, align 1
%step1 = or disjoint i32 %v0, 1
%b = add nsw i32 %v1, %step1
%eb = sext i32 %b to i64
%gb = getelementptr inbounds i8, ptr %src, i64 %eb
%lb = load i8, ptr %gb, align 1
%step2 = or disjoint i32 %v0, 2
%c = add nsw i32 %v1, %step2
%ec = sext i32 %c to i64
%gc = getelementptr inbounds i8, ptr %src, i64 %ec
%lc = load i8, ptr %gc, align 1
%step3 = or disjoint i32 %v0, 3
%d = add nsw i32 %v1, %step3
%ed = sext i32 %d to i64
%gd = getelementptr inbounds i8, ptr %src, i64 %ed
%ld = load i8, ptr %gd, align 1
%r0 = insertelement <4 x i8> poison, i8 %la, i32 0
%r1 = insertelement <4 x i8> %r0, i8 %lb, i32 1
%r2 = insertelement <4 x i8> %r1, i8 %lc, i32 2
%r3 = insertelement <4 x i8> %r2, i8 %ld, i32 3
store <4 x i8> %r3, ptr %dst
ret void
}
; Pattern 3 in checkIfSafeAddSequence: x +nsw (y |disj c) and
; x +nsw (y |disj (c + IdxDiff)). Both inner operations are or-disjoint,
; exercising checkNoWrapFlags on both OtherInstrA and OtherInstrB.
define void @or_disjoint_both_inner(i32 %v0, i32 %v1, ptr %src, ptr %dst) {
; CHECK-LABEL: define void @or_disjoint_both_inner(
; CHECK-SAME: i32 [[V0:%.*]], i32 [[V1:%.*]], ptr [[SRC:%.*]], ptr [[DST:%.*]]) {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[INNER_A:%.*]] = or disjoint i32 [[V0]], 4
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[V1]], [[INNER_A]]
; CHECK-NEXT: [[EA:%.*]] = sext i32 [[A]] to i64
; CHECK-NEXT: [[GA:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[EA]]
; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[GA]], align 1
; CHECK-NEXT: [[LA1:%.*]] = extractelement <4 x i8> [[TMP0]], i64 0
; CHECK-NEXT: [[LB2:%.*]] = extractelement <4 x i8> [[TMP0]], i64 1
; CHECK-NEXT: [[LC3:%.*]] = extractelement <4 x i8> [[TMP0]], i64 2
; CHECK-NEXT: [[LD4:%.*]] = extractelement <4 x i8> [[TMP0]], i64 3
; CHECK-NEXT: [[R0:%.*]] = insertelement <4 x i8> poison, i8 [[LA1]], i32 0
; CHECK-NEXT: [[R1:%.*]] = insertelement <4 x i8> [[R0]], i8 [[LB2]], i32 1
; CHECK-NEXT: [[R2:%.*]] = insertelement <4 x i8> [[R1]], i8 [[LC3]], i32 2
; CHECK-NEXT: [[R3:%.*]] = insertelement <4 x i8> [[R2]], i8 [[LD4]], i32 3
; CHECK-NEXT: store <4 x i8> [[R3]], ptr [[DST]], align 4
; CHECK-NEXT: ret void
;
bb:
%inner_a = or disjoint i32 %v0, 4
%a = add nsw i32 %v1, %inner_a
%ea = sext i32 %a to i64
%ga = getelementptr inbounds i8, ptr %src, i64 %ea
%la = load i8, ptr %ga, align 1
%inner_b = or disjoint i32 %v0, 5
%b = add nsw i32 %v1, %inner_b
%eb = sext i32 %b to i64
%gb = getelementptr inbounds i8, ptr %src, i64 %eb
%lb = load i8, ptr %gb, align 1
%inner_c = or disjoint i32 %v0, 6
%c = add nsw i32 %v1, %inner_c
%ec = sext i32 %c to i64
%gc = getelementptr inbounds i8, ptr %src, i64 %ec
%lc = load i8, ptr %gc, align 1
%inner_d = or disjoint i32 %v0, 7
%d = add nsw i32 %v1, %inner_d
%ed = sext i32 %d to i64
%gd = getelementptr inbounds i8, ptr %src, i64 %ed
%ld = load i8, ptr %gd, align 1
%r0 = insertelement <4 x i8> poison, i8 %la, i32 0
%r1 = insertelement <4 x i8> %r0, i8 %lb, i32 1
%r2 = insertelement <4 x i8> %r1, i8 %lc, i32 2
%r3 = insertelement <4 x i8> %r2, i8 %ld, i32 3
store <4 x i8> %r3, ptr %dst
ret void
}
; Negative test: plain or (not disjoint) as inner operation should NOT
; vectorize through checkIfSafeAddSequence.
define void @or_plain_inner(i32 %v0, i32 %v1, ptr %src, ptr %dst) {
; CHECK-LABEL: define void @or_plain_inner(
; CHECK-SAME: i32 [[V0:%.*]], i32 [[V1:%.*]], ptr [[SRC:%.*]], ptr [[DST:%.*]]) {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[V1]], [[V0]]
; CHECK-NEXT: [[EA:%.*]] = sext i32 [[A]] to i64
; CHECK-NEXT: [[GA:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[EA]]
; CHECK-NEXT: [[LA:%.*]] = load i8, ptr [[GA]], align 1
; CHECK-NEXT: [[STEP1:%.*]] = or i32 [[V0]], 1
; CHECK-NEXT: [[B:%.*]] = add nsw i32 [[V1]], [[STEP1]]
; CHECK-NEXT: [[EB:%.*]] = sext i32 [[B]] to i64
; CHECK-NEXT: [[GB:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[EB]]
; CHECK-NEXT: [[LB:%.*]] = load i8, ptr [[GB]], align 1
; CHECK-NEXT: [[STEP2:%.*]] = or i32 [[V0]], 2
; CHECK-NEXT: [[C:%.*]] = add nsw i32 [[V1]], [[STEP2]]
; CHECK-NEXT: [[EC:%.*]] = sext i32 [[C]] to i64
; CHECK-NEXT: [[GC:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[EC]]
; CHECK-NEXT: [[LC:%.*]] = load i8, ptr [[GC]], align 1
; CHECK-NEXT: [[STEP3:%.*]] = or i32 [[V0]], 3
; CHECK-NEXT: [[D:%.*]] = add nsw i32 [[V1]], [[STEP3]]
; CHECK-NEXT: [[ED:%.*]] = sext i32 [[D]] to i64
; CHECK-NEXT: [[GD:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 [[ED]]
; CHECK-NEXT: [[LD:%.*]] = load i8, ptr [[GD]], align 1
; CHECK-NEXT: [[R0:%.*]] = insertelement <4 x i8> poison, i8 [[LA]], i32 0
; CHECK-NEXT: [[R1:%.*]] = insertelement <4 x i8> [[R0]], i8 [[LB]], i32 1
; CHECK-NEXT: [[R2:%.*]] = insertelement <4 x i8> [[R1]], i8 [[LC]], i32 2
; CHECK-NEXT: [[R3:%.*]] = insertelement <4 x i8> [[R2]], i8 [[LD]], i32 3
; CHECK-NEXT: store <4 x i8> [[R3]], ptr [[DST]], align 4
; CHECK-NEXT: ret void
;
bb:
%a = add nsw i32 %v1, %v0
%ea = sext i32 %a to i64
%ga = getelementptr inbounds i8, ptr %src, i64 %ea
%la = load i8, ptr %ga, align 1
%step1 = or i32 %v0, 1
%b = add nsw i32 %v1, %step1
%eb = sext i32 %b to i64
%gb = getelementptr inbounds i8, ptr %src, i64 %eb
%lb = load i8, ptr %gb, align 1
%step2 = or i32 %v0, 2
%c = add nsw i32 %v1, %step2
%ec = sext i32 %c to i64
%gc = getelementptr inbounds i8, ptr %src, i64 %ec
%lc = load i8, ptr %gc, align 1
%step3 = or i32 %v0, 3
%d = add nsw i32 %v1, %step3
%ed = sext i32 %d to i64
%gd = getelementptr inbounds i8, ptr %src, i64 %ed
%ld = load i8, ptr %gd, align 1
%r0 = insertelement <4 x i8> poison, i8 %la, i32 0
%r1 = insertelement <4 x i8> %r0, i8 %lb, i32 1
%r2 = insertelement <4 x i8> %r1, i8 %lc, i32 2
%r3 = insertelement <4 x i8> %r2, i8 %ld, i32 3
store <4 x i8> %r3, ptr %dst
ret void
}