diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp @@ -377,6 +377,50 @@ return IC.replaceInstUsesWith(II, NPN); } +static Optional> GetPredicatedBinOp(Value* Val){ + IntrinsicInst* II = dyn_cast(Val); + if (!II) + return None; + + if (II->getIntrinsicID() == Intrinsic::aarch64_sve_and_z) + return std::make_pair(II, Intrinsic::aarch64_sve_and_z); + return None; +} + +// Predicated binary operations which must have equal argument and return types +// can produce redundant convert.to.svbools. +static Optional SolveRedundantSVBoolForBinOps(InstCombiner &IC, + IntrinsicInst &II) { + if (auto Opt = GetPredicatedBinOp(II.getOperand(0))){ + auto OptVal = Opt.getValue(); + auto BinOp = OptVal.first; + auto BinOpPred = BinOp->getOperand(0); + auto BinOpOp1 = BinOp->getOperand(1); + auto BinOpOp2 = BinOp->getOperand(2); + + auto PredIntr = dyn_cast(BinOpPred); + if (!PredIntr || PredIntr->getIntrinsicID() != Intrinsic::aarch64_sve_convert_to_svbool) + return None; + + IRBuilder<> Builder(II.getContext()); + Builder.SetInsertPoint(&II); + auto PredOp = PredIntr->getOperand(0); + auto PredOpTy = cast(PredOp->getType()); + + SmallVector NarrowedBinOpArgs = { PredOp }; + auto NarrowBinOpOp1 = Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_from_svbool, { PredOpTy }, { BinOpOp1 }); + NarrowedBinOpArgs.push_back(NarrowBinOpOp1); + if (BinOpOp1 == BinOpOp2) + NarrowedBinOpArgs.push_back(NarrowBinOpOp1); + else + NarrowedBinOpArgs.push_back(Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_from_svbool, { PredOpTy }, { BinOpOp2 })); + + auto NarrowedBinOp = Builder.CreateIntrinsic(OptVal.second, { PredOpTy }, NarrowedBinOpArgs); + return IC.replaceInstUsesWith(II, NarrowedBinOp); + } + return None; +} + static Optional instCombineConvertFromSVBool(InstCombiner &IC, IntrinsicInst &II) { // If the reinterpret instruction operand is a PHI Node @@ -414,10 +458,11 @@ Cursor = IntrinsicCursor->getOperand(0); } - // If no viable replacement in the conversion chain was found, there is - // nothing to do. - if (!EarliestReplacement) - return None; + // If no viable replacement in the conversion chain was found, check for + // redundant convert.to.svbools for binary op intrinsics + if (!EarliestReplacement){ + return SolveRedundantSVBoolForBinOps(IC, II); + } return IC.replaceInstUsesWith(II, EarliestReplacement); } diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll @@ -0,0 +1,35 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instcombine < %s | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +define @remove_redundant_svbool( %a, %b, %c) { +; CHECK-LABEL: @remove_redundant_svbool( +; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[B:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[C:%.*]]) +; CHECK-NEXT: [[TMP3:%.*]] = call @llvm.aarch64.sve.and.z.nxv4i1( [[A:%.*]], [[TMP1]], [[TMP2]]) +; CHECK-NEXT: ret [[TMP3]] +; + %t1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %a) + %t2 = tail call @llvm.aarch64.sve.and.z.nxv16i1( %t1, %b, %c) + %t3 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %t2) + ret %t3 +} + +define @remove_redundant_svbool_equal_ops( %a, %b) { +; CHECK-LABEL: @remove_redundant_svbool_equal_ops( +; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[B:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call @llvm.aarch64.sve.and.z.nxv4i1( [[A:%.*]], [[TMP1]], [[TMP1]]) +; CHECK-NEXT: ret [[TMP2]] +; + %t1 = tail call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %a) + %t2 = tail call @llvm.aarch64.sve.and.z.nxv16i1( %t1, %b, %b) + %t3 = tail call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( %t2) + ret %t3 +} + +declare @llvm.aarch64.sve.convert.to.svbool.nxv4i1() +declare @llvm.aarch64.sve.and.z.nxv16i1(, , ) +declare @llvm.aarch64.sve.convert.from.svbool.nxv4i1() + +attributes #0 = { "target-features"="+sve" }