diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 8e447b84d3149..9dbab56348411 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1969,6 +1969,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) { case Intrinsic::experimental_constrained_rint: case Intrinsic::experimental_constrained_fcmp: case Intrinsic::experimental_constrained_fcmps: + + case Intrinsic::experimental_cttz_elts: return true; default: return false; @@ -3792,6 +3794,27 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty, break; } } + + if (IntrinsicID == Intrinsic::experimental_cttz_elts) { + auto *FVTy = dyn_cast(Operands[0]->getType()); + bool ZeroIsPoison = cast(Operands[1])->isOne(); + if (!FVTy) + return nullptr; + unsigned Width = Ty->getIntegerBitWidth(); + if (APInt::getMaxValue(Width).ult(FVTy->getNumElements())) + return PoisonValue::get(Ty); + for (unsigned I = 0; I < FVTy->getNumElements(); ++I) { + Constant *Elt = Operands[0]->getAggregateElement(I); + if (!Elt) + return nullptr; + if (isa(Elt) || Elt->isNullValue()) + continue; + return ConstantInt::get(Ty, I); + } + if (ZeroIsPoison) + return PoisonValue::get(Ty); + return ConstantInt::get(Ty, FVTy->getNumElements()); + } return nullptr; } diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/cttz-elts.ll b/llvm/test/Transforms/InstSimplify/ConstProp/cttz-elts.ll new file mode 100644 index 0000000000000..db91fd68fcbe6 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/ConstProp/cttz-elts.ll @@ -0,0 +1,74 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes=instsimplify < %s | FileCheck %s + +define i1 @cttz_elts_i1_v4i32() { +; CHECK-LABEL: @cttz_elts_i1_v4i32( +; CHECK-NEXT: ret i1 poison +; + %res = call i1 @llvm.experimental.cttz.elts.i1.v4i32(<4 x i32> , i1 false) + ret i1 %res +} + +define i32 @cttz_elts_v4i1() { +; CHECK-LABEL: @cttz_elts_v4i1( +; CHECK-NEXT: ret i32 3 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i1(<4 x i1> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32() { +; CHECK-LABEL: @cttz_elts_v4i32( +; CHECK-NEXT: ret i32 1 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_unused_lane_undef() { +; CHECK-LABEL: @cttz_elts_v4i32_unused_lane_undef( +; CHECK-NEXT: ret i32 1 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_used_lane_undef() { +; CHECK-LABEL: @cttz_elts_v4i32_used_lane_undef( +; CHECK-NEXT: ret i32 3 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_unused_lane_poison() { +; CHECK-LABEL: @cttz_elts_v4i32_unused_lane_poison( +; CHECK-NEXT: ret i32 1 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_used_lane_poison() { +; CHECK-LABEL: @cttz_elts_v4i32_used_lane_poison( +; CHECK-NEXT: ret i32 3 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_all_zeros() { +; CHECK-LABEL: @cttz_elts_v4i32_all_zeros( +; CHECK-NEXT: ret i32 4 +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 false) + ret i32 %res +} + +define i32 @cttz_elts_v4i32_all_zeros_iszeropoison() { +; CHECK-LABEL: @cttz_elts_v4i32_all_zeros_iszeropoison( +; CHECK-NEXT: ret i32 poison +; + %res = call i32 @llvm.experimental.cttz.elts.i32.v4i32(<4 x i32> , i1 true) + ret i32 %res +}