; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s target triple = "aarch64" define @reinterpret_test_h( %a) { ; CHECK-LABEL: define @reinterpret_test_h ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: ret [[A]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( %1) ret %2 } ; Reinterprets are not redundant because the second reinterpret zeros the ; lanes that don't exist within its input. define @reinterpret_test_h_rev( %a) { ; CHECK-LABEL: define @reinterpret_test_h_rev ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( [[TMP1]]) ; CHECK-NEXT: ret [[TMP2]] ; %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( %a) %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %1) ret %2 } define @reinterpret_test_w( %a) { ; CHECK-LABEL: define @reinterpret_test_w ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: ret [[A]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) ret %2 } ; Reinterprets are not redundant because the second reinterpret zeros the ; lanes that don't exist within its input. define @reinterpret_test_w_rev( %a) { ; CHECK-LABEL: define @reinterpret_test_w_rev ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( [[TMP1]]) ; CHECK-NEXT: ret [[TMP2]] ; %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %a) %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %1) ret %2 } define @reinterpret_test_d( %a) { ; CHECK-LABEL: define @reinterpret_test_d ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: ret [[A]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %1) ret %2 } ; Reinterprets are not redundant because the second reinterpret zeros the ; lanes that don't exist within its input. define @reinterpret_test_d_rev( %a) { ; CHECK-LABEL: define @reinterpret_test_d_rev ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[TMP1]]) ; CHECK-NEXT: ret [[TMP2]] ; %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %a) %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %1) ret %2 } define @reinterpret_test_full_chain( %a) { ; CHECK-LABEL: define @reinterpret_test_full_chain ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: ret [[A]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) %3 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %2) %4 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %3) %5 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %4) %6 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %5) ret %6 } ; The last two reinterprets are not necessary, since they are doing the same ; work as the first two. define @reinterpret_test_partial_chain( %a) { ; CHECK-LABEL: define @reinterpret_test_partial_chain ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[TMP1]]) ; CHECK-NEXT: ret [[TMP2]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) %3 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %2) %4 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %3) ret %4 } ; The chain cannot be reduced because of the second reinterpret, which causes ; zeroing. define @reinterpret_test_irreducible_chain( %a) { ; CHECK-LABEL: define @reinterpret_test_irreducible_chain ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( [[TMP2]]) ; CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( [[TMP3]]) ; CHECK-NEXT: ret [[TMP4]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) %3 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %2) %4 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( %3) ret %4 } ; Here, the candidate list is larger than the number of instructions that we ; end up removing. define @reinterpret_test_keep_some_candidates( %a) { ; CHECK-LABEL: define @reinterpret_test_keep_some_candidates ; CHECK-SAME: ( [[A:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( [[A]]) ; CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[TMP1]]) ; CHECK-NEXT: ret [[TMP2]] ; %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %a) %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) %3 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %2) %4 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %3) ret %4 } define @reinterpret_reductions(i32 %cond, %a, %b, %c) { ; CHECK-LABEL: define @reinterpret_reductions ; CHECK-SAME: (i32 [[COND:%.*]], [[A:%.*]], [[B:%.*]], [[C:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: switch i32 [[COND]], label [[BR_PHI_C:%.*]] [ ; CHECK-NEXT: i32 43, label [[BR_PHI_A:%.*]] ; CHECK-NEXT: i32 45, label [[BR_PHI_B:%.*]] ; CHECK-NEXT: ] ; CHECK: br_phi_a: ; CHECK-NEXT: br label [[JOIN:%.*]] ; CHECK: br_phi_b: ; CHECK-NEXT: br label [[JOIN]] ; CHECK: br_phi_c: ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: ; CHECK-NEXT: [[PG1:%.*]] = phi [ [[A]], [[BR_PHI_A]] ], [ [[B]], [[BR_PHI_B]] ], [ [[C]], [[BR_PHI_C]] ] ; CHECK-NEXT: ret [[PG1]] ; entry: switch i32 %cond, label %br_phi_c [ i32 43, label %br_phi_a i32 45, label %br_phi_b ] br_phi_a: %a1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) br label %join br_phi_b: %b1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %b) br label %join br_phi_c: %c1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %c) br label %join join: %pg = phi [ %a1, %br_phi_a ], [ %b1, %br_phi_b ], [ %c1, %br_phi_c ] %pg1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ret %pg1 } ; No transform as the reinterprets are converting from different types (nxv2i1 & nxv4i1) ; As the incoming values to the phi must all be the same type, we cannot remove the reinterprets. define @reinterpret_reductions_1(i32 %cond, %a, %b, %c) { ; CHECK-LABEL: define @reinterpret_reductions_1 ; CHECK-SAME: (i32 [[COND:%.*]], [[A:%.*]], [[B:%.*]], [[C:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: switch i32 [[COND]], label [[BR_PHI_C:%.*]] [ ; CHECK-NEXT: i32 43, label [[BR_PHI_A:%.*]] ; CHECK-NEXT: i32 45, label [[BR_PHI_B:%.*]] ; CHECK-NEXT: ] ; CHECK: br_phi_a: ; CHECK-NEXT: [[A1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[A]]) ; CHECK-NEXT: br label [[JOIN:%.*]] ; CHECK: br_phi_b: ; CHECK-NEXT: [[B1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( [[B]]) ; CHECK-NEXT: br label [[JOIN]] ; CHECK: br_phi_c: ; CHECK-NEXT: [[C1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[C]]) ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: ; CHECK-NEXT: [[PG:%.*]] = phi [ [[A1]], [[BR_PHI_A]] ], [ [[B1]], [[BR_PHI_B]] ], [ [[C1]], [[BR_PHI_C]] ] ; CHECK-NEXT: [[PG1:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG]]) ; CHECK-NEXT: ret [[PG1]] ; entry: switch i32 %cond, label %br_phi_c [ i32 43, label %br_phi_a i32 45, label %br_phi_b ] br_phi_a: %a1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) br label %join br_phi_b: %b1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %b) br label %join br_phi_c: %c1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %c) br label %join join: %pg = phi [ %a1, %br_phi_a ], [ %b1, %br_phi_b ], [ %c1, %br_phi_c ] %pg1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ret %pg1 } ; No transform. Similar to the the test above, but here only two of the arguments need to ; be converted to svbool. define @reinterpret_reductions_2(i32 %cond, %a, %b, %c) { ; CHECK-LABEL: define @reinterpret_reductions_2 ; CHECK-SAME: (i32 [[COND:%.*]], [[A:%.*]], [[B:%.*]], [[C:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: switch i32 [[COND]], label [[BR_PHI_C:%.*]] [ ; CHECK-NEXT: i32 43, label [[BR_PHI_A:%.*]] ; CHECK-NEXT: i32 45, label [[BR_PHI_B:%.*]] ; CHECK-NEXT: ] ; CHECK: br_phi_a: ; CHECK-NEXT: [[A1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[A]]) ; CHECK-NEXT: br label [[JOIN:%.*]] ; CHECK: br_phi_b: ; CHECK-NEXT: br label [[JOIN]] ; CHECK: br_phi_c: ; CHECK-NEXT: [[C1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[C]]) ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: ; CHECK-NEXT: [[PG:%.*]] = phi [ [[A1]], [[BR_PHI_A]] ], [ [[B]], [[BR_PHI_B]] ], [ [[C1]], [[BR_PHI_C]] ] ; CHECK-NEXT: [[PG1:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( [[PG]]) ; CHECK-NEXT: ret [[PG1]] ; entry: switch i32 %cond, label %br_phi_c [ i32 43, label %br_phi_a i32 45, label %br_phi_b ] br_phi_a: %a1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) br label %join br_phi_b: br label %join br_phi_c: %c1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %c) br label %join join: %pg = phi [ %a1, %br_phi_a ], [ %b, %br_phi_b ], [ %c1, %br_phi_c ] %pg1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ret %pg1 } ; Similar to reinterpret_reductions but the reinterprets remain because the ; original phi cannot be removed (i.e. prefer reinterprets over multiple phis). define @reinterpret_reductions3(i32 %cond, %a, %b, %c) { ; CHECK-LABEL: define @reinterpret_reductions3 ; CHECK-SAME: (i32 [[COND:%.*]], [[A:%.*]], [[B:%.*]], [[C:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: switch i32 [[COND]], label [[BR_PHI_C:%.*]] [ ; CHECK-NEXT: i32 43, label [[BR_PHI_A:%.*]] ; CHECK-NEXT: i32 45, label [[BR_PHI_B:%.*]] ; CHECK-NEXT: ] ; CHECK: br_phi_a: ; CHECK-NEXT: [[A1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[A]]) ; CHECK-NEXT: br label [[JOIN:%.*]] ; CHECK: br_phi_b: ; CHECK-NEXT: [[B1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[B]]) ; CHECK-NEXT: br label [[JOIN]] ; CHECK: br_phi_c: ; CHECK-NEXT: [[C1:%.*]] = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( [[C]]) ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: ; CHECK-NEXT: [[PG:%.*]] = phi [ [[A1]], [[BR_PHI_A]] ], [ [[B1]], [[BR_PHI_B]] ], [ [[C1]], [[BR_PHI_C]] ] ; CHECK-NEXT: ret [[PG]] ; entry: switch i32 %cond, label %br_phi_c [ i32 43, label %br_phi_a i32 45, label %br_phi_b ] br_phi_a: %a1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) br label %join br_phi_b: %b1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %b) br label %join br_phi_c: %c1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %c) br label %join join: %pg = phi [ %a1, %br_phi_a ], [ %b1, %br_phi_b ], [ %c1, %br_phi_c ] %pg1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ret %pg } define void @phi_insert_point( %arg, ptr %p) { ; CHECK-LABEL: define void @phi_insert_point ; CHECK-SAME: ( [[ARG:%.*]], ptr [[P:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[CONVERT:%.*]] = phi [ [[ARG]], [[ENTRY:%.*]] ], [ zeroinitializer, [[FOR_BODY]] ] ; CHECK-NEXT: [[IDX:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[IDX_NEXT:%.*]], [[FOR_BODY]] ] ; CHECK-NEXT: [[IDX_EXT:%.*]] = ashr i64 [[IDX]], 1 ; CHECK-NEXT: store [[CONVERT]], ptr [[P]], align 1 ; CHECK-NEXT: [[IDX_NEXT]] = or i64 [[IDX_EXT]], 1 ; CHECK-NEXT: br label [[FOR_BODY]] ; entry: %init = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %arg) br label %for.body for.body: %phi = phi [ %init, %entry ], [ %phi.next, %for.body ] %idx = phi i64 [ 0, %entry ], [ %idx.next, %for.body ] %idx.ext = ashr i64 %idx, 1 %convert = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %phi) store %convert, ptr %p %idx.next = or i64 %idx.ext, 1 %phi.next = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( zeroinitializer) br label %for.body } declare @llvm.aarch64.sve.convert.to.svbool.nxv8i1() declare @llvm.aarch64.sve.convert.to.svbool.nxv4i1() declare @llvm.aarch64.sve.convert.to.svbool.nxv2i1() declare @llvm.aarch64.sve.convert.from.svbool.nxv8i1() declare @llvm.aarch64.sve.convert.from.svbool.nxv4i1() declare @llvm.aarch64.sve.convert.from.svbool.nxv2i1() attributes #0 = { "target-features"="+sve" }