-
Notifications
You must be signed in to change notification settings - Fork 299
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
[Moore] Add AssignedVarOp and canonicalization for VariableOp. #7251
[Moore] Add AssignedVarOp and canonicalization for VariableOp. #7251
Conversation
Appendix:
|
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 it's reasonable to make SVModuleOp graph region op for progressive lowering into core dialects. However it's a big change for Moore dialect design so would be nice to have consensus on this change.
`:` type($result) | ||
}]; | ||
} | ||
|
||
def AssignedVarOp : MooreOp<"assigned_variable", [ |
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 we need a new op? NetOp seems to have an assignment
operand so is that same?
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.
You're totally right! NetOp
has an assignment
operand. Maybe I think I need to rename it. Like def AssignedDeclOp : MooreOp<"assigned_decl(aration)", [
, what do @fabianschuiki @uenoku think? By the way, slang will throw an error, if we drive the same variable multiple times.
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.
Hmmm yeah good question... SV differentiates between nets and variables in quite a few places. My gut feeling is that turning a VariableOp
into a NetOp
with an assignment isn't going to be correct in general 🤔. The AssignedVariableOp
feels like a good step, because it retains the variable-ness but makes it explicit that it is continuously assigned a specific value.
I'm pretty sure we'll be able to write some simplification passes that take always_comb
procedures that write to variables through moore.blocking_assign
and convert that into a simple moore.assigned_variable
for simplicity. Then only the truly annoying uses of variables would remain (the ones interacting with the event queue, have delays, etc.).
I'll separate the changing of |
fd08bf5
to
843f558
Compare
I'm wondering if this could work as a canonicalization pattern defined on |
ef922c6
to
ade3855
Compare
It makes sense to implement it as canonicalization. We do the same thing for SV so compile time should be OK. However in that case please make sure lowering pass can lower them even without canonicalization. |
c8c19f6
to
edce0c1
Compare
Hey, @fabianschuiki @uenoku! I add the canonicalization pattern for |
lib/Dialect/Moore/MooreOps.cpp
Outdated
for (auto *user : op->getUsers()) | ||
if (isa<ContinuousAssignOp>(user) && | ||
(user->getOperand(0) == op.getResult())) { | ||
auto assignVarOp = rewriter.create<AssignedVarOp>( | ||
op->getLoc(), op.getType(), op.getName(), user->getOperand(1)); | ||
rewriter.replaceOp(op, assignVarOp); | ||
return success(); | ||
} | ||
return failure(); | ||
} |
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 you must ensure that there is no multiple ContinuousAssignOp
.
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.
Slang has guaranteed that the variable has only one continuous assignment. For example:
int x;
assign x = 32;
assign x = 64;
source.sv:4:9: error: cannot have multiple continuous assignments to variable 'x'
assign x = 64;
^
source.sv:3:9: note: also assigned here
assign x = 32;
I'll leave a comment about this.
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 we shouldn't rely on implicit assumption of slang. We should at least check that property in our verifier.
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.
Ok, I'll add this.
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 understood why we need to check whether there are multiple continuous assignments for the same variable. Because the --canonicalize
operates on the IR, not from AST to IR, right?
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 think we should able to use Moore dialect not only for slang.
Can we remove mergeAssignments pass if we implemented it as a canonicalization? |
dcbc38f
to
1234b63
Compare
I have removed the |
1234b63
to
e89aa9e
Compare
lib/Dialect/Moore/MooreOps.cpp
Outdated
llvm::DenseSet<Operation *> variables; | ||
Value initial; | ||
for (auto *user : op->getUsers()) | ||
if (isa<ContinuousAssignOp>(user) && | ||
(user->getOperand(0) == op.getResult())) { | ||
// Don't canonicalize the multiple continuous assignment to the same | ||
// variable. | ||
if (variables.contains(op)) | ||
return failure(); | ||
|
||
variables.insert(op); | ||
initial = user->getOperand(1); | ||
} |
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 we don't need variables
set.
llvm::DenseSet<Operation *> variables; | |
Value initial; | |
for (auto *user : op->getUsers()) | |
if (isa<ContinuousAssignOp>(user) && | |
(user->getOperand(0) == op.getResult())) { | |
// Don't canonicalize the multiple continuous assignment to the same | |
// variable. | |
if (variables.contains(op)) | |
return failure(); | |
variables.insert(op); | |
initial = user->getOperand(1); | |
} | |
Value initial; | |
for (auto *user : op->getUsers()) | |
if (isa<ContinuousAssignOp>(user) && | |
(user->getOperand(0) == op.getResult())) { | |
// Don't canonicalize the multiple continuous assignment to the same | |
// variable. | |
if (initial) | |
return failure(); | |
initial = user->getOperand(1); | |
} |
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.
Nice~ ! 💯
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.
One nit, otherwise LGTM!
[Moore] Add the canonicalization pattern for VariableOp.
e89aa9e
to
1f3374f
Compare
Thanks for the code review 😃 . |
Very cool! 🥳 |
The canonicalization for VariableOp is aimed at merging the "easy use" of the variable and its value(continuous assignment) into a new op called
assigned_variable
. Don't handleblocking_assign
andnonBlocking_assign
due to the dominance.The "easy use" is assigning a value to a variable with the whole bit-width, in other words, exclude the bits slice, concatenation operator, etc.