[IRBuilder] (Target|InstSimplify)-fold intrinsics#204967
Conversation
Includes changes to guard against a nullptr TLI and Call. TargetFold or InstSimplify fold in IRBuilderBase::CreateIntrinsic, in the same way we fold in Create(Unary|Binary)Intrinsic.
|
@llvm/pr-subscribers-vectorizers @llvm/pr-subscribers-llvm-analysis Author: Ramkumar Ramachandra (artagnon) ChangesIncludes changes to guard against a nullptr TLI and Call. TargetFold or InstSimplify fold in IRBuilderBase::CreateIntrinsic, in the same way we fold in Create(Unary|Binary)Intrinsic. Patch is 38.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/204967.diff 18 Files Affected:
diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h
index 2f7a327e1652a..f223ebf0586f4 100644
--- a/llvm/include/llvm/Analysis/ConstantFolding.h
+++ b/llvm/include/llvm/Analysis/ConstantFolding.h
@@ -175,6 +175,9 @@ LLVM_ABI Constant *ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
LLVM_ABI Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty);
+LLVM_ABI Constant *ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty);
+
/// ConstantFoldLoadThroughBitcast - try to cast constant to destination type
/// returning null if unsuccessful. Can cast pointer to pointer or pointer to
/// integer and vice versa if their sizes are equal.
diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index a8dff839de214..93cf827750528 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -132,6 +132,11 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
return simplifyBinaryIntrinsic(ID, Ty, LHS, RHS, FMF, SQ);
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return simplifyIntrinsic(ID, Ty, Ops, FMF, SQ);
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index 0a9d9c3d88111..74d8ac3f1fc1f 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -19,6 +19,7 @@
#define LLVM_ANALYSIS_TARGETFOLDER_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/IR/ConstantFold.h"
#include "llvm/IR/Constants.h"
@@ -207,6 +208,15 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ auto COps =
+ map_to_vector(Ops, [](Value *Op) { return dyn_cast<Constant>(Op); });
+ if (none_of(COps, equal_to(nullptr)))
+ return ConstantFoldIntrinsic(ID, COps, Ty);
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index b2937c2339ca7..c47a990650f68 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -194,6 +194,12 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ // Use TargetFolder or InstSimplifyFolder instead.
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index e68fff29b7165..1699845b22466 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -76,13 +76,15 @@ class LLVM_ABI IRBuilderFolder {
virtual Value *FoldCast(Instruction::CastOps Op, Value *V,
Type *DestTy) const = 0;
- virtual Value *
- FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
- virtual Value *
- FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS,
+ Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
+
+ virtual Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops,
+ Type *Ty, FastMathFlags FMF = {}) const = 0;
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index a86cbf724e69f..5ba098d5cddf4 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -124,6 +124,11 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index f18b7a0b66a21..aba7492de9179 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2489,13 +2489,13 @@ getEvaluationRoundingMode(const ConstrainedFPIntrinsic *CI) {
}
/// Try to constant fold llvm.canonicalize for the given caller and value.
-static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
- const APFloat &Src) {
+static Constant *constantFoldCanonicalize(const Type *Ty, const APFloat &Src,
+ const Function *CtxF = nullptr) {
// Zero, positive and negative, is always OK to fold.
if (Src.isZero()) {
// Get a fresh 0, since ppc_fp128 does have non-canonical zeros.
return ConstantFP::get(
- CI->getContext(),
+ Ty->getContext(),
APFloat::getZero(Src.getSemantics(), Src.isNegative()));
}
@@ -2507,14 +2507,13 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
// Denorms and nans may have special encodings, but it should be OK to fold a
// totally average number.
if (Src.isNormal() || Src.isInfinity())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
- if (Src.isDenormal() && CI->getParent() && CI->getFunction()) {
- DenormalMode DenormMode =
- CI->getFunction()->getDenormalMode(Src.getSemantics());
+ if (Src.isDenormal() && CtxF) {
+ DenormalMode DenormMode = CtxF->getDenormalMode(Src.getSemantics());
if (DenormMode == DenormalMode::getIEEE())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
if (DenormMode.Input == DenormalMode::Dynamic)
return nullptr;
@@ -2531,7 +2530,7 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
(DenormMode.Output == DenormalMode::PositiveZero &&
DenormMode.Input == DenormalMode::IEEE));
- return ConstantFP::get(CI->getContext(),
+ return ConstantFP::get(Ty->getContext(),
APFloat::getZero(Src.getSemantics(), !IsPositive));
}
@@ -2539,11 +2538,10 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
}
static Constant *ConstantFoldScalarCall1(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 1 && "Wrong number of operands.");
if (IntrinsicID == Intrinsic::is_constant) {
@@ -2580,7 +2578,7 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// a function during inlining), Call's caller may not be available.
// So check Call's BB first before querying Call->getCaller.
const Function *Caller =
- Call->getParent() ? Call->getCaller() : nullptr;
+ Call && Call->getParent() ? Call->getCaller() : nullptr;
if (Caller &&
!NullPointerIsDefined(
Caller, Operands[0]->getType()->getPointerAddressSpace())) {
@@ -2622,8 +2620,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantInt::get(Ty, Int);
}
- if (IntrinsicID == Intrinsic::canonicalize)
- return constantFoldCanonicalize(Ty, Call, U);
+ if (IntrinsicID == Intrinsic::canonicalize) {
+ const Function *CtxF =
+ Call && Call->getParent() ? Call->getFunction() : nullptr;
+ return constantFoldCanonicalize(Ty, U, CtxF);
+ }
#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128)
if (Ty->isFP128Ty()) {
@@ -2697,48 +2698,49 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// Rounding operations (floor, trunc, ceil, round and nearbyint) do not
// raise FP exceptions, unless the argument is signaling NaN.
- std::optional<APFloat::roundingMode> RM;
- switch (IntrinsicID) {
- default:
- break;
- case Intrinsic::experimental_constrained_nearbyint:
- case Intrinsic::experimental_constrained_rint: {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- RM = CI->getRoundingMode();
- if (!RM || *RM == RoundingMode::Dynamic)
- return nullptr;
- break;
- }
- case Intrinsic::experimental_constrained_round:
- RM = APFloat::rmNearestTiesToAway;
- break;
- case Intrinsic::experimental_constrained_ceil:
- RM = APFloat::rmTowardPositive;
- break;
- case Intrinsic::experimental_constrained_floor:
- RM = APFloat::rmTowardNegative;
- break;
- case Intrinsic::experimental_constrained_trunc:
- RM = APFloat::rmTowardZero;
- break;
- }
- if (RM) {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- if (U.isFinite()) {
- APFloat::opStatus St = U.roundToIntegral(*RM);
- if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
- St == APFloat::opInexact) {
+ if (auto *CI = dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
+ std::optional<APFloat::roundingMode> RM;
+ switch (IntrinsicID) {
+ default:
+ break;
+ case Intrinsic::experimental_constrained_nearbyint:
+ case Intrinsic::experimental_constrained_rint: {
+ RM = CI->getRoundingMode();
+ if (!RM || *RM == RoundingMode::Dynamic)
+ return nullptr;
+ break;
+ }
+ case Intrinsic::experimental_constrained_round:
+ RM = APFloat::rmNearestTiesToAway;
+ break;
+ case Intrinsic::experimental_constrained_ceil:
+ RM = APFloat::rmTowardPositive;
+ break;
+ case Intrinsic::experimental_constrained_floor:
+ RM = APFloat::rmTowardNegative;
+ break;
+ case Intrinsic::experimental_constrained_trunc:
+ RM = APFloat::rmTowardZero;
+ break;
+ }
+ if (RM) {
+ if (U.isFinite()) {
+ APFloat::opStatus St = U.roundToIntegral(*RM);
+ if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
+ St == APFloat::opInexact) {
+ std::optional<fp::ExceptionBehavior> EB =
+ CI->getExceptionBehavior();
+ if (EB == fp::ebStrict)
+ return nullptr;
+ }
+ } else if (U.isSignaling()) {
std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB == fp::ebStrict)
+ if (EB && *EB != fp::ebIgnore)
return nullptr;
+ U = APFloat::getQNaN(U.getSemantics());
}
- } else if (U.isSignaling()) {
- std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB && *EB != fp::ebIgnore)
- return nullptr;
- U = APFloat::getQNaN(U.getSemantics());
+ return ConstantFP::get(Ty, U);
}
- return ConstantFP::get(Ty, U);
}
// NVVM float/double to signed/unsigned int32/int64 conversions:
@@ -3350,7 +3352,7 @@ static Constant *ConstantFoldNextToward(const APFloat &Op0, const APFloat &Op1,
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI = nullptr) {
if (!TLI)
return nullptr;
@@ -3421,7 +3423,7 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const CallBase *Call) {
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 2 && "Wrong number of operands.");
if (Ty->isFloatingPointTy()) {
@@ -4098,11 +4100,10 @@ static Constant *ConstantFoldAMDGCNPermIntrinsic(ArrayRef<Constant *> Operands,
}
static Constant *ConstantFoldScalarCall3(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 3 && "Wrong number of operands.");
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
@@ -4112,7 +4113,8 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
const APFloat &C2 = Op2->getValueAPF();
const APFloat &C3 = Op3->getValueAPF();
- if (const auto *ConstrIntr = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
+ if (const auto *ConstrIntr =
+ dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
RoundingMode RM = getEvaluationRoundingMode(ConstrIntr);
APFloat Res = C1;
APFloat::opStatus St;
@@ -4262,11 +4264,10 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
}
static Constant *ConstantFoldScalarCall(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
if (IntrinsicID != Intrinsic::not_intrinsic &&
any_of(Operands, IsaPred<PoisonValue>) &&
intrinsicPropagatesPoison(IntrinsicID))
@@ -4708,12 +4709,17 @@ ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
Constant *llvm::ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
Type *Ty) {
- return ConstantFoldScalarCall1("", ID, Ty, Op, nullptr, nullptr);
+ return ConstantFoldScalarCall1("", ID, Ty, Op);
}
Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty) {
- return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS}, nullptr);
+ return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS});
+}
+
+Constant *llvm::ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty) {
+ return ConstantFoldScalarCall("", ID, Ty, Ops);
}
Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index eac591af3f495..46a52d94ec7f4 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -966,7 +966,9 @@ Value *IRBuilderBase::CreateIntrinsic(Intrinsic::ID ID,
FMFSource FMFSource, const Twine &Name,
ArrayRef<OperandBundleDef> OpBundles,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ Type *RetTy = Intrinsic::getType(Context, ID, OverloadTypes)->getReturnType();
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI = CreateIntrinsicWithoutFolding(ID, OverloadTypes, Args,
FMFSource, Name, OpBundles);
SetFn(CI);
@@ -977,7 +979,8 @@ Value *IRBuilderBase::CreateIntrinsic(Type *RetTy, Intrinsic::ID ID,
ArrayRef<Value *> Args,
FMFSource FMFSource, const Twine &Name,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI =
CreateIntrinsicWithoutFolding(RetTy, ID, Args, FMFSource, Name);
SetFn(CI);
diff --git a/llvm/test/Transforms/IRCE/correct-loop-info.ll b/llvm/test/Transforms/IRCE/correct-loop-info.ll
index c75de167681ad..7ea445718289a 100644
--- a/llvm/test/Transforms/IRCE/correct-loop-info.ll
+++ b/llvm/test/Transforms/IRCE/correct-loop-info.ll
@@ -13,33 +13,30 @@ source_filename = "correct-loop-info.ll"
define void @baz() personality ptr @ham {
; CHECK-LABEL: @baz(
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 -1)
-; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 0)
; CHECK-NEXT: br label [[OUTERHEADER:%.*]]
; CHECK: outerheader:
; CHECK-NEXT: [[TMP:%.*]] = icmp slt i32 undef, 84
; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB16:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 undef, [[EXIT_PRELOOP_AT]]
-; CHECK-NEXT: br i1 [[TMP0]], label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
+; CHECK-NEXT: br i1 false, label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preloop.preheader:
; CHECK-NEXT: br label [[INNERHEADER_PRELOOP:%.*]]
; CHECK: mainloop:
-; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], [[EXIT_MAINLOOP_AT]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], 2147483647
; CHECK-NEXT: br i1 [[TMP1]], label [[INNERHEADER_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preheader:
; CHECK-NEXT: br label [[INNERHEADER:%.*]]
; CHECK: innerheader:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP6:%.*]], [[BB8:%.*]] ], [ [[TMP4_PRELOOP_COPY:%.*]], [[INNERHEADER_PREHEADER]] ]
; CHECK-NEXT: invoke void @pluto()
-; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
+; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
; CHECK: bb5:
; CHECK-NEXT: [[TMP6]] = add nsw i32 [[TMP4]], 1
; CH...
[truncated]
|
|
@llvm/pr-subscribers-llvm-transforms Author: Ramkumar Ramachandra (artagnon) ChangesIncludes changes to guard against a nullptr TLI and Call. TargetFold or InstSimplify fold in IRBuilderBase::CreateIntrinsic, in the same way we fold in Create(Unary|Binary)Intrinsic. Patch is 38.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/204967.diff 18 Files Affected:
diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h
index 2f7a327e1652a..f223ebf0586f4 100644
--- a/llvm/include/llvm/Analysis/ConstantFolding.h
+++ b/llvm/include/llvm/Analysis/ConstantFolding.h
@@ -175,6 +175,9 @@ LLVM_ABI Constant *ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
LLVM_ABI Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty);
+LLVM_ABI Constant *ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty);
+
/// ConstantFoldLoadThroughBitcast - try to cast constant to destination type
/// returning null if unsuccessful. Can cast pointer to pointer or pointer to
/// integer and vice versa if their sizes are equal.
diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index a8dff839de214..93cf827750528 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -132,6 +132,11 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
return simplifyBinaryIntrinsic(ID, Ty, LHS, RHS, FMF, SQ);
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return simplifyIntrinsic(ID, Ty, Ops, FMF, SQ);
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index 0a9d9c3d88111..74d8ac3f1fc1f 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -19,6 +19,7 @@
#define LLVM_ANALYSIS_TARGETFOLDER_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/IR/ConstantFold.h"
#include "llvm/IR/Constants.h"
@@ -207,6 +208,15 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ auto COps =
+ map_to_vector(Ops, [](Value *Op) { return dyn_cast<Constant>(Op); });
+ if (none_of(COps, equal_to(nullptr)))
+ return ConstantFoldIntrinsic(ID, COps, Ty);
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index b2937c2339ca7..c47a990650f68 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -194,6 +194,12 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ // Use TargetFolder or InstSimplifyFolder instead.
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index e68fff29b7165..1699845b22466 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -76,13 +76,15 @@ class LLVM_ABI IRBuilderFolder {
virtual Value *FoldCast(Instruction::CastOps Op, Value *V,
Type *DestTy) const = 0;
- virtual Value *
- FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
- virtual Value *
- FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS,
+ Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
+
+ virtual Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops,
+ Type *Ty, FastMathFlags FMF = {}) const = 0;
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index a86cbf724e69f..5ba098d5cddf4 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -124,6 +124,11 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index f18b7a0b66a21..aba7492de9179 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2489,13 +2489,13 @@ getEvaluationRoundingMode(const ConstrainedFPIntrinsic *CI) {
}
/// Try to constant fold llvm.canonicalize for the given caller and value.
-static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
- const APFloat &Src) {
+static Constant *constantFoldCanonicalize(const Type *Ty, const APFloat &Src,
+ const Function *CtxF = nullptr) {
// Zero, positive and negative, is always OK to fold.
if (Src.isZero()) {
// Get a fresh 0, since ppc_fp128 does have non-canonical zeros.
return ConstantFP::get(
- CI->getContext(),
+ Ty->getContext(),
APFloat::getZero(Src.getSemantics(), Src.isNegative()));
}
@@ -2507,14 +2507,13 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
// Denorms and nans may have special encodings, but it should be OK to fold a
// totally average number.
if (Src.isNormal() || Src.isInfinity())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
- if (Src.isDenormal() && CI->getParent() && CI->getFunction()) {
- DenormalMode DenormMode =
- CI->getFunction()->getDenormalMode(Src.getSemantics());
+ if (Src.isDenormal() && CtxF) {
+ DenormalMode DenormMode = CtxF->getDenormalMode(Src.getSemantics());
if (DenormMode == DenormalMode::getIEEE())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
if (DenormMode.Input == DenormalMode::Dynamic)
return nullptr;
@@ -2531,7 +2530,7 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
(DenormMode.Output == DenormalMode::PositiveZero &&
DenormMode.Input == DenormalMode::IEEE));
- return ConstantFP::get(CI->getContext(),
+ return ConstantFP::get(Ty->getContext(),
APFloat::getZero(Src.getSemantics(), !IsPositive));
}
@@ -2539,11 +2538,10 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
}
static Constant *ConstantFoldScalarCall1(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 1 && "Wrong number of operands.");
if (IntrinsicID == Intrinsic::is_constant) {
@@ -2580,7 +2578,7 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// a function during inlining), Call's caller may not be available.
// So check Call's BB first before querying Call->getCaller.
const Function *Caller =
- Call->getParent() ? Call->getCaller() : nullptr;
+ Call && Call->getParent() ? Call->getCaller() : nullptr;
if (Caller &&
!NullPointerIsDefined(
Caller, Operands[0]->getType()->getPointerAddressSpace())) {
@@ -2622,8 +2620,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantInt::get(Ty, Int);
}
- if (IntrinsicID == Intrinsic::canonicalize)
- return constantFoldCanonicalize(Ty, Call, U);
+ if (IntrinsicID == Intrinsic::canonicalize) {
+ const Function *CtxF =
+ Call && Call->getParent() ? Call->getFunction() : nullptr;
+ return constantFoldCanonicalize(Ty, U, CtxF);
+ }
#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128)
if (Ty->isFP128Ty()) {
@@ -2697,48 +2698,49 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// Rounding operations (floor, trunc, ceil, round and nearbyint) do not
// raise FP exceptions, unless the argument is signaling NaN.
- std::optional<APFloat::roundingMode> RM;
- switch (IntrinsicID) {
- default:
- break;
- case Intrinsic::experimental_constrained_nearbyint:
- case Intrinsic::experimental_constrained_rint: {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- RM = CI->getRoundingMode();
- if (!RM || *RM == RoundingMode::Dynamic)
- return nullptr;
- break;
- }
- case Intrinsic::experimental_constrained_round:
- RM = APFloat::rmNearestTiesToAway;
- break;
- case Intrinsic::experimental_constrained_ceil:
- RM = APFloat::rmTowardPositive;
- break;
- case Intrinsic::experimental_constrained_floor:
- RM = APFloat::rmTowardNegative;
- break;
- case Intrinsic::experimental_constrained_trunc:
- RM = APFloat::rmTowardZero;
- break;
- }
- if (RM) {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- if (U.isFinite()) {
- APFloat::opStatus St = U.roundToIntegral(*RM);
- if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
- St == APFloat::opInexact) {
+ if (auto *CI = dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
+ std::optional<APFloat::roundingMode> RM;
+ switch (IntrinsicID) {
+ default:
+ break;
+ case Intrinsic::experimental_constrained_nearbyint:
+ case Intrinsic::experimental_constrained_rint: {
+ RM = CI->getRoundingMode();
+ if (!RM || *RM == RoundingMode::Dynamic)
+ return nullptr;
+ break;
+ }
+ case Intrinsic::experimental_constrained_round:
+ RM = APFloat::rmNearestTiesToAway;
+ break;
+ case Intrinsic::experimental_constrained_ceil:
+ RM = APFloat::rmTowardPositive;
+ break;
+ case Intrinsic::experimental_constrained_floor:
+ RM = APFloat::rmTowardNegative;
+ break;
+ case Intrinsic::experimental_constrained_trunc:
+ RM = APFloat::rmTowardZero;
+ break;
+ }
+ if (RM) {
+ if (U.isFinite()) {
+ APFloat::opStatus St = U.roundToIntegral(*RM);
+ if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
+ St == APFloat::opInexact) {
+ std::optional<fp::ExceptionBehavior> EB =
+ CI->getExceptionBehavior();
+ if (EB == fp::ebStrict)
+ return nullptr;
+ }
+ } else if (U.isSignaling()) {
std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB == fp::ebStrict)
+ if (EB && *EB != fp::ebIgnore)
return nullptr;
+ U = APFloat::getQNaN(U.getSemantics());
}
- } else if (U.isSignaling()) {
- std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB && *EB != fp::ebIgnore)
- return nullptr;
- U = APFloat::getQNaN(U.getSemantics());
+ return ConstantFP::get(Ty, U);
}
- return ConstantFP::get(Ty, U);
}
// NVVM float/double to signed/unsigned int32/int64 conversions:
@@ -3350,7 +3352,7 @@ static Constant *ConstantFoldNextToward(const APFloat &Op0, const APFloat &Op1,
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI = nullptr) {
if (!TLI)
return nullptr;
@@ -3421,7 +3423,7 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const CallBase *Call) {
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 2 && "Wrong number of operands.");
if (Ty->isFloatingPointTy()) {
@@ -4098,11 +4100,10 @@ static Constant *ConstantFoldAMDGCNPermIntrinsic(ArrayRef<Constant *> Operands,
}
static Constant *ConstantFoldScalarCall3(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 3 && "Wrong number of operands.");
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
@@ -4112,7 +4113,8 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
const APFloat &C2 = Op2->getValueAPF();
const APFloat &C3 = Op3->getValueAPF();
- if (const auto *ConstrIntr = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
+ if (const auto *ConstrIntr =
+ dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
RoundingMode RM = getEvaluationRoundingMode(ConstrIntr);
APFloat Res = C1;
APFloat::opStatus St;
@@ -4262,11 +4264,10 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
}
static Constant *ConstantFoldScalarCall(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
if (IntrinsicID != Intrinsic::not_intrinsic &&
any_of(Operands, IsaPred<PoisonValue>) &&
intrinsicPropagatesPoison(IntrinsicID))
@@ -4708,12 +4709,17 @@ ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
Constant *llvm::ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
Type *Ty) {
- return ConstantFoldScalarCall1("", ID, Ty, Op, nullptr, nullptr);
+ return ConstantFoldScalarCall1("", ID, Ty, Op);
}
Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty) {
- return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS}, nullptr);
+ return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS});
+}
+
+Constant *llvm::ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty) {
+ return ConstantFoldScalarCall("", ID, Ty, Ops);
}
Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index eac591af3f495..46a52d94ec7f4 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -966,7 +966,9 @@ Value *IRBuilderBase::CreateIntrinsic(Intrinsic::ID ID,
FMFSource FMFSource, const Twine &Name,
ArrayRef<OperandBundleDef> OpBundles,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ Type *RetTy = Intrinsic::getType(Context, ID, OverloadTypes)->getReturnType();
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI = CreateIntrinsicWithoutFolding(ID, OverloadTypes, Args,
FMFSource, Name, OpBundles);
SetFn(CI);
@@ -977,7 +979,8 @@ Value *IRBuilderBase::CreateIntrinsic(Type *RetTy, Intrinsic::ID ID,
ArrayRef<Value *> Args,
FMFSource FMFSource, const Twine &Name,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI =
CreateIntrinsicWithoutFolding(RetTy, ID, Args, FMFSource, Name);
SetFn(CI);
diff --git a/llvm/test/Transforms/IRCE/correct-loop-info.ll b/llvm/test/Transforms/IRCE/correct-loop-info.ll
index c75de167681ad..7ea445718289a 100644
--- a/llvm/test/Transforms/IRCE/correct-loop-info.ll
+++ b/llvm/test/Transforms/IRCE/correct-loop-info.ll
@@ -13,33 +13,30 @@ source_filename = "correct-loop-info.ll"
define void @baz() personality ptr @ham {
; CHECK-LABEL: @baz(
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 -1)
-; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 0)
; CHECK-NEXT: br label [[OUTERHEADER:%.*]]
; CHECK: outerheader:
; CHECK-NEXT: [[TMP:%.*]] = icmp slt i32 undef, 84
; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB16:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 undef, [[EXIT_PRELOOP_AT]]
-; CHECK-NEXT: br i1 [[TMP0]], label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
+; CHECK-NEXT: br i1 false, label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preloop.preheader:
; CHECK-NEXT: br label [[INNERHEADER_PRELOOP:%.*]]
; CHECK: mainloop:
-; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], [[EXIT_MAINLOOP_AT]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], 2147483647
; CHECK-NEXT: br i1 [[TMP1]], label [[INNERHEADER_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preheader:
; CHECK-NEXT: br label [[INNERHEADER:%.*]]
; CHECK: innerheader:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP6:%.*]], [[BB8:%.*]] ], [ [[TMP4_PRELOOP_COPY:%.*]], [[INNERHEADER_PREHEADER]] ]
; CHECK-NEXT: invoke void @pluto()
-; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
+; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
; CHECK: bb5:
; CHECK-NEXT: [[TMP6]] = add nsw i32 [[TMP4]], 1
; CH...
[truncated]
|
|
@llvm/pr-subscribers-backend-risc-v Author: Ramkumar Ramachandra (artagnon) ChangesIncludes changes to guard against a nullptr TLI and Call. TargetFold or InstSimplify fold in IRBuilderBase::CreateIntrinsic, in the same way we fold in Create(Unary|Binary)Intrinsic. Patch is 38.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/204967.diff 18 Files Affected:
diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h
index 2f7a327e1652a..f223ebf0586f4 100644
--- a/llvm/include/llvm/Analysis/ConstantFolding.h
+++ b/llvm/include/llvm/Analysis/ConstantFolding.h
@@ -175,6 +175,9 @@ LLVM_ABI Constant *ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
LLVM_ABI Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty);
+LLVM_ABI Constant *ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty);
+
/// ConstantFoldLoadThroughBitcast - try to cast constant to destination type
/// returning null if unsuccessful. Can cast pointer to pointer or pointer to
/// integer and vice versa if their sizes are equal.
diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index a8dff839de214..93cf827750528 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -132,6 +132,11 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
return simplifyBinaryIntrinsic(ID, Ty, LHS, RHS, FMF, SQ);
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return simplifyIntrinsic(ID, Ty, Ops, FMF, SQ);
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index 0a9d9c3d88111..74d8ac3f1fc1f 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -19,6 +19,7 @@
#define LLVM_ANALYSIS_TARGETFOLDER_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/IR/ConstantFold.h"
#include "llvm/IR/Constants.h"
@@ -207,6 +208,15 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ auto COps =
+ map_to_vector(Ops, [](Value *Op) { return dyn_cast<Constant>(Op); });
+ if (none_of(COps, equal_to(nullptr)))
+ return ConstantFoldIntrinsic(ID, COps, Ty);
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index b2937c2339ca7..c47a990650f68 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -194,6 +194,12 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ // Use TargetFolder or InstSimplifyFolder instead.
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index e68fff29b7165..1699845b22466 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -76,13 +76,15 @@ class LLVM_ABI IRBuilderFolder {
virtual Value *FoldCast(Instruction::CastOps Op, Value *V,
Type *DestTy) const = 0;
- virtual Value *
- FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldUnaryIntrinsic(Intrinsic::ID ID, Value *Op, Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
- virtual Value *
- FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
- FastMathFlags FMF = FastMathFlags()) const = 0;
+ virtual Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS,
+ Type *Ty,
+ FastMathFlags FMF = {}) const = 0;
+
+ virtual Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops,
+ Type *Ty, FastMathFlags FMF = {}) const = 0;
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index a86cbf724e69f..5ba098d5cddf4 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -124,6 +124,11 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
return nullptr;
}
+ Value *FoldIntrinsic(Intrinsic::ID ID, ArrayRef<Value *> Ops, Type *Ty,
+ FastMathFlags FMF) const override {
+ return nullptr;
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index f18b7a0b66a21..aba7492de9179 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2489,13 +2489,13 @@ getEvaluationRoundingMode(const ConstrainedFPIntrinsic *CI) {
}
/// Try to constant fold llvm.canonicalize for the given caller and value.
-static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
- const APFloat &Src) {
+static Constant *constantFoldCanonicalize(const Type *Ty, const APFloat &Src,
+ const Function *CtxF = nullptr) {
// Zero, positive and negative, is always OK to fold.
if (Src.isZero()) {
// Get a fresh 0, since ppc_fp128 does have non-canonical zeros.
return ConstantFP::get(
- CI->getContext(),
+ Ty->getContext(),
APFloat::getZero(Src.getSemantics(), Src.isNegative()));
}
@@ -2507,14 +2507,13 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
// Denorms and nans may have special encodings, but it should be OK to fold a
// totally average number.
if (Src.isNormal() || Src.isInfinity())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
- if (Src.isDenormal() && CI->getParent() && CI->getFunction()) {
- DenormalMode DenormMode =
- CI->getFunction()->getDenormalMode(Src.getSemantics());
+ if (Src.isDenormal() && CtxF) {
+ DenormalMode DenormMode = CtxF->getDenormalMode(Src.getSemantics());
if (DenormMode == DenormalMode::getIEEE())
- return ConstantFP::get(CI->getContext(), Src);
+ return ConstantFP::get(Ty->getContext(), Src);
if (DenormMode.Input == DenormalMode::Dynamic)
return nullptr;
@@ -2531,7 +2530,7 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
(DenormMode.Output == DenormalMode::PositiveZero &&
DenormMode.Input == DenormalMode::IEEE));
- return ConstantFP::get(CI->getContext(),
+ return ConstantFP::get(Ty->getContext(),
APFloat::getZero(Src.getSemantics(), !IsPositive));
}
@@ -2539,11 +2538,10 @@ static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
}
static Constant *ConstantFoldScalarCall1(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 1 && "Wrong number of operands.");
if (IntrinsicID == Intrinsic::is_constant) {
@@ -2580,7 +2578,7 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// a function during inlining), Call's caller may not be available.
// So check Call's BB first before querying Call->getCaller.
const Function *Caller =
- Call->getParent() ? Call->getCaller() : nullptr;
+ Call && Call->getParent() ? Call->getCaller() : nullptr;
if (Caller &&
!NullPointerIsDefined(
Caller, Operands[0]->getType()->getPointerAddressSpace())) {
@@ -2622,8 +2620,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantInt::get(Ty, Int);
}
- if (IntrinsicID == Intrinsic::canonicalize)
- return constantFoldCanonicalize(Ty, Call, U);
+ if (IntrinsicID == Intrinsic::canonicalize) {
+ const Function *CtxF =
+ Call && Call->getParent() ? Call->getFunction() : nullptr;
+ return constantFoldCanonicalize(Ty, U, CtxF);
+ }
#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128)
if (Ty->isFP128Ty()) {
@@ -2697,48 +2698,49 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
// Rounding operations (floor, trunc, ceil, round and nearbyint) do not
// raise FP exceptions, unless the argument is signaling NaN.
- std::optional<APFloat::roundingMode> RM;
- switch (IntrinsicID) {
- default:
- break;
- case Intrinsic::experimental_constrained_nearbyint:
- case Intrinsic::experimental_constrained_rint: {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- RM = CI->getRoundingMode();
- if (!RM || *RM == RoundingMode::Dynamic)
- return nullptr;
- break;
- }
- case Intrinsic::experimental_constrained_round:
- RM = APFloat::rmNearestTiesToAway;
- break;
- case Intrinsic::experimental_constrained_ceil:
- RM = APFloat::rmTowardPositive;
- break;
- case Intrinsic::experimental_constrained_floor:
- RM = APFloat::rmTowardNegative;
- break;
- case Intrinsic::experimental_constrained_trunc:
- RM = APFloat::rmTowardZero;
- break;
- }
- if (RM) {
- auto CI = cast<ConstrainedFPIntrinsic>(Call);
- if (U.isFinite()) {
- APFloat::opStatus St = U.roundToIntegral(*RM);
- if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
- St == APFloat::opInexact) {
+ if (auto *CI = dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
+ std::optional<APFloat::roundingMode> RM;
+ switch (IntrinsicID) {
+ default:
+ break;
+ case Intrinsic::experimental_constrained_nearbyint:
+ case Intrinsic::experimental_constrained_rint: {
+ RM = CI->getRoundingMode();
+ if (!RM || *RM == RoundingMode::Dynamic)
+ return nullptr;
+ break;
+ }
+ case Intrinsic::experimental_constrained_round:
+ RM = APFloat::rmNearestTiesToAway;
+ break;
+ case Intrinsic::experimental_constrained_ceil:
+ RM = APFloat::rmTowardPositive;
+ break;
+ case Intrinsic::experimental_constrained_floor:
+ RM = APFloat::rmTowardNegative;
+ break;
+ case Intrinsic::experimental_constrained_trunc:
+ RM = APFloat::rmTowardZero;
+ break;
+ }
+ if (RM) {
+ if (U.isFinite()) {
+ APFloat::opStatus St = U.roundToIntegral(*RM);
+ if (IntrinsicID == Intrinsic::experimental_constrained_rint &&
+ St == APFloat::opInexact) {
+ std::optional<fp::ExceptionBehavior> EB =
+ CI->getExceptionBehavior();
+ if (EB == fp::ebStrict)
+ return nullptr;
+ }
+ } else if (U.isSignaling()) {
std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB == fp::ebStrict)
+ if (EB && *EB != fp::ebIgnore)
return nullptr;
+ U = APFloat::getQNaN(U.getSemantics());
}
- } else if (U.isSignaling()) {
- std::optional<fp::ExceptionBehavior> EB = CI->getExceptionBehavior();
- if (EB && *EB != fp::ebIgnore)
- return nullptr;
- U = APFloat::getQNaN(U.getSemantics());
+ return ConstantFP::get(Ty, U);
}
- return ConstantFP::get(Ty, U);
}
// NVVM float/double to signed/unsigned int32/int64 conversions:
@@ -3350,7 +3352,7 @@ static Constant *ConstantFoldNextToward(const APFloat &Op0, const APFloat &Op1,
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI = nullptr) {
if (!TLI)
return nullptr;
@@ -3421,7 +3423,7 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const CallBase *Call) {
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 2 && "Wrong number of operands.");
if (Ty->isFloatingPointTy()) {
@@ -4098,11 +4100,10 @@ static Constant *ConstantFoldAMDGCNPermIntrinsic(ArrayRef<Constant *> Operands,
}
static Constant *ConstantFoldScalarCall3(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
assert(Operands.size() == 3 && "Wrong number of operands.");
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
@@ -4112,7 +4113,8 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
const APFloat &C2 = Op2->getValueAPF();
const APFloat &C3 = Op3->getValueAPF();
- if (const auto *ConstrIntr = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
+ if (const auto *ConstrIntr =
+ dyn_cast_or_null<ConstrainedFPIntrinsic>(Call)) {
RoundingMode RM = getEvaluationRoundingMode(ConstrIntr);
APFloat Res = C1;
APFloat::opStatus St;
@@ -4262,11 +4264,10 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
}
static Constant *ConstantFoldScalarCall(StringRef Name,
- Intrinsic::ID IntrinsicID,
- Type *Ty,
+ Intrinsic::ID IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
- const TargetLibraryInfo *TLI,
- const CallBase *Call) {
+ const TargetLibraryInfo *TLI = nullptr,
+ const CallBase *Call = nullptr) {
if (IntrinsicID != Intrinsic::not_intrinsic &&
any_of(Operands, IsaPred<PoisonValue>) &&
intrinsicPropagatesPoison(IntrinsicID))
@@ -4708,12 +4709,17 @@ ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
Constant *llvm::ConstantFoldUnaryIntrinsic(Intrinsic::ID ID, Constant *Op,
Type *Ty) {
- return ConstantFoldScalarCall1("", ID, Ty, Op, nullptr, nullptr);
+ return ConstantFoldScalarCall1("", ID, Ty, Op);
}
Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
Constant *RHS, Type *Ty) {
- return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS}, nullptr);
+ return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS});
+}
+
+Constant *llvm::ConstantFoldIntrinsic(Intrinsic::ID ID,
+ ArrayRef<Constant *> Ops, Type *Ty) {
+ return ConstantFoldScalarCall("", ID, Ty, Ops);
}
Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index eac591af3f495..46a52d94ec7f4 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -966,7 +966,9 @@ Value *IRBuilderBase::CreateIntrinsic(Intrinsic::ID ID,
FMFSource FMFSource, const Twine &Name,
ArrayRef<OperandBundleDef> OpBundles,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ Type *RetTy = Intrinsic::getType(Context, ID, OverloadTypes)->getReturnType();
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI = CreateIntrinsicWithoutFolding(ID, OverloadTypes, Args,
FMFSource, Name, OpBundles);
SetFn(CI);
@@ -977,7 +979,8 @@ Value *IRBuilderBase::CreateIntrinsic(Type *RetTy, Intrinsic::ID ID,
ArrayRef<Value *> Args,
FMFSource FMFSource, const Twine &Name,
function_ref<void(CallInst *)> SetFn) {
- // TODO: Try to constant-fold.
+ if (Value *V = Folder.FoldIntrinsic(ID, Args, RetTy, FMFSource.get(FMF)))
+ return V;
CallInst *CI =
CreateIntrinsicWithoutFolding(RetTy, ID, Args, FMFSource, Name);
SetFn(CI);
diff --git a/llvm/test/Transforms/IRCE/correct-loop-info.ll b/llvm/test/Transforms/IRCE/correct-loop-info.ll
index c75de167681ad..7ea445718289a 100644
--- a/llvm/test/Transforms/IRCE/correct-loop-info.ll
+++ b/llvm/test/Transforms/IRCE/correct-loop-info.ll
@@ -13,33 +13,30 @@ source_filename = "correct-loop-info.ll"
define void @baz() personality ptr @ham {
; CHECK-LABEL: @baz(
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[EXIT_PRELOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 -1)
-; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = call i32 @llvm.smax.i32(i32 undef, i32 0)
; CHECK-NEXT: br label [[OUTERHEADER:%.*]]
; CHECK: outerheader:
; CHECK-NEXT: [[TMP:%.*]] = icmp slt i32 undef, 84
; CHECK-NEXT: br i1 [[TMP]], label [[BB2:%.*]], label [[BB16:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 undef, [[EXIT_PRELOOP_AT]]
-; CHECK-NEXT: br i1 [[TMP0]], label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
+; CHECK-NEXT: br i1 false, label [[INNERHEADER_PRELOOP_PREHEADER:%.*]], label [[PRELOOP_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preloop.preheader:
; CHECK-NEXT: br label [[INNERHEADER_PRELOOP:%.*]]
; CHECK: mainloop:
-; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], [[EXIT_MAINLOOP_AT]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[INDVAR_END:%.*]], 2147483647
; CHECK-NEXT: br i1 [[TMP1]], label [[INNERHEADER_PREHEADER:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]]
; CHECK: innerheader.preheader:
; CHECK-NEXT: br label [[INNERHEADER:%.*]]
; CHECK: innerheader:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP6:%.*]], [[BB8:%.*]] ], [ [[TMP4_PRELOOP_COPY:%.*]], [[INNERHEADER_PREHEADER]] ]
; CHECK-NEXT: invoke void @pluto()
-; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
+; CHECK-NEXT: to label [[BB5:%.*]] unwind label [[OUTER_EXITING_LOOPEXIT_SPLIT_LP_LOOPEXIT_SPLIT_LP:%.*]]
; CHECK: bb5:
; CHECK-NEXT: [[TMP6]] = add nsw i32 [[TMP4]], 1
; CH...
[truncated]
|
dtcxzyw
left a comment
There was a problem hiding this comment.
LGTM. I checked the logic and it looks fine. No crashes reported by llvm-opt-benchmark. I cannot run fuzzing tests with csmith because I have a running experiment on the machine :)
Please wait for additional approval from other reviewers.
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
You can test this locally with the following command:git diff -U0 --pickaxe-regex -S '([^a-zA-Z0-9#_-]undef([^a-zA-Z0-9_-]|$)|UndefValue::get)' 'HEAD~1' HEAD llvm/include/llvm/Analysis/ConstantFolding.h llvm/include/llvm/Analysis/InstSimplifyFolder.h llvm/include/llvm/Analysis/InstructionSimplify.h llvm/include/llvm/Analysis/TargetFolder.h llvm/include/llvm/IR/ConstantFolder.h llvm/include/llvm/IR/IRBuilderFolder.h llvm/include/llvm/IR/NoFolder.h llvm/lib/Analysis/ConstantFolding.cpp llvm/lib/Analysis/InstructionSimplify.cpp llvm/lib/IR/IRBuilder.cpp llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp llvm/test/CodeGen/VE/Scalar/atomic.ll llvm/test/CodeGen/VE/Scalar/atomic_cmp_swap.ll llvm/test/Transforms/IRCE/correct-loop-info.ll llvm/test/Transforms/IndVarSimplify/lcssa-preservation.ll llvm/test/Transforms/LoopUnroll/runtime-loop-multiexit-dom-verify.ll llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll llvm/test/Transforms/LoopVectorize/trip-count-expansion-may-introduce-ub.ll llvm/test/Transforms/LoopVectorize/version-mem-access.ll llvm/test/Transforms/VectorCombine/AArch64/shuffle-of-intrinsics.ll llvm/test/Transforms/VectorCombine/AArch64/shuffletoidentity.ll llvm/test/Transforms/VectorCombine/RISCV/shuffle-of-intrinsics.ll llvm/test/Transforms/VectorCombine/X86/shuffle-of-intrinsics.ll polly/test/CodeGen/scop_expander_insert_point.llThe following files introduce new uses of undef:
Undef is now deprecated and should only be used in the rare cases where no replacement is possible. For example, a load of uninitialized memory yields In tests, avoid using For example, this is considered a bad practice: define void @fn() {
...
br i1 undef, ...
}Please use the following instead: define void @fn(i1 %cond) {
...
br i1 %cond, ...
}Please refer to the Undefined Behavior Manual for more information. |
| #define LLVM_ANALYSIS_TARGETFOLDER_H | ||
|
|
||
| #include "llvm/ADT/ArrayRef.h" | ||
| #include "llvm/ADT/SmallVectorExtras.h" |
| ; | ||
| entry: | ||
| %2 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %0, i32 0) | ||
| %3 = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %1, i32 0) |
There was a problem hiding this comment.
Should probably change the argument here so it doesn't fold awy? I don't think it tests what it's intended to otherwise.
| ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <4 x float> [[TMP0:%.*]], <4 x float> [[TMP1:%.*]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = call <8 x i1> @llvm.is.fpclass.v8f32(<8 x float> [[TMP2]], i32 0) | ||
| ; CHECK-NEXT: ret <8 x i1> [[TMP3]] | ||
| ; CHECK-NEXT: ret <8 x i1> zeroinitializer |
There was a problem hiding this comment.
Similar here (and the other is.fpclass 0 uses).
9192357 to
173e781
Compare
Includes changes to guard against a nullptr TLI and Call. TargetFold or InstSimplify fold in IRBuilderBase::CreateIntrinsic, in the same way we fold in Create(Unary|Binary)Intrinsic.