Skip to content

Commit 1411452

Browse files
authored
[IRBuilder] Fold binary intrinsics (#80743)
Fixes #61240.
1 parent 8ab0632 commit 1411452

16 files changed

+204
-125
lines changed

llvm/include/llvm/Analysis/ConstantFolding.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include <stdint.h>
2323

2424
namespace llvm {
25+
26+
namespace Intrinsic {
27+
using ID = unsigned;
28+
}
29+
2530
class APInt;
2631
template <typename T> class ArrayRef;
2732
class CallBase;
@@ -187,6 +192,10 @@ Constant *ConstantFoldCall(const CallBase *Call, Function *F,
187192
ArrayRef<Constant *> Operands,
188193
const TargetLibraryInfo *TLI = nullptr);
189194

195+
Constant *ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
196+
Constant *RHS, Type *Ty,
197+
Instruction *FMFSource);
198+
190199
/// ConstantFoldLoadThroughBitcast - try to cast constant to destination type
191200
/// returning null if unsuccessful. Can cast pointer to pointer or pointer to
192201
/// integer and vice versa if their sizes are equal.

llvm/include/llvm/Analysis/InstSimplifyFolder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ class InstSimplifyFolder final : public IRBuilderFolder {
117117
return simplifyCastInst(Op, V, DestTy, SQ);
118118
}
119119

120+
Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
121+
Instruction *FMFSource) const override {
122+
return simplifyBinaryIntrinsic(ID, Ty, LHS, RHS, SQ,
123+
dyn_cast_if_present<CallBase>(FMFSource));
124+
}
125+
120126
//===--------------------------------------------------------------------===//
121127
// Cast/Conversion Operators
122128
//===--------------------------------------------------------------------===//

llvm/include/llvm/Analysis/InstructionSimplify.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ Value *simplifyExtractElementInst(Value *Vec, Value *Idx,
186186
Value *simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
187187
const SimplifyQuery &Q);
188188

189+
/// Given operands for a BinaryIntrinsic, fold the result or return null.
190+
Value *simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, Value *Op0,
191+
Value *Op1, const SimplifyQuery &Q,
192+
const CallBase *Call);
193+
189194
/// Given operands for a ShuffleVectorInst, fold the result or return null.
190195
/// See class ShuffleVectorInst for a description of the mask representation.
191196
Value *simplifyShuffleVectorInst(Value *Op0, Value *Op1, ArrayRef<int> Mask,

llvm/include/llvm/Analysis/TargetFolder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ class TargetFolder final : public IRBuilderFolder {
191191
return nullptr;
192192
}
193193

194+
Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
195+
Instruction *FMFSource) const override {
196+
auto *C1 = dyn_cast<Constant>(LHS);
197+
auto *C2 = dyn_cast<Constant>(RHS);
198+
if (C1 && C2)
199+
return ConstantFoldBinaryIntrinsic(ID, C1, C2, Ty, FMFSource);
200+
return nullptr;
201+
}
202+
194203
//===--------------------------------------------------------------------===//
195204
// Cast/Conversion Operators
196205
//===--------------------------------------------------------------------===//

llvm/include/llvm/IR/ConstantFolder.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
#include "llvm/ADT/ArrayRef.h"
2020
#include "llvm/ADT/STLExtras.h"
21-
#include "llvm/IR/Constants.h"
2221
#include "llvm/IR/ConstantFold.h"
22+
#include "llvm/IR/Constants.h"
2323
#include "llvm/IR/IRBuilderFolder.h"
2424
#include "llvm/IR/Instruction.h"
2525
#include "llvm/IR/Operator.h"
@@ -89,7 +89,7 @@ class ConstantFolder final : public IRBuilderFolder {
8989
}
9090

9191
Value *FoldUnOpFMF(Instruction::UnaryOps Opc, Value *V,
92-
FastMathFlags FMF) const override {
92+
FastMathFlags FMF) const override {
9393
if (Constant *C = dyn_cast<Constant>(V))
9494
return ConstantFoldUnaryInstruction(Opc, C);
9595
return nullptr;
@@ -183,6 +183,12 @@ class ConstantFolder final : public IRBuilderFolder {
183183
return nullptr;
184184
}
185185

186+
Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
187+
Instruction *FMFSource) const override {
188+
// Use TargetFolder or InstSimplifyFolder instead.
189+
return nullptr;
190+
}
191+
186192
//===--------------------------------------------------------------------===//
187193
// Cast/Conversion Operators
188194
//===--------------------------------------------------------------------===//

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,9 @@ class IRBuilderBase {
962962

963963
/// Create a call to intrinsic \p ID with 2 operands which is mangled on the
964964
/// first type.
965-
CallInst *CreateBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS,
966-
Instruction *FMFSource = nullptr,
967-
const Twine &Name = "");
965+
Value *CreateBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS,
966+
Instruction *FMFSource = nullptr,
967+
const Twine &Name = "");
968968

969969
/// Create a call to intrinsic \p ID with \p Args, mangled using \p Types. If
970970
/// \p FMFSource is provided, copy fast-math-flags from that instruction to
@@ -983,7 +983,7 @@ class IRBuilderBase {
983983
const Twine &Name = "");
984984

985985
/// Create call to the minnum intrinsic.
986-
CallInst *CreateMinNum(Value *LHS, Value *RHS, const Twine &Name = "") {
986+
Value *CreateMinNum(Value *LHS, Value *RHS, const Twine &Name = "") {
987987
if (IsFPConstrained) {
988988
return CreateConstrainedFPUnroundedBinOp(
989989
Intrinsic::experimental_constrained_minnum, LHS, RHS, nullptr, Name);
@@ -993,7 +993,7 @@ class IRBuilderBase {
993993
}
994994

995995
/// Create call to the maxnum intrinsic.
996-
CallInst *CreateMaxNum(Value *LHS, Value *RHS, const Twine &Name = "") {
996+
Value *CreateMaxNum(Value *LHS, Value *RHS, const Twine &Name = "") {
997997
if (IsFPConstrained) {
998998
return CreateConstrainedFPUnroundedBinOp(
999999
Intrinsic::experimental_constrained_maxnum, LHS, RHS, nullptr, Name);
@@ -1003,19 +1003,19 @@ class IRBuilderBase {
10031003
}
10041004

10051005
/// Create call to the minimum intrinsic.
1006-
CallInst *CreateMinimum(Value *LHS, Value *RHS, const Twine &Name = "") {
1006+
Value *CreateMinimum(Value *LHS, Value *RHS, const Twine &Name = "") {
10071007
return CreateBinaryIntrinsic(Intrinsic::minimum, LHS, RHS, nullptr, Name);
10081008
}
10091009

10101010
/// Create call to the maximum intrinsic.
1011-
CallInst *CreateMaximum(Value *LHS, Value *RHS, const Twine &Name = "") {
1011+
Value *CreateMaximum(Value *LHS, Value *RHS, const Twine &Name = "") {
10121012
return CreateBinaryIntrinsic(Intrinsic::maximum, LHS, RHS, nullptr, Name);
10131013
}
10141014

10151015
/// Create call to the copysign intrinsic.
1016-
CallInst *CreateCopySign(Value *LHS, Value *RHS,
1017-
Instruction *FMFSource = nullptr,
1018-
const Twine &Name = "") {
1016+
Value *CreateCopySign(Value *LHS, Value *RHS,
1017+
Instruction *FMFSource = nullptr,
1018+
const Twine &Name = "") {
10191019
return CreateBinaryIntrinsic(Intrinsic::copysign, LHS, RHS, FMFSource,
10201020
Name);
10211021
}

llvm/include/llvm/IR/IRBuilderFolder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class IRBuilderFolder {
7373
virtual Value *FoldCast(Instruction::CastOps Op, Value *V,
7474
Type *DestTy) const = 0;
7575

76+
virtual Value *
77+
FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
78+
Instruction *FMFSource = nullptr) const = 0;
79+
7680
//===--------------------------------------------------------------------===//
7781
// Cast/Conversion Operators
7882
//===--------------------------------------------------------------------===//

llvm/include/llvm/IR/NoFolder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ class NoFolder final : public IRBuilderFolder {
112112
return nullptr;
113113
}
114114

115+
Value *FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
116+
Instruction *FMFSource) const override {
117+
return nullptr;
118+
}
119+
115120
//===--------------------------------------------------------------------===//
116121
// Cast/Conversion Operators
117122
//===--------------------------------------------------------------------===//

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 83 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2534,12 +2534,73 @@ static Constant *evaluateCompare(const APFloat &Op1, const APFloat &Op2,
25342534
return nullptr;
25352535
}
25362536

2537-
static Constant *ConstantFoldScalarCall2(StringRef Name,
2538-
Intrinsic::ID IntrinsicID,
2539-
Type *Ty,
2540-
ArrayRef<Constant *> Operands,
2541-
const TargetLibraryInfo *TLI,
2542-
const CallBase *Call) {
2537+
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
2538+
ArrayRef<Constant *> Operands,
2539+
const TargetLibraryInfo *TLI) {
2540+
if (!TLI)
2541+
return nullptr;
2542+
2543+
LibFunc Func = NotLibFunc;
2544+
if (!TLI->getLibFunc(Name, Func))
2545+
return nullptr;
2546+
2547+
const auto *Op1 = dyn_cast<ConstantFP>(Operands[0]);
2548+
if (!Op1)
2549+
return nullptr;
2550+
2551+
const auto *Op2 = dyn_cast<ConstantFP>(Operands[1]);
2552+
if (!Op2)
2553+
return nullptr;
2554+
2555+
const APFloat &Op1V = Op1->getValueAPF();
2556+
const APFloat &Op2V = Op2->getValueAPF();
2557+
2558+
switch (Func) {
2559+
default:
2560+
break;
2561+
case LibFunc_pow:
2562+
case LibFunc_powf:
2563+
case LibFunc_pow_finite:
2564+
case LibFunc_powf_finite:
2565+
if (TLI->has(Func))
2566+
return ConstantFoldBinaryFP(pow, Op1V, Op2V, Ty);
2567+
break;
2568+
case LibFunc_fmod:
2569+
case LibFunc_fmodf:
2570+
if (TLI->has(Func)) {
2571+
APFloat V = Op1->getValueAPF();
2572+
if (APFloat::opStatus::opOK == V.mod(Op2->getValueAPF()))
2573+
return ConstantFP::get(Ty->getContext(), V);
2574+
}
2575+
break;
2576+
case LibFunc_remainder:
2577+
case LibFunc_remainderf:
2578+
if (TLI->has(Func)) {
2579+
APFloat V = Op1->getValueAPF();
2580+
if (APFloat::opStatus::opOK == V.remainder(Op2->getValueAPF()))
2581+
return ConstantFP::get(Ty->getContext(), V);
2582+
}
2583+
break;
2584+
case LibFunc_atan2:
2585+
case LibFunc_atan2f:
2586+
// atan2(+/-0.0, +/-0.0) is known to raise an exception on some libm
2587+
// (Solaris), so we do not assume a known result for that.
2588+
if (Op1V.isZero() && Op2V.isZero())
2589+
return nullptr;
2590+
[[fallthrough]];
2591+
case LibFunc_atan2_finite:
2592+
case LibFunc_atan2f_finite:
2593+
if (TLI->has(Func))
2594+
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
2595+
break;
2596+
}
2597+
2598+
return nullptr;
2599+
}
2600+
2601+
static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
2602+
ArrayRef<Constant *> Operands,
2603+
const CallBase *Call) {
25432604
assert(Operands.size() == 2 && "Wrong number of operands.");
25442605

25452606
if (Ty->isFloatingPointTy()) {
@@ -2569,7 +2630,8 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
25692630
return nullptr;
25702631
const APFloat &Op2V = Op2->getValueAPF();
25712632

2572-
if (const auto *ConstrIntr = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
2633+
if (const auto *ConstrIntr =
2634+
dyn_cast_if_present<ConstrainedFPIntrinsic>(Call)) {
25732635
RoundingMode RM = getEvaluationRoundingMode(ConstrIntr);
25742636
APFloat Res = Op1V;
25752637
APFloat::opStatus St;
@@ -2632,52 +2694,6 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
26322694
return ConstantFP::get(Ty->getContext(), Op1V * Op2V);
26332695
}
26342696

2635-
if (!TLI)
2636-
return nullptr;
2637-
2638-
LibFunc Func = NotLibFunc;
2639-
if (!TLI->getLibFunc(Name, Func))
2640-
return nullptr;
2641-
2642-
switch (Func) {
2643-
default:
2644-
break;
2645-
case LibFunc_pow:
2646-
case LibFunc_powf:
2647-
case LibFunc_pow_finite:
2648-
case LibFunc_powf_finite:
2649-
if (TLI->has(Func))
2650-
return ConstantFoldBinaryFP(pow, Op1V, Op2V, Ty);
2651-
break;
2652-
case LibFunc_fmod:
2653-
case LibFunc_fmodf:
2654-
if (TLI->has(Func)) {
2655-
APFloat V = Op1->getValueAPF();
2656-
if (APFloat::opStatus::opOK == V.mod(Op2->getValueAPF()))
2657-
return ConstantFP::get(Ty->getContext(), V);
2658-
}
2659-
break;
2660-
case LibFunc_remainder:
2661-
case LibFunc_remainderf:
2662-
if (TLI->has(Func)) {
2663-
APFloat V = Op1->getValueAPF();
2664-
if (APFloat::opStatus::opOK == V.remainder(Op2->getValueAPF()))
2665-
return ConstantFP::get(Ty->getContext(), V);
2666-
}
2667-
break;
2668-
case LibFunc_atan2:
2669-
case LibFunc_atan2f:
2670-
// atan2(+/-0.0, +/-0.0) is known to raise an exception on some libm
2671-
// (Solaris), so we do not assume a known result for that.
2672-
if (Op1V.isZero() && Op2V.isZero())
2673-
return nullptr;
2674-
[[fallthrough]];
2675-
case LibFunc_atan2_finite:
2676-
case LibFunc_atan2f_finite:
2677-
if (TLI->has(Func))
2678-
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
2679-
break;
2680-
}
26812697
} else if (auto *Op2C = dyn_cast<ConstantInt>(Operands[1])) {
26822698
switch (IntrinsicID) {
26832699
case Intrinsic::ldexp: {
@@ -3168,8 +3184,13 @@ static Constant *ConstantFoldScalarCall(StringRef Name,
31683184
if (Operands.size() == 1)
31693185
return ConstantFoldScalarCall1(Name, IntrinsicID, Ty, Operands, TLI, Call);
31703186

3171-
if (Operands.size() == 2)
3172-
return ConstantFoldScalarCall2(Name, IntrinsicID, Ty, Operands, TLI, Call);
3187+
if (Operands.size() == 2) {
3188+
if (Constant *FoldedLibCall =
3189+
ConstantFoldLibCall2(Name, Ty, Operands, TLI)) {
3190+
return FoldedLibCall;
3191+
}
3192+
return ConstantFoldIntrinsicCall2(IntrinsicID, Ty, Operands, Call);
3193+
}
31733194

31743195
if (Operands.size() == 3)
31753196
return ConstantFoldScalarCall3(Name, IntrinsicID, Ty, Operands, TLI, Call);
@@ -3376,6 +3397,13 @@ ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
33763397

33773398
} // end anonymous namespace
33783399

3400+
Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
3401+
Constant *RHS, Type *Ty,
3402+
Instruction *FMFSource) {
3403+
return ConstantFoldIntrinsicCall2(ID, Ty, {LHS, RHS},
3404+
dyn_cast_if_present<CallBase>(FMFSource));
3405+
}
3406+
33793407
Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
33803408
ArrayRef<Constant *> Operands,
33813409
const TargetLibraryInfo *TLI) {

0 commit comments

Comments
 (0)