| ; 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 |
| } |