; RUN: opt -S -aarch64-sve-intrinsic-opts -mtriple=aarch64-linux-gnu -mattr=+sve < %s 2>%t | FileCheck --check-prefix OPT %s ; RUN: FileCheck --check-prefix=WARN --allow-empty %s <%t ; If this check fails please read test/CodeGen/AArch64/README for instructions on how to resolve it. ; WARN-NOT: warning define @reinterpret_test_h( %a) { ; OPT-LABEL: @reinterpret_test_h( ; OPT-NOT: convert ; OPT: 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) { ; OPT-LABEL: @reinterpret_test_h_rev( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %1) ; OPT-NEXT: ret %2 %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) { ; OPT-LABEL: @reinterpret_test_w( ; OPT-NOT: convert ; OPT: 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) { ; OPT-LABEL: @reinterpret_test_w_rev( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %1) ; OPT-NEXT: ret %2 %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) { ; OPT-LABEL: @reinterpret_test_d( ; OPT-NOT: convert ; OPT: 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) { ; OPT-LABEL: @reinterpret_test_d_rev( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %1) ; OPT-NEXT: ret %2 %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) { ; OPT-LABEL: @reinterpret_test_full_chain( ; OPT: 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) { ; OPT-LABEL: @reinterpret_test_partial_chain( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) ; OPT-NEXT: ret %2 %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) { ; OPT-LABEL: @reinterpret_test_irreducible_chain( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) ; OPT-NEXT: %3 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %2) ; OPT-NEXT: %4 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv8i1( %3) ; OPT-NEXT: ret %4 %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) { ; OPT-LABEL: @reinterpret_test_keep_some_candidates( ; OPT: %1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %a) ; OPT-NEXT: %2 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %1) ; OPT-NEXT: ret %2 %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) { ; OPT-LABEL: reinterpret_reductions ; OPT-NOT: convert ; OPT-NOT: phi ; OPT: phi [ %a, %br_phi_a ], [ %b, %br_phi_b ], [ %c, %br_phi_c ] ; OPT-NOT: convert ; OPT: ret 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) { ; OPT-LABEL: reinterpret_reductions_1 ; OPT: convert ; OPT: phi [ %a1, %br_phi_a ], [ %b1, %br_phi_b ], [ %c1, %br_phi_c ] ; OPT-NOT: phi ; OPT: tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ; OPT: ret 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) { ; OPT-LABEL: reinterpret_reductions_2 ; OPT: convert ; OPT: phi [ %a1, %br_phi_a ], [ %b, %br_phi_b ], [ %c1, %br_phi_c ] ; OPT-NOT: phi ; OPT: tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ; OPT: ret 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) { ; OPT-LABEL: reinterpret_reductions3 ; OPT: phi [ %a1, %br_phi_a ], [ %b1, %br_phi_b ], [ %c1, %br_phi_c ] ; OPT-NOT: phi ; OPT: tail call @llvm.aarch64.sve.convert.from.svbool.nxv2i1( %pg) ; OPT-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 } 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()