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