Skip to content
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

[ir] Add a function to test if two IRNodes are equivalent #683

Merged
merged 46 commits into from
Apr 4, 2020

Conversation

xumingkuan
Copy link
Contributor

@xumingkuan
Copy link
Contributor Author

Shall we move

bool is() const {

to IRNode in order to test if IRNode *other is of the same type with the current IRNode *? (for example, to test if other is Block * in void visit(Block *stmt_list))

@yuanming-hu
Copy link
Member

Good idea!

@xumingkuan
Copy link
Contributor Author

I was writing the IRNode comparator while referring to the IR printer to see which fields each kind of Stmts has. I noticed that many Frontend...Stmt's visit function of IR printer invokes serialize, of which it would be extremely hard to compare if two are the same without re_id.

I wonder if, in the stage of calling our IRNode comparator, there would be no Frontend...Stmt's? If the answer is yes, I would be able to build an std::map to incrementally store the relationships of ids.

@yuanming-hu
Copy link
Member

I wonder if, in the stage of calling our IRNode comparator, there would be no Frontend...Stmt's? If the answer is yes, I would be able to build an std::map to incrementally store the relationships of ids.

Yes, you can assume you are working on a lowered AST.

@xumingkuan
Copy link
Contributor Author

Is type_hint() a necessary field to check?

@yuanming-hu
Copy link
Member

Yes, we should assume this process happens only after type_check, where ret_type of all statements are computed.

Comment on lines 45 to 46
std::map<int, int> id_map; // map the id from this node to the other node
std::set<int> captured_id; // ids which don't belong to either node
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to use the std::unordered_ versions for efficienty.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the advantage of map? If unordered_map always superior, then why they don't replace it then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::map uses less memory, provides functions about the order (lower_bound for example), and guarantees worst-case O(log(n)) time (std::unordered_map has a worst-case complexity of O(n)). I agree that we should use std::unordered_map in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that the indices inserted to id_map must be in ascending order. Maybe std::vector is more efficient if the range is not too big (and after re_id, it is not). However, I would still prefer to use std::unordered_map for maintainable code.

taichi/analysis/same_statements.cpp Outdated Show resolved Hide resolved
@xumingkuan
Copy link
Contributor Author

Why are there XStmts in both ir.h and statements.h?

@xumingkuan
Copy link
Contributor Author

Well... In some cases, a SNode * could be a nullptr. Maybe it's also OK to check if two SNode *'s (pointers) are the same, rather than check their id's?

@yuanming-hu
Copy link
Member

yuanming-hu commented Mar 31, 2020

Well... In some cases, a SNode * could be a nullptr. Maybe it's also OK to check if two SNode *'s (pointers) are the same, rather than check their id's?

Yes, you can simply use the pointers for comparison. LLVM uses that as well.

Or you can define a function that takes in SNode * and returns the unique_ids and -1 on null pointers.

@yuanming-hu
Copy link
Member

yuanming-hu commented Mar 31, 2020

Well... In some cases, a SNode * could be a nullptr. Maybe it's also OK to check if two SNode *'s (pointers) are the same, rather than check their id's?

Yes, you can simply use the pointers for comparison. LLVM uses that as well.

Or you can define a function that takes in SNode * and returns the unique_ids and -1 on null pointers.

Let's take the second approach, considering we may allow deleting/adding new SNodes dynamically and reuse pointer addresses in the future. LLVM uses pointer comparison on its types because it assumes once created the types won't get recycled.

@xumingkuan
Copy link
Contributor Author

Or you can define a function that takes in SNode * and returns the unique_ids and -1 on null pointers.

It can't be applied directly with this macro though...

#define DEFINE_FIELD_CHECK(field)    \
  if (stmt->field != other->field) { \
    same = false;                    \
    return;                          \
  }

Shall I write another macro like this?

#define DEFINE_SNODE_CHECK(snode)    \
  if (get_snode_id(stmt->snode) != get_snode_id(other->snode)) { \
    same = false;                    \
    return;                          \
  }

@xumingkuan
Copy link
Contributor Author

xumingkuan commented Mar 31, 2020

Seems that

int step;
and
std::vector<Stmt *> loop_vars;
are never used?

@xumingkuan
Copy link
Contributor Author

Why is Travis CI failing?

@xumingkuan
Copy link
Contributor Author

I see. Probably because LocalAddress is used before definition...

@xumingkuan xumingkuan requested a review from yuanming-hu April 3, 2020 21:05
Copy link
Member

@yuanming-hu yuanming-hu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

taichi/ir/ir.h Outdated Show resolved Hide resolved
@yuanming-hu
Copy link
Member

One final thing before merging this: could you add a pass after lower_ast to check if fields_registered is true for all statements? Thanks!

@xumingkuan xumingkuan requested a review from yuanming-hu April 3, 2020 23:00
@yuanming-hu
Copy link
Member

I realized type_check is a better place to check these fields. I also registered WhileStmt. I'll merge this in once CI passes. Thanks!

@xumingkuan
Copy link
Contributor Author

WhileStmt::mask was not an operand. What does it do and what's the effect of adding it to operands?

@yuanming-hu
Copy link
Member

#583 (comment)

@xumingkuan
Copy link
Contributor Author

Should WhileStmt::mask be similar to WhileControlStmt::mask, what about IfStmt::true_mask and IfStmt::false_mask? Just to make sure everything is good as IfStmt::true_mask and IfStmt::false_mask are not operands.

@yuanming-hu
Copy link
Member

Should WhileStmt::mask be similar to WhileControlStmt::mask, what about IfStmt::true_mask and IfStmt::false_mask? Just to make sure everything is good as IfStmt::true_mask and IfStmt::false_mask are not operands.

Maybe I should redefine operand: they are defined as all Stmt * fields of a statement. Let's initialize all the remaining operands (especially the masks) to nullptr and register them. (I realized that for IfStmt, true/false mask are not registered & initialized...)

@yuanming-hu
Copy link
Member

LGTM now. Thank you so much, Mingkuan!

@yuanming-hu yuanming-hu merged commit b865805 into taichi-dev:master Apr 4, 2020
@xumingkuan xumingkuan deleted the same branch April 10, 2020 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants