blob: a7762a0bb9a8174c247471fc52452d0ca0c94ca5 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes=licm -S < %s | FileCheck %s
define <16 x i1> @iss195497(ptr %1, <16 x ptr> %2, ptr %store, ptr %scevgep90, <2 x ptr> %17, <4 x ptr> %18, <8 x ptr> %19, <2 x ptr> %25, <4 x ptr> %26, <8 x ptr> %27) {
; CHECK-LABEL: define <16 x i1> @iss195497(
; CHECK-SAME: ptr [[TMP0:%.*]], <16 x ptr> [[TMP1:%.*]], ptr [[STORE:%.*]], ptr [[SCEVGEP90:%.*]], <2 x ptr> [[TMP2:%.*]], <4 x ptr> [[TMP3:%.*]], <8 x ptr> [[TMP4:%.*]], <2 x ptr> [[TMP5:%.*]], <4 x ptr> [[TMP6:%.*]], <8 x ptr> [[TMP7:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <8 x ptr> [[TMP7]], <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP9:%.*]] = shufflevector <4 x ptr> [[TMP6]], <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP10:%.*]] = shufflevector <2 x ptr> [[TMP5]], <2 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP11:%.*]] = shufflevector <2 x ptr> [[TMP2]], <2 x ptr> poison, <16 x i32> <i32 poison, i32 poison, i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <8 x ptr> [[TMP4]], <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <4 x ptr> [[TMP3]], <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP14:%.*]] = insertelement <16 x ptr> poison, ptr [[SCEVGEP90]], i64 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[CNT:%.*]] = phi i64 [ [[CNT_NEW:%.*]], %[[LOOP]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[SCEVGEP89:%.*]] = getelementptr i8, ptr [[TMP0]], i64 [[CNT]]
; CHECK-NEXT: [[TMP15:%.*]] = insertelement <16 x ptr> [[TMP14]], ptr [[SCEVGEP89]], i64 0
; CHECK-NEXT: [[TMP16:%.*]] = shufflevector <16 x ptr> [[TMP15]], <16 x ptr> [[TMP8]], <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
; CHECK-NEXT: [[TMP17:%.*]] = shufflevector <16 x ptr> [[TMP16]], <16 x ptr> [[TMP9]], <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <16 x ptr> [[TMP17]], <16 x ptr> [[TMP10]], <16 x i32> <i32 0, i32 1, i32 16, i32 17, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
; CHECK-NEXT: [[TMP19:%.*]] = icmp ult <16 x ptr> [[TMP1]], [[TMP18]]
; CHECK-NEXT: [[STORE_GEP:%.*]] = getelementptr <16 x i1>, ptr [[STORE]], i64 [[CNT]]
; CHECK-NEXT: store volatile <16 x i1> [[TMP19]], ptr [[STORE_GEP]], align 2
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[CNT]], 100
; CHECK-NEXT: [[CNT_NEW]] = add i64 [[CNT]], 1
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi <16 x i1> [ [[TMP19]], %[[LOOP]] ]
; CHECK-NEXT: ret <16 x i1> [[DOTLCSSA]]
;
entry:
%30 = shufflevector <8 x ptr> %27, <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
%31 = shufflevector <4 x ptr> %26, <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
%32 = shufflevector <2 x ptr> %25, <2 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
%33 = shufflevector <2 x ptr> %17, <2 x ptr> poison, <16 x i32> <i32 poison, i32 poison, i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
%34 = shufflevector <8 x ptr> %19, <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
%35 = shufflevector <4 x ptr> %18, <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
br label %loop
loop:
%cnt = phi i64 [ %cnt_new, %loop ], [ 0, %entry ]
%scevgep89 = getelementptr i8, ptr %1, i64 %cnt
%92 = insertelement <16 x ptr> poison, ptr %scevgep89, i64 0
%93 = insertelement <16 x ptr> %92, ptr %scevgep90, i64 1
%94 = shufflevector <16 x ptr> %93, <16 x ptr> %30, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
%95 = shufflevector <16 x ptr> %94, <16 x ptr> %31, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
%96 = shufflevector <16 x ptr> %95, <16 x ptr> %32, <16 x i32> <i32 0, i32 1, i32 16, i32 17, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
%97 = icmp ult <16 x ptr> %2, %96
%store.gep = getelementptr <16 x i1>, ptr %store, i64 %cnt
store volatile <16 x i1> %97, ptr %store.gep
%done = icmp eq i64 %cnt, 100
%cnt_new = add i64 %cnt, 1
br i1 %done, label %exit, label %loop
exit:
ret <16 x i1> %97
}
; Basic positive case: simple 4xi32, invariant inserted at lane 1 over variant at lane 0.
; The inner insertelement (lane 0, variant) should be hoisted.
define <4 x i32> @hoist_simple_swap(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @hoist_simple_swap(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Positive: wide constant index type should not crash and should still hoist/swap.
define <4 x i32> @hoist_simple_swap_wide_index_ty(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @hoist_simple_swap_wide_index_ty(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i128 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
; CHECK-NEXT: [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT]], i128 0
; CHECK-NEXT: store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i128 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i128 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Positive: The initial vector is invariant
define <4 x i32> @hoist_simple_swap_basevec(ptr %base, i32 %inv, i32 %n, <4 x i32> %basevec) {
; CHECK-LABEL: define <4 x i32> @hoist_simple_swap_basevec(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]], <4 x i32> [[BASEVEC:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> [[BASEVEC]], i32 [[INV]], i32 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> %basevec, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Positive: Have to jump through multiple insert vectors
define <4 x i32> @hoist_multiple_variants(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @hoist_multiple_variants(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 2
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 1
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%inner2 = insertelement <4 x i32> %inner, i32 %variant, i32 1
%outer = insertelement <4 x i32> %inner2, i32 %inv, i32 2
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Positive: Multiple invariant inserts
define <4 x i32> @hoist_multiple_invariants(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @hoist_multiple_invariants(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 1
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 2
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[OUTER2_LE:%.*]] = insertelement <4 x i32> [[OUTER]], i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: store <4 x i32> [[OUTER2_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER2_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER2_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER2_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
%outer2 = insertelement <4 x i32> %outer, i32 %inv, i32 2
store <4 x i32> %outer2, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer2
}
define <4 x i32> @no_hoist_variant_basevec(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_variant_basevec(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[BASEVEC_LE:%.*]] = load <4 x i32>, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> [[BASEVEC_LE]], i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 1
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%basevec = load <4 x i32>, ptr %idx, align 4
%inner = insertelement <4 x i32> %basevec, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: outer index is not a constant — no hoist.
define <4 x i32> @no_hoist_nonconstant_outer_idx(ptr %base, i32 %inv, i32 %vidx, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_nonconstant_outer_idx(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[VIDX:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 [[VIDX]]
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 %vidx
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: inner index is not a constant — no hoist.
define <4 x i32> @no_hoist_nonconstant_inner_idx(ptr %base, i32 %inv, i32 %vidx, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_nonconstant_inner_idx(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[VIDX:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 [[VIDX]]
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 1
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 %vidx
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: outer element is loop-variant — no hoist.
define <4 x i32> @no_hoist_variant_outer_elt(ptr %base, ptr %base2, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_variant_outer_elt(
; CHECK-SAME: ptr [[BASE:%.*]], ptr [[BASE2:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA1]]
; CHECK-NEXT: [[IDX2_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE2]], i32 [[IV_LCSSA1]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[VARIANT2_LE:%.*]] = load i32, ptr [[IDX2_LE]], align 4
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[VARIANT2_LE]], i32 1
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA1]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA1]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%idx2 = getelementptr inbounds i32, ptr %base2, i32 %iv
%variant = load i32, ptr %idx, align 4
%variant2 = load i32, ptr %idx2, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %variant2, i32 1
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: inner has multiple uses — no hoist.
define <4 x i32> @no_hoist_inner_multiuse(ptr %base, i32 %inv, ptr %store, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_inner_multiuse(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], ptr [[STORE:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
; CHECK-NEXT: [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT]], i32 0
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 1
; CHECK-NEXT: store volatile <4 x i32> [[INNER]], ptr [[STORE]], align 16
; CHECK-NEXT: store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LE:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LE]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
store volatile <4 x i32> %inner, ptr %store
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: inner and outer use the same index — no hoist.
define <4 x i32> @no_hoist_same_index(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_same_index(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
; CHECK-NEXT: [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
; CHECK-NEXT: [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
; CHECK-NEXT: [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 0
; CHECK-NEXT: store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 0
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: outer index is out-of-range constant — no hoist/swap.
define <4 x i32> @no_hoist_out_of_range_outer_idx(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_out_of_range_outer_idx(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
; CHECK-NEXT: [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT]], i32 0
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 7
; CHECK-NEXT: store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv, i32 7
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Negative: inner element is loop-invariant — nothing to swap, no hoist.
define <4 x i32> @no_hoist_inner_invariant_elt(ptr %base, i32 %inv1, i32 %inv2, i32 %n) {
; CHECK-LABEL: define <4 x i32> @no_hoist_inner_invariant_elt(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV1:%.*]], i32 [[INV2:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV1]], i32 0
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV2]], i32 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
; CHECK-NEXT: store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LE:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
; CHECK-NEXT: ret <4 x i32> [[OUTER_LE]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%inner = insertelement <4 x i32> poison, i32 %inv1, i32 0
%outer = insertelement <4 x i32> %inner, i32 %inv2, i32 1
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
store <4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <4 x i32> %outer
}
; Basic positive case with scalable vectors
define <vscale x 4 x i32> @hoist_scalable_swap(ptr %base, i32 %inv, i32 %n) {
; CHECK-LABEL: define <vscale x 4 x i32> @hoist_scalable_swap(
; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[OUTER:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[INV]], i32 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
; CHECK-NEXT: [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
; CHECK-NEXT: [[INNER:%.*]] = insertelement <vscale x 4 x i32> [[OUTER]], i32 [[VARIANT]], i32 0
; CHECK-NEXT: store <vscale x 4 x i32> [[INNER]], ptr [[IDX]], align 16
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[OUTER_LCSSA:%.*]] = phi <vscale x 4 x i32> [ [[INNER]], %[[LOOP]] ]
; CHECK-NEXT: ret <vscale x 4 x i32> [[OUTER_LCSSA]]
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
%idx = getelementptr inbounds i32, ptr %base, i32 %iv
%variant = load i32, ptr %idx, align 4
%inner = insertelement <vscale x 4 x i32> poison, i32 %variant, i32 0
%outer = insertelement <vscale x 4 x i32> %inner, i32 %inv, i32 1
store <vscale x 4 x i32> %outer, ptr %idx
%iv.next = add i32 %iv, 1
%done = icmp eq i32 %iv, %n
br i1 %done, label %exit, label %loop
exit:
ret <vscale x 4 x i32> %outer
}