| ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --filter-out-after "middle.block" --version 6 | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 \ | |
| ; RUN: -disable-output -vplan-print-after="printFinalVPlan$" %s 2>&1 | FileCheck %s | |
| ; REQUIRES: asserts | |
| ; Tests CSE of duplicate widened loads. | |
| ; Two identical loads from the same address are CSE'd into one. | |
| define void @cse_duplicate_load(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'cse_duplicate_load' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%x> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4 | |
| %y = load i32, ptr %gep.a, align 4 | |
| %sum = add i32 %x, %y | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Three identical loads from the same address collapse to a single load. | |
| define void @cse_three_duplicate_loads(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'cse_three_duplicate_loads' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%t> = add ir<%x>, ir<%x> | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%t>, ir<%x> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4 | |
| %y = load i32, ptr %gep.a, align 4 | |
| %z = load i32, ptr %gep.a, align 4 | |
| %t = add i32 %x, %y | |
| %sum = add i32 %t, %z | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Two independent groups of duplicate loads are each CSE'd. | |
| define void @two_dup_groups(ptr noalias %a, ptr noalias %b, ptr noalias %out) { | |
| ; CHECK-LABEL: VPlan for loop in 'two_dup_groups' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%pa> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%a1> = load ir<%pa>, align 4 | |
| ; CHECK-NEXT: CLONE ir<%pb> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%b1> = load ir<%pb>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sa> = add ir<%a1>, ir<%a1> | |
| ; CHECK-NEXT: WIDEN ir<%sb> = add ir<%b1>, ir<%b1> | |
| ; CHECK-NEXT: WIDEN ir<%s> = add ir<%sa>, ir<%sb> | |
| ; CHECK-NEXT: CLONE ir<%po> = getelementptr inbounds ir<%out>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%po>, ir<%s>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %pa = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %a1 = load i32, ptr %pa, align 4 | |
| %a2 = load i32, ptr %pa, align 4 | |
| %pb = getelementptr inbounds i32, ptr %b, i64 %iv | |
| %b1 = load i32, ptr %pb, align 4 | |
| %b2 = load i32, ptr %pb, align 4 | |
| %sa = add i32 %a1, %a2 | |
| %sb = add i32 %b1, %b2 | |
| %s = add i32 %sa, %sb | |
| %po = getelementptr inbounds i32, ptr %out, i64 %iv | |
| store i32 %s, ptr %po, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; A duplicate load and the duplicate add depending on it are both CSE'd. | |
| define void @load_then_dup_add(ptr noalias %a, ptr noalias %out) { | |
| ; CHECK-LABEL: VPlan for loop in 'load_then_dup_add' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%p> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%p>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%ax> = add ir<%x>, ir<7> | |
| ; CHECK-NEXT: WIDEN ir<%m> = mul ir<%ax>, ir<%ax> | |
| ; CHECK-NEXT: CLONE ir<%po> = getelementptr inbounds ir<%out>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%po>, ir<%m>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %p = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %p, align 4 | |
| %y = load i32, ptr %p, align 4 | |
| %ax = add i32 %x, 7 | |
| %ay = add i32 %y, 7 | |
| %m = mul i32 %ax, %ay | |
| %po = getelementptr inbounds i32, ptr %out, i64 %iv | |
| store i32 %m, ptr %po, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; A store between two loads prevents CSE of the second load. | |
| define void @no_cse_across_store(ptr %a) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_across_store' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%inc> = add ir<%x>, ir<1> | |
| ; CHECK-NEXT: WIDEN store ir<%gep>, ir<%inc>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sink> = add ir<%y>, ir<2> | |
| ; CHECK-NEXT: WIDEN store ir<%gep>, ir<%sink>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 4 | |
| %inc = add i32 %x, 1 | |
| store i32 %inc, ptr %gep, align 4 | |
| %y = load i32, ptr %gep, align 4 | |
| %sink = add i32 %y, 2 | |
| %gep.s = getelementptr inbounds i32, ptr %a, i64 %iv | |
| store i32 %sink, ptr %gep.s, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; The store clobbers the first load, but the two loads after it are duplicates | |
| ; of each other and are still CSE'd. | |
| define void @cse_duplicate_loads_after_store(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'cse_duplicate_loads_after_store' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%inc> = add ir<%x>, ir<1> | |
| ; CHECK-NEXT: WIDEN store ir<%gep>, ir<%inc>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%y>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 4 | |
| %inc = add i32 %x, 1 | |
| store i32 %inc, ptr %gep, align 4 | |
| %y = load i32, ptr %gep, align 4 | |
| %z = load i32, ptr %gep, align 4 | |
| %sum = add i32 %y, %z | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Loads from different addresses are not CSE'd. | |
| define void @no_cse_different_address(ptr noalias %a, ptr noalias %b, ptr noalias %c) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_different_address' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.b>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%gep.c> = getelementptr inbounds ir<%c>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.c>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4 | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| %y = load i32, ptr %gep.b, align 4 | |
| %sum = add i32 %x, %y | |
| %gep.c = getelementptr inbounds i32, ptr %c, i64 %iv | |
| store i32 %sum, ptr %gep.c, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Loads of different scalar types are not CSE'd. | |
| define void @no_cse_different_type(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_different_type' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: vp<[[VP1:%[0-9]+]]> = SCALAR-STEPS vp<%index>, ir<1>, ir<4>, ir<1> | |
| ; CHECK-NEXT: vp<[[VP2:%[0-9]+]]> = SCALAR-STEPS vp<%index>, ir<1>, ir<4>, ir<2> | |
| ; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = SCALAR-STEPS vp<%index>, ir<1>, ir<4>, ir<3> | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: CLONE ir<%gep>.1 = getelementptr inbounds ir<%a>, vp<[[VP1]]> | |
| ; CHECK-NEXT: CLONE ir<%gep>.2 = getelementptr inbounds ir<%a>, vp<[[VP2]]> | |
| ; CHECK-NEXT: CLONE ir<%gep>.3 = getelementptr inbounds ir<%a>, vp<[[VP3]]> | |
| ; CHECK-NEXT: CLONE ir<%x> = load ir<%gep> | |
| ; CHECK-NEXT: CLONE ir<%x>.1 = load ir<%gep>.1 | |
| ; CHECK-NEXT: CLONE ir<%x>.2 = load ir<%gep>.2 | |
| ; CHECK-NEXT: CLONE ir<%x>.3 = load ir<%gep>.3 | |
| ; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = buildvector ir<%x>, ir<%x>.1, ir<%x>.2, ir<%x>.3 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>, align 8 | |
| ; CHECK-NEXT: WIDEN-CAST ir<%xe> = zext vp<[[VP4]]> to i64 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%xe>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 8 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP5:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP5]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i64, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 8 | |
| %y = load i64, ptr %gep, align 8 | |
| %xe = zext i32 %x to i64 | |
| %sum = add i64 %xe, %y | |
| %gep.b = getelementptr inbounds i64, ptr %b, i64 %iv | |
| store i64 %sum, ptr %gep.b, align 8 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; The earlier load has the stronger alignment, so the later load reuses it and | |
| ; no alignment information is lost. | |
| define void @cse_stronger_align_first(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'cse_stronger_align_first' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep>, align 8 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%x> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 8 | |
| %y = load i32, ptr %gep, align 4 | |
| %sum = add i32 %x, %y | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; The earlier load is weaker aligned, so reusing it would drop the stronger | |
| ; alignment of the second load and CSE is skipped. | |
| define void @no_cse_weaker_align_first(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_weaker_align_first' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>, align 8 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 4 | |
| %y = load i32, ptr %gep, align 8 | |
| %sum = add i32 %x, %y | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Two identical loads with different TBAA are CSE'd, keeping only common | |
| ; metadata. | |
| define void @dup_load_diff_tbaa(ptr noalias %a, ptr noalias %out) { | |
| ; CHECK-LABEL: VPlan for loop in 'dup_load_diff_tbaa' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%p> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%p>, align 4{{$}} | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%x> | |
| ; CHECK-NEXT: CLONE ir<%po> = getelementptr inbounds ir<%out>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%po>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %p = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %p, align 4, !tbaa !5 | |
| %y = load i32, ptr %p, align 4, !tbaa !9 | |
| %sum = add i32 %x, %y | |
| %po = getelementptr inbounds i32, ptr %out, i64 %iv | |
| store i32 %sum, ptr %po, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; A store between two loads prevents CSE of the second load. | |
| ; TODO: The store is proven not to alias the loaded address via scoped-noalias | |
| ; metadata, so the second load could be CSE'd here. | |
| define void @no_cse_across_noalias_store(ptr %a, ptr %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_across_noalias_store' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 (!alias.scope ![[SCOPE:[0-9]+]], !noalias ![[NOALIAS:[0-9]+]]) | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%x>, align 4 (!alias.scope ![[NOALIAS]], !noalias ![[SCOPE]]) | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.a>, align 4 (!alias.scope ![[SCOPE]], !noalias ![[NOALIAS]]) | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 (!alias.scope ![[NOALIAS]], !noalias ![[SCOPE]]) | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4, !alias.scope !0, !noalias !3 | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %x, ptr %gep.b, align 4, !alias.scope !3, !noalias !0 | |
| %y = load i32, ptr %gep.a, align 4, !alias.scope !0, !noalias !3 | |
| %sum = add i32 %x, %y | |
| store i32 %sum, ptr %gep.b, align 4, !alias.scope !3, !noalias !0 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; A store without alias metadata cannot be proven not to alias the loaded | |
| ; address, so the second load is not CSE'd. | |
| define void @no_cse_across_store_without_scopes(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'no_cse_across_store_without_scopes' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 (!alias.scope ![[SCOPE2:[0-9]+]], !noalias ![[NOALIAS2:[0-9]+]]) | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%x>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.a>, align 4 (!alias.scope ![[SCOPE2]], !noalias ![[NOALIAS2]]) | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4, !alias.scope !0, !noalias !3 | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %x, ptr %gep.b, align 4 | |
| %y = load i32, ptr %gep.a, align 4, !alias.scope !0, !noalias !3 | |
| %sum = add i32 %x, %y | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Loads separated by a replicate region are not CSE'd. | |
| define void @dup_load_across_replicate_region(ptr noalias %a, ptr noalias %b, ptr noalias %out) { | |
| ; CHECK-LABEL: VPlan for loop in 'dup_load_across_replicate_region' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, pred.load.continue ] | |
| ; CHECK-NEXT: CLONE ir<%p> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%p>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%c> = icmp sgt ir<%x>, ir<0> | |
| ; CHECK-NEXT: WIDEN-CAST ir<%idx> = sext ir<%x> to i64 | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = extractelement ir<%c>, ir<0> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): pred.load.if, pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.if: | |
| ; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = extractelement ir<%idx>, ir<0> | |
| ; CHECK-NEXT: CLONE ir<%gep2> = getelementptr inbounds ir<%b>, vp<[[VP3]]> | |
| ; CHECK-NEXT: CLONE ir<%ld> = load ir<%gep2> | |
| ; CHECK-NEXT: EMIT vp<[[VP4:%[0-9]+]]> = insertelement ir<poison>, ir<%ld>, ir<0> | |
| ; CHECK-NEXT: Successor(s): pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.continue: | |
| ; CHECK-NEXT: WIDEN-PHI vp<[[VP5:%[0-9]+]]> = phi [ ir<poison>, vector.body ], [ vp<[[VP4]]>, pred.load.if ] | |
| ; CHECK-NEXT: EMIT vp<[[VP6:%[0-9]+]]> = extractelement ir<%c>, ir<1> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP6]]> | |
| ; CHECK-NEXT: Successor(s): pred.load.if, pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.if: | |
| ; CHECK-NEXT: EMIT vp<[[VP8:%[0-9]+]]> = extractelement ir<%idx>, ir<1> | |
| ; CHECK-NEXT: CLONE ir<%gep2>.1 = getelementptr inbounds ir<%b>, vp<[[VP8]]> | |
| ; CHECK-NEXT: CLONE ir<%ld>.1 = load ir<%gep2>.1 | |
| ; CHECK-NEXT: EMIT vp<[[VP9:%[0-9]+]]> = insertelement vp<[[VP5]]>, ir<%ld>.1, ir<1> | |
| ; CHECK-NEXT: Successor(s): pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.continue: | |
| ; CHECK-NEXT: WIDEN-PHI vp<[[VP10:%[0-9]+]]> = phi [ vp<[[VP5]]>, pred.load.continue ], [ vp<[[VP9]]>, pred.load.if ] | |
| ; CHECK-NEXT: EMIT vp<[[VP11:%[0-9]+]]> = extractelement ir<%c>, ir<2> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP11]]> | |
| ; CHECK-NEXT: Successor(s): pred.load.if, pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.if: | |
| ; CHECK-NEXT: EMIT vp<[[VP13:%[0-9]+]]> = extractelement ir<%idx>, ir<2> | |
| ; CHECK-NEXT: CLONE ir<%gep2>.2 = getelementptr inbounds ir<%b>, vp<[[VP13]]> | |
| ; CHECK-NEXT: CLONE ir<%ld>.2 = load ir<%gep2>.2 | |
| ; CHECK-NEXT: EMIT vp<[[VP14:%[0-9]+]]> = insertelement vp<[[VP10]]>, ir<%ld>.2, ir<2> | |
| ; CHECK-NEXT: Successor(s): pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.continue: | |
| ; CHECK-NEXT: WIDEN-PHI vp<[[VP15:%[0-9]+]]> = phi [ vp<[[VP10]]>, pred.load.continue ], [ vp<[[VP14]]>, pred.load.if ] | |
| ; CHECK-NEXT: EMIT vp<[[VP16:%[0-9]+]]> = extractelement ir<%c>, ir<3> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP16]]> | |
| ; CHECK-NEXT: Successor(s): pred.load.if, pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.if: | |
| ; CHECK-NEXT: EMIT vp<[[VP18:%[0-9]+]]> = extractelement ir<%idx>, ir<3> | |
| ; CHECK-NEXT: CLONE ir<%gep2>.3 = getelementptr inbounds ir<%b>, vp<[[VP18]]> | |
| ; CHECK-NEXT: CLONE ir<%ld>.3 = load ir<%gep2>.3 | |
| ; CHECK-NEXT: EMIT vp<[[VP19:%[0-9]+]]> = insertelement vp<[[VP15]]>, ir<%ld>.3, ir<3> | |
| ; CHECK-NEXT: Successor(s): pred.load.continue | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: pred.load.continue: | |
| ; CHECK-NEXT: WIDEN-PHI vp<[[VP20:%[0-9]+]]> = phi [ vp<[[VP15]]>, pred.load.continue ], [ vp<[[VP19]]>, pred.load.if ] | |
| ; CHECK-NEXT: EMIT vp<%predphi> = select ir<%c>, vp<[[VP20]]>, ir<0> | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%p>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add vp<%predphi>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%po> = getelementptr inbounds ir<%out>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%po>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP21:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP21]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %cont ] | |
| %p = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %p, align 4 | |
| %c = icmp sgt i32 %x, 0 | |
| br i1 %c, label %then, label %cont | |
| then: | |
| %idx = sext i32 %x to i64 | |
| %gep2 = getelementptr inbounds i32, ptr %b, i64 %idx | |
| %ld = load i32, ptr %gep2, align 4 | |
| br label %cont | |
| cont: | |
| %v = phi i32 [ %ld, %then ], [ 0, %loop ] | |
| %y = load i32, ptr %p, align 4 | |
| %sum = add i32 %v, %y | |
| %po = getelementptr inbounds i32, ptr %out, i64 %iv | |
| store i32 %sum, ptr %po, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; The first load cannot be reused by the stronger aligned second load, but the | |
| ; second one becomes the candidate for the third load, which reuses it. | |
| define void @cse_after_weaker_align_first(ptr noalias %a, ptr noalias %b) { | |
| ; CHECK-LABEL: VPlan for loop in 'cse_after_weaker_align_first' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep>, align 4 | |
| ; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>, align 8 | |
| ; CHECK-NEXT: WIDEN ir<%s1> = add ir<%x>, ir<%y> | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%s1>, ir<%y> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP1:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP1]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep, align 4 | |
| %y = load i32, ptr %gep, align 8 | |
| %z = load i32, ptr %gep, align 8 | |
| %s1 = add i32 %x, %y | |
| %sum = add i32 %s1, %z | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv | |
| store i32 %sum, ptr %gep.b, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| ; Duplicate loads separated by a reverse load. | |
| define void @dup_load_across_reverse_load(ptr noalias %a, ptr noalias %b, ptr noalias %out) { | |
| ; CHECK-LABEL: VPlan for loop in 'dup_load_across_reverse_load' | |
| ; CHECK: VPlan 'Final VPlan for VF={4},UF={1}' { | |
| ; CHECK-NEXT: Live-in ir<1024> = vector-trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): vector.body | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.body: | |
| ; CHECK-NEXT: EMIT-SCALAR vp<%index> = phi [ ir<0>, vector.ph ], [ vp<%index.next>, vector.body ] | |
| ; CHECK-NEXT: CLONE ir<%gep.a> = getelementptr inbounds ir<%a>, vp<%index> | |
| ; CHECK-NEXT: WIDEN ir<%x> = load ir<%gep.a>, align 4 | |
| ; CHECK-NEXT: CLONE ir<%rev.iv> = sub ir<1023>, vp<%index> | |
| ; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, ir<%rev.iv> | |
| ; CHECK-NEXT: vp<[[VP1:%[0-9]+]]> = vector-end-pointer inbounds i32, ir<%gep.b>, ir<4>, ir<-3> | |
| ; CHECK-NEXT: WIDEN ir<%r> = load vp<[[VP1]]>, align 4 | |
| ; CHECK-NEXT: EMIT vp<[[VP2:%[0-9]+]]> = reverse ir<%r> | |
| ; CHECK-NEXT: WIDEN ir<%s1> = add ir<%x>, vp<[[VP2]]> | |
| ; CHECK-NEXT: WIDEN ir<%sum> = add ir<%s1>, ir<%x> | |
| ; CHECK-NEXT: CLONE ir<%gep.out> = getelementptr inbounds ir<%out>, vp<%index> | |
| ; CHECK-NEXT: WIDEN store ir<%gep.out>, ir<%sum>, align 4 | |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<%index>, ir<4> | |
| ; CHECK-NEXT: EMIT vp<[[VP3:%[0-9]+]]> = icmp eq vp<%index.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond vp<[[VP3]]> | |
| ; CHECK-NEXT: Successor(s): middle.block, vector.body | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv | |
| %x = load i32, ptr %gep.a, align 4 | |
| %rev.iv = sub i64 1023, %iv | |
| %gep.b = getelementptr inbounds i32, ptr %b, i64 %rev.iv | |
| %r = load i32, ptr %gep.b, align 4 | |
| %y = load i32, ptr %gep.a, align 4 | |
| %s1 = add i32 %x, %r | |
| %sum = add i32 %s1, %y | |
| %gep.out = getelementptr inbounds i32, ptr %out, i64 %iv | |
| store i32 %sum, ptr %gep.out, align 4 | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| !0 = !{!1} | |
| !1 = distinct !{!1, !2, !"scope_a"} | |
| !2 = distinct !{!2, i1 false, !"domain"} | |
| !3 = !{!4} | |
| !4 = distinct !{!4, !2, !"scope_b"} | |
| !5 = !{!6, !6, i64 0} | |
| !6 = !{!"int", !7, i64 0} | |
| !7 = !{!"omnipotent char", !8, i64 0} | |
| !8 = !{!"Simple C/C++ TBAA"} | |
| !9 = !{!10, !10, i64 0} | |
| !10 = !{!"float", !7, i64 0} |