-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[SandboxVec][DAG] Implement PredIterator #111604
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,10 +8,54 @@ | |
|
||
#include "llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h" | ||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/SandboxIR/Instruction.h" | ||
#include "llvm/SandboxIR/Utils.h" | ||
|
||
namespace llvm::sandboxir { | ||
|
||
PredIterator::value_type PredIterator::operator*() { | ||
// If it's a DGNode then we dereference the operand iterator. | ||
if (!isa<MemDGNode>(N)) { | ||
assert(OpIt != OpItE && "Can't dereference end iterator!"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This confuses me, when N is not a MemDGNode, there is no guarantee OpIt != OpItE. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it's a DGNode then the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I refactored this code too to make it more readable. |
||
return DAG->getNode(cast<Instruction>((Value *)*OpIt)); | ||
} | ||
// It's a MemDGNode, so we check if we return either the use-def operand, | ||
// or a mem predecessor. | ||
if (OpIt != OpItE) | ||
return DAG->getNode(cast<Instruction>((Value *)*OpIt)); | ||
assert(MemIt != cast<MemDGNode>(N)->memPreds().end() && | ||
"Cant' dereference end iterator!"); | ||
return *MemIt; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you simplify this code a bit for just more readability:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure I understand how you are going to be using this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The DAG only implements memory dependencies, but not use-def dependencies to save memory. This iterator hides this detail and provides a way to access all dependencies regardless of whether they are use-def or mem. This is useful for the scheduler who doesn't care about the nature of the dependency. |
||
|
||
PredIterator &PredIterator::operator++() { | ||
// If it's a DGNode then we increment the use-def iterator. | ||
if (!isa<MemDGNode>(N)) { | ||
assert(OpIt != OpItE && "Already at end!"); | ||
++OpIt; | ||
// Skip operands that are not instructions. | ||
OpIt = skipNonInstr(OpIt, OpItE); | ||
return *this; | ||
} | ||
// It's a MemDGNode, so if we are not at the end of the use-def iterator we | ||
// need to first increment that. | ||
if (OpIt != OpItE) { | ||
++OpIt; | ||
// Skip operands that are not instructions. | ||
OpIt = skipNonInstr(OpIt, OpItE); | ||
return *this; | ||
} | ||
assert(MemIt != cast<MemDGNode>(N)->memPreds().end() && "Already at end!"); | ||
++MemIt; | ||
return *this; | ||
} | ||
|
||
bool PredIterator::operator==(const PredIterator &Other) const { | ||
assert(DAG == Other.DAG && "Iterators of different DAGs!"); | ||
assert(N == Other.N && "Iterators of different nodes!"); | ||
return OpIt == Other.OpIt && MemIt == Other.MemIt; | ||
} | ||
|
||
#ifndef NDEBUG | ||
void DGNode::print(raw_ostream &OS, bool PrintDeps) const { | ||
I->dumpOS(OS); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,12 +240,53 @@ define void @foo(ptr %ptr, i8 %v0, i8 %v1) { | |
EXPECT_TRUE(N1->hasMemPred(N0)); | ||
EXPECT_FALSE(N0->hasMemPred(N1)); | ||
|
||
// Check preds(). | ||
EXPECT_TRUE(N0->preds(DAG).empty()); | ||
EXPECT_THAT(N1->preds(DAG), testing::ElementsAre(N0)); | ||
|
||
// Check memPreds(). | ||
EXPECT_TRUE(N0->memPreds().empty()); | ||
EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0)); | ||
EXPECT_TRUE(N2->memPreds().empty()); | ||
} | ||
|
||
TEST_F(DependencyGraphTest, Preds) { | ||
parseIR(C, R"IR( | ||
declare ptr @bar(i8) | ||
define i8 @foo(i8 %v0, i8 %v1) { | ||
%add0 = add i8 %v0, %v0 | ||
%add1 = add i8 %v1, %v1 | ||
%add2 = add i8 %add0, %add1 | ||
%ptr = call ptr @bar(i8 %add1) | ||
store i8 %add2, ptr %ptr | ||
ret i8 %add2 | ||
} | ||
)IR"); | ||
llvm::Function *LLVMF = &*M->getFunction("foo"); | ||
sandboxir::Context Ctx(C); | ||
auto *F = Ctx.createFunction(LLVMF); | ||
auto *BB = &*F->begin(); | ||
auto It = BB->begin(); | ||
sandboxir::DependencyGraph DAG(getAA(*LLVMF)); | ||
DAG.extend({&*BB->begin(), BB->getTerminator()}); | ||
|
||
auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); | ||
auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); | ||
auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); | ||
auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); | ||
auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); | ||
auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); | ||
|
||
// Check preds(). | ||
EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); | ||
EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); | ||
EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); | ||
EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); | ||
EXPECT_THAT(StN->preds(DAG), | ||
testing::UnorderedElementsAre(CallN, CallN, AddN2)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding a note somewhere that this can return the same instruction multiple times would be good There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah there is no filtering out of duplicates. I will add a note in the description. |
||
EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); | ||
} | ||
|
||
TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { | ||
parseIR(C, R"IR( | ||
define void @foo(ptr %ptr, i8 %v0, i8 %v1) { | ||
|
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.
Is it time to move MemPreds into MemDGNode?
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, it's in a follow-up patch.