blob: 34dbaef2b17a063f7c05862990b40d63e872ddee [file] [edit]
; 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>
; 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>
; 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>
; 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>
; 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>
; CHECK-NEXT: CLONE ir<%pb> = getelementptr inbounds ir<%b>, vp<%index>
; CHECK-NEXT: WIDEN ir<%b1> = load ir<%pb>
; 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>
; 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>
; 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>
; 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>
; CHECK-NEXT: WIDEN ir<%inc> = add ir<%x>, ir<1>
; CHECK-NEXT: WIDEN store ir<%gep>, ir<%inc>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>
; CHECK-NEXT: WIDEN ir<%sink> = add ir<%y>, ir<2>
; CHECK-NEXT: WIDEN store ir<%gep>, ir<%sink>
; 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>
; CHECK-NEXT: WIDEN ir<%inc> = add ir<%x>, ir<1>
; CHECK-NEXT: WIDEN store ir<%gep>, ir<%inc>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>
; 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>
; 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>
; CHECK-NEXT: CLONE ir<%gep.b> = getelementptr inbounds ir<%b>, vp<%index>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.b>
; 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>
; 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>
; 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>
; 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>
; 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>
; 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>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>
; 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>
; 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>{{$}}
; 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>
; 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> (!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> (!alias.scope ![[NOALIAS]], !noalias ![[SCOPE]])
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.a> (!alias.scope ![[SCOPE]], !noalias ![[NOALIAS]])
; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y>
; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum> (!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> (!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>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep.a> (!alias.scope ![[SCOPE2]], !noalias ![[NOALIAS2]])
; CHECK-NEXT: WIDEN ir<%sum> = add ir<%x>, ir<%y>
; CHECK-NEXT: WIDEN store ir<%gep.b>, ir<%sum>
; 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>
; 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>
; 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>
; 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>
; CHECK-NEXT: WIDEN ir<%y> = load ir<%gep>
; 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>
; 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
}
!0 = !{!1}
!1 = distinct !{!1, !2, !"scope_a"}
!2 = distinct !{!2, !"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}