-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[SandboxVec][DAG] MemDGNode for memory-dependency candidate nodes #109684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: vporpo (vporpo) ChangesThis patch adds DGNode member functions for visiting them in program order.
Full diff: https://github.com/llvm/llvm-project/pull/109684.diff 3 Files Affected:
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index 75b2073d0557c5..c040c00b68220e 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -29,6 +29,8 @@
namespace llvm::sandboxir {
+class DependencyGraph;
+
/// A DependencyGraph Node that points to an Instruction and contains memory
/// dependency edges.
class DGNode {
@@ -45,6 +47,7 @@ class DGNode {
(isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca()) ||
I->isStackSaveOrRestoreIntrinsic();
}
+ DGNode(const DGNode &Other) = delete;
Instruction *getInstruction() const { return I; }
void addMemPred(DGNode *PredN) { MemPreds.insert(PredN); }
/// \Returns all memory dependency predecessors.
@@ -56,6 +59,19 @@ class DGNode {
/// \Returns true if this may read/write memory, or if it has some ordering
/// constraings, like with stacksave/stackrestore and alloca/inalloca.
bool isMem() const { return IsMem; }
+ /// \Returns the previous DGNode in program order.
+ DGNode *getPrev(DependencyGraph &DAG) const;
+ /// \Returns the next DGNode in program order.
+ DGNode *getNext(DependencyGraph &DAG) const;
+ /// Walks up the instruction chain looking for the next memory dependency
+ /// candidate instruction.
+ /// \Returns the corresponding DAG Node, or null if no instruction found.
+ DGNode *getPrevMem(DependencyGraph &DAG) const;
+ /// Walks down the instr chain looking for the next memory dependency
+ /// candidate instruction.
+ /// \Returns the corresponding DAG Node, or null if no instruction found.
+ DGNode *getNextMem(DependencyGraph &DAG) const;
+
#ifndef NDEBUG
void print(raw_ostream &OS, bool PrintDeps = true) const;
friend raw_ostream &operator<<(DGNode &N, raw_ostream &OS) {
@@ -66,9 +82,73 @@ class DGNode {
#endif // NDEBUG
};
+/// Walks in the order of the instruction chain but skips non-mem Nodes.
+/// This is used for building/updating the DAG.
+class MemDGNodeIterator {
+ DGNode *N;
+ DependencyGraph *DAG;
+
+public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = DGNode;
+ using pointer = value_type *;
+ using reference = value_type &;
+ using iterator_category = std::bidirectional_iterator_tag;
+ MemDGNodeIterator(DGNode *N, DependencyGraph *DAG) : N(N), DAG(DAG) {
+ assert((N == nullptr || N->isMem()) && "Expects mem node!");
+ }
+ MemDGNodeIterator &operator++() {
+ assert(N != nullptr && "Already at end!");
+ N = N->getNextMem(*DAG);
+ return *this;
+ }
+ MemDGNodeIterator operator++(int) {
+ auto ItCopy = *this;
+ ++*this;
+ return ItCopy;
+ }
+ MemDGNodeIterator &operator--() {
+ N = N->getPrevMem(*DAG);
+ return *this;
+ }
+ MemDGNodeIterator operator--(int) {
+ auto ItCopy = *this;
+ --*this;
+ return ItCopy;
+ }
+ pointer operator*() { return N; }
+ const DGNode *operator*() const { return N; }
+ bool operator==(const MemDGNodeIterator &Other) const { return N == Other.N; }
+ bool operator!=(const MemDGNodeIterator &Other) const {
+ return !(*this == Other);
+ }
+};
+
+/// A MemDGNodeIterator with convenience builders and dump().
+class DGNodeRange : public iterator_range<MemDGNodeIterator> {
+public:
+ DGNodeRange(MemDGNodeIterator Begin, MemDGNodeIterator End)
+ : iterator_range(Begin, End) {}
+ /// An empty range.
+ DGNodeRange()
+ : iterator_range(MemDGNodeIterator(nullptr, nullptr),
+ MemDGNodeIterator(nullptr, nullptr)) {}
+ /// Given \p TopN and \p BotN it finds their closest mem nodes in the range
+ /// TopN to BotN and returns the corresponding mem range.
+ /// Note: BotN (or its neighboring mem node) is included in the range.
+ static DGNodeRange makeMemRange(DGNode *TopN, DGNode *BotN,
+ DependencyGraph &DAG);
+ static DGNodeRange makeEmptyMemRange() { return DGNodeRange(); }
+#ifndef NDEBUG
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
class DependencyGraph {
private:
DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
+ /// The DAG spans across all instructions in this interval.
+ InstrInterval DAGInterval;
public:
DependencyGraph() {}
@@ -77,6 +157,12 @@ class DependencyGraph {
auto It = InstrToNodeMap.find(I);
return It != InstrToNodeMap.end() ? It->second.get() : nullptr;
}
+ /// Like getNode() but returns nullptr if \p I is nullptr.
+ DGNode *getNodeOrNull(Instruction *I) const {
+ if (I == nullptr)
+ return nullptr;
+ return getNode(I);
+ }
DGNode *getOrCreateNode(Instruction *I) {
auto [It, NotInMap] = InstrToNodeMap.try_emplace(I);
if (NotInMap)
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
index 139e581ce03d96..58545df8f456e7 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
@@ -11,6 +11,39 @@
using namespace llvm::sandboxir;
+// TODO: Move this to Utils once it lands.
+/// \Returns the previous memory-dependency-candidate instruction before \p I in
+/// the instruction stream.
+static llvm::sandboxir::Instruction *
+getPrevMemDepInst(llvm::sandboxir::Instruction *I) {
+ for (I = I->getPrevNode(); I != nullptr; I = I->getPrevNode())
+ if (I->isMemDepCandidate() || I->isStackSaveOrRestoreIntrinsic())
+ return I;
+ return nullptr;
+}
+/// \Returns the next memory-dependency-candidate instruction after \p I in the
+/// instruction stream.
+static llvm::sandboxir::Instruction *
+getNextMemDepInst(llvm::sandboxir::Instruction *I) {
+ for (I = I->getNextNode(); I != nullptr; I = I->getNextNode())
+ if (I->isMemDepCandidate() || I->isStackSaveOrRestoreIntrinsic())
+ return I;
+ return nullptr;
+}
+
+DGNode *DGNode::getPrev(DependencyGraph &DAG) const {
+ return DAG.getNodeOrNull(I->getPrevNode());
+}
+DGNode *DGNode::getNext(DependencyGraph &DAG) const {
+ return DAG.getNodeOrNull(I->getNextNode());
+}
+DGNode *DGNode::getPrevMem(DependencyGraph &DAG) const {
+ return DAG.getNodeOrNull(getPrevMemDepInst(I));
+}
+DGNode *DGNode::getNextMem(DependencyGraph &DAG) const {
+ return DAG.getNodeOrNull(getNextMemDepInst(I));
+}
+
#ifndef NDEBUG
void DGNode::print(raw_ostream &OS, bool PrintDeps) const {
I->dumpOS(OS);
@@ -31,6 +64,34 @@ void DGNode::dump() const {
}
#endif // NDEBUG
+DGNodeRange DGNodeRange::makeMemRange(DGNode *TopN, DGNode *BotN,
+ DependencyGraph &DAG) {
+ assert((TopN == BotN ||
+ TopN->getInstruction()->comesBefore(BotN->getInstruction())) &&
+ "Expected TopN before BotN!");
+ // If TopN/BotN are not mem-dep candidate nodes we need to walk down/up the
+ // chain and find the mem-dep ones.
+ DGNode *MemTopN = TopN;
+ DGNode *MemBotN = BotN;
+ while (!MemTopN->isMem() && MemTopN != MemBotN)
+ MemTopN = MemTopN->getNext(DAG);
+ while (!MemBotN->isMem() && MemBotN != MemTopN)
+ MemBotN = MemBotN->getPrev(DAG);
+ // If we couldn't find a mem node in range TopN - BotN then it's empty.
+ if (!MemTopN->isMem())
+ return {};
+ // Now that we have the mem-dep nodes, create and return the range.
+ return DGNodeRange(MemDGNodeIterator(MemTopN, &DAG),
+ MemDGNodeIterator(MemBotN->getNextMem(DAG), &DAG));
+}
+
+#ifndef NDEBUG
+void DGNodeRange::dump() const {
+ for (const DGNode *N : *this)
+ N->dump();
+}
+#endif // NDEBUG
+
InstrInterval DependencyGraph::extend(ArrayRef<Instruction *> Instrs) {
if (Instrs.empty())
return {};
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
index f6bfd097f20a4e..3c8e217264481c 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
@@ -113,3 +113,105 @@ define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0));
EXPECT_THAT(N2->memPreds(), testing::ElementsAre(N1));
}
+
+TEST_F(DependencyGraphTest, DGNode_getPrev_getNext_getPrevMem_getNextMem) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
+ store i8 %v0, ptr %ptr
+ add i8 %v0, %v0
+ store i8 %v1, ptr %ptr
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ auto It = BB->begin();
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Add = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+ sandboxir::DependencyGraph DAG;
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+
+ sandboxir::DGNode *S0N = DAG.getNode(S0);
+ sandboxir::DGNode *AddN = DAG.getNode(Add);
+ sandboxir::DGNode *S1N = DAG.getNode(S1);
+ sandboxir::DGNode *RetN = DAG.getNode(Ret);
+
+ EXPECT_EQ(S0N->getPrev(DAG), nullptr);
+ EXPECT_EQ(S0N->getNext(DAG), AddN);
+ EXPECT_EQ(S0N->getPrevMem(DAG), nullptr);
+ EXPECT_EQ(S0N->getNextMem(DAG), S1N);
+
+ EXPECT_EQ(AddN->getPrev(DAG), S0N);
+ EXPECT_EQ(AddN->getNext(DAG), S1N);
+ EXPECT_EQ(AddN->getPrevMem(DAG), S0N);
+ EXPECT_EQ(AddN->getNextMem(DAG), S1N);
+
+ EXPECT_EQ(S1N->getPrev(DAG), AddN);
+ EXPECT_EQ(S1N->getNext(DAG), RetN);
+ EXPECT_EQ(S1N->getPrevMem(DAG), S0N);
+ EXPECT_EQ(S1N->getNextMem(DAG), nullptr);
+
+ EXPECT_EQ(RetN->getPrev(DAG), S1N);
+ EXPECT_EQ(RetN->getNext(DAG), nullptr);
+ EXPECT_EQ(RetN->getPrevMem(DAG), S1N);
+ EXPECT_EQ(RetN->getNextMem(DAG), nullptr);
+}
+
+TEST_F(DependencyGraphTest, DGNodeRange) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
+ add i8 %v0, %v0
+ store i8 %v0, ptr %ptr
+ add i8 %v0, %v0
+ store i8 %v1, ptr %ptr
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ auto It = BB->begin();
+ auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+ sandboxir::DependencyGraph DAG;
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+
+ sandboxir::DGNode *Add0N = DAG.getNode(Add0);
+ sandboxir::DGNode *S0N = DAG.getNode(S0);
+ sandboxir::DGNode *Add1N = DAG.getNode(Add1);
+ sandboxir::DGNode *S1N = DAG.getNode(S1);
+ sandboxir::DGNode *RetN = DAG.getNode(Ret);
+
+ // Check empty range.
+ EXPECT_THAT(sandboxir::DGNodeRange::makeEmptyMemRange(),
+ testing::ElementsAre());
+
+ // Both TopN and BotN are memory.
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(S0N, S1N, DAG),
+ testing::ElementsAre(S0N, S1N));
+ // Only TopN is memory.
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(S0N, RetN, DAG),
+ testing::ElementsAre(S0N, S1N));
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(S0N, Add1N, DAG),
+ testing::ElementsAre(S0N));
+ // Only BotN is memory.
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(Add0N, S1N, DAG),
+ testing::ElementsAre(S0N, S1N));
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(Add0N, S0N, DAG),
+ testing::ElementsAre(S0N));
+ // Neither TopN or BotN is memory.
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(Add0N, RetN, DAG),
+ testing::ElementsAre(S0N, S1N));
+ EXPECT_THAT(sandboxir::DGNodeRange::makeMemRange(Add0N, Add0N, DAG),
+ testing::ElementsAre());
+}
|
You are upstreaming this because you have already experience with it and thought about the design. Two questions: how does it relate to MemorySSA and graph traits? |
It's not relying on MemorySSA for now, but we may switch to it at some point. |
I made a design change: There are now two DAG Node classes: |
ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor things, but mostly looks good.
@@ -66,9 +84,94 @@ class DGNode { | |||
#endif // NDEBUG | |||
}; | |||
|
|||
/// A DependencyGraph Node for instructiosn that may read/write memory, or have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instructions
(isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca()) || | ||
I->isStackSaveOrRestoreIntrinsic(); | ||
} | ||
|
||
Instruction *getInstruction() const { return I; } | ||
void addMemPred(DGNode *PredN) { MemPreds.insert(PredN); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this take a MemDGNode now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops I just saw this comments. Yes, I think this should be MemDGNode.
static bool classof(const DGNode *Other) { | ||
return Other->SubclassID == DGNodeID::MemDGNode; | ||
} | ||
/// \Returns the previosu Mem DGNode in instruction order. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
previous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
MemDGNode *NextMemN = nullptr; | ||
|
||
void setNextNode(DGNode *N) { NextMemN = cast_or_null<MemDGNode>(N); } | ||
void setPrevNode(DGNode *N) { PrevMemN = cast_or_null<MemDGNode>(N); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "cast_if_present" is the new hotness over cast_or_null.
How sure are we that these will always be MemDGNodes? And if we are sure, shouldn't it take MemDGNodes then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these should take a MemDGNode *
argument, let me change it.
/// \Returns true if \p I is a memory dependency candidate instruction. | ||
static bool isMemDepCandidate(Instruction *I) { | ||
return I->isMemDepCandidate() || | ||
(isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca()) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dyn_cast!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative is the following which is not as readable as the original code.
if (I->isMemDepCandidate())
return true;
auto *AllocaI = dyn_cast<AllocaInst>(I);
return AllocaI != nullptr ? AllocaI->isUsedWithInAlloca() || I->isStackSaveOrRestoreIntrinsic();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (I->isMemDepCandidate())
return true;
if (auto *AllocaI = dyn_cast<AllocaInst>(I))
if (AllocaI->isUsedWithInAlloca())
return true;
return I->isStackSaveOrRestoreIntrinsic();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the original one is much better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it is a violation of the coding style guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Note that you should not use an isa<> test followed by a cast<>, for that use the dyn_cast<> operator."
https://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can argue about the should
but ....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me start a thread on discourse about it. It would be good to know what the rest of the community thinks about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me change it to what @david-xl suggested in the thread, which is still readable but not too verbose:
AllocaInst *Alloca;
return I->isMemDepCandidate() ||
((Alloca = dyn_cast<AllocaInst>(I)) && Alloca->isUsedWithInAlloca()) ||
I->isStackSaveOrRestoreIntrinsic();
f2e8949
to
098cc79
Compare
I just realized I had pushed the version without the fix. |
Now that the Interval is available there is no need for the custom iterator that was implemented in this patch. I was planning to do this cleanup in the follow-up patch, but it's probably best to do this here since it simplifies the code of this patch a bit. |
Rebased and fixed typo |
ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions inline. This is very skeleton-like and some things are not clear where they're heading.
if (NotInMap) | ||
It->second = std::make_unique<DGNode>(I); | ||
if (NotInMap) { | ||
if (I->isMemDepCandidate() || I->isStackSaveOrRestoreIntrinsic()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These conditions shouldn't be the same as in the static isMemDepCandidate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I should have used the static function for the check.
/// Given \p Instrs it finds their closest mem nodes in the interval and | ||
/// returns the corresponding mem range. Note: BotN (or its neighboring mem | ||
/// node) is included in the range. | ||
static Interval<MemDGNode> make(const Interval<Instruction> &Instrs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate why you need both Interval and a DAG? The DAG has an interval inside. Are they different intervals, what's the usage for each?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interval describes a range of nodes in program order. This particular interval is going to be used as the range of nodes to be scanned for dependencies as we are building the DAG. The DAG's interval is the range of instructions that are represented by the DAG, it's only used to check if some instruction/node is inside or outside the DAG.
Instruction *MemTopI = Instrs.top(); | ||
Instruction *MemBotI = Instrs.bottom(); | ||
while (!DGNode::isMemDepCandidate(MemTopI) && MemTopI != MemBotI) | ||
MemTopI = MemTopI->getNextNode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm missing how getNextNode works for an Instruction here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just skip the non memory-candidate instructions. getNextNode() gives you the next instruction in the instruction list.
This patch implements the MemDGNode class for DAG nodes that are candidates for memory dependencies. These nodes form a chain that is accessible by `getPrevNode()` and `getNextNode()`. It also implements a builder class that creates MemDGNode intervals from Instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
return I->isMemDepCandidate() || | ||
((Alloca = dyn_cast<AllocaInst>(I)) && | ||
Alloca->isUsedWithInAlloca()) || | ||
I->isStackSaveOrRestoreIntrinsic(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't these checks be moved into isMemDepCandidate for sandboxir::Instruction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean in member function like sandboxir::Instruction::isMemDepCandidate()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chatted offline and resolving, keeping it here is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason why isMemDepCandidate()
and isStackSaveOrRestoreIntrinsic()
are in sandboxir::Instruction
is that they need to access LLVM IR, but the combined check does not need to. Also I don't think this check will be used in other places.
…odes (llvm#109684)" This reverts commit fd5e220.
…vm#109684) This patch implements the MemDGNode class for DAG nodes that are candidates for memory dependencies. These nodes form a chain that is accessible by `getPrevNode()` and `getNextNode()`. It also implements a builder class that creates MemDGNode intervals from Instructions.
This patch implements the MemDGNode class for DAG nodes that are candidates
for memory dependencies. These nodes form a chain that is accessible by
getPrevNode()
andgetNextNode()
.It also implements a builder class that creates MemDGNode intervals from
Instructions.