aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/Constants.cpp
diff options
context:
space:
mode:
authorJoshua Cao <cao.joshua@yahoo.com>2023-12-04 22:35:59 -0800
committerGitHub <noreply@github.com>2023-12-04 22:35:59 -0800
commit72ffaa915623e337abb5c689b5087d7e1d4477ae (patch)
tree32ac78aa8e8e4051ad431c36fead276587609fed /llvm/lib/IR/Constants.cpp
parent1334030f12e8f33a28167d32c51ca956634ec5f7 (diff)
downloadllvm-72ffaa915623e337abb5c689b5087d7e1d4477ae.zip
llvm-72ffaa915623e337abb5c689b5087d7e1d4477ae.tar.gz
llvm-72ffaa915623e337abb5c689b5087d7e1d4477ae.tar.bz2
[IR][TRE] Support associative intrinsics (#74226)
There is support for intrinsics in Instruction::isCommunative, but there is no equivalent implementation for isAssociative. This patch builds support for associative intrinsics with TRE as an application. TRE can now have associative intrinsics as an accumulator. For example: ``` struct Node { Node *next; unsigned val; } unsigned maxval(struct Node *n) { if (!n) return 0; return std::max(n->val, maxval(n->next)); } ``` Can be transformed into: ``` unsigned maxval(struct Node *n) { struct Node *head = n; unsigned max = 0; // Identity of unsigned std::max while (true) { if (!head) return max; max = std::max(max, head->val); head = head->next; } return max; } ``` This example results in about 5x speedup in local runs. We conservatively only consider min/max and as associative for this patch to limit testing scope. There are probably other intrinsics that could be considered associative. There are a few consumers of isAssociative() that could be impacted. Testing has only required to Reassociate pass be updated.
Diffstat (limited to 'llvm/lib/IR/Constants.cpp')
-rw-r--r--llvm/lib/IR/Constants.cpp26
1 files changed, 26 insertions, 0 deletions
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index bc55d5b..a38b912 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -2556,6 +2556,32 @@ Constant *ConstantExpr::getBinOpIdentity(unsigned Opcode, Type *Ty,
}
}
+Constant *ConstantExpr::getIntrinsicIdentity(Intrinsic::ID ID, Type *Ty) {
+ switch (ID) {
+ case Intrinsic::umax:
+ return Constant::getNullValue(Ty);
+ case Intrinsic::umin:
+ return Constant::getAllOnesValue(Ty);
+ case Intrinsic::smax:
+ return Constant::getIntegerValue(
+ Ty, APInt::getSignedMinValue(Ty->getIntegerBitWidth()));
+ case Intrinsic::smin:
+ return Constant::getIntegerValue(
+ Ty, APInt::getSignedMaxValue(Ty->getIntegerBitWidth()));
+ default:
+ return nullptr;
+ }
+}
+
+Constant *ConstantExpr::getIdentity(Instruction *I, Type *Ty,
+ bool AllowRHSConstant, bool NSZ) {
+ if (I->isBinaryOp())
+ return getBinOpIdentity(I->getOpcode(), Ty, AllowRHSConstant, NSZ);
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
+ return getIntrinsicIdentity(II->getIntrinsicID(), Ty);
+ return nullptr;
+}
+
Constant *ConstantExpr::getBinOpAbsorber(unsigned Opcode, Type *Ty) {
switch (Opcode) {
default: