Skip to content

Commit 6792293

Browse files
authored
Move Node-specific behavior into Node subclasses (#1039)
* Move ConstantFold into Node classes * Move Compare into Node classes * Move Coalesce into Node classes * Move Sort into Node classes * Move Cleanup into Node classes * Add separate Create methods for different kinds of expressions * Change null root invariant to check if the Root is null rather than if the Parent is null * Make Node Compare methods const * Add comments to Node methods * Make LeafExprNode::Compare const * Fix line lengths * Move PrettyPrint method to Node classes * Add comment to AddZero method describing the conditions where `e` must be canonically equivalent to `e + 0` * Add virtual Node destructor * Replace range-based for loop in BinaryOperatorNode::Coalesce with index-based for loop This fixes a crash that would happen on Linux for certain binary operators. * Don't evaluate BParent->Children.end() on every loop iteration * Make Coalesce, Sort, ConstantFold, Compare, PrettyPrint, and Cleanup pure virtual Node functions * Restore Node::Cleanup method
1 parent 660525e commit 6792293

File tree

2 files changed

+545
-559
lines changed

2 files changed

+545
-559
lines changed

clang/include/clang/AST/PreorderAST.h

Lines changed: 140 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,65 @@ namespace clang {
4545
if (Parent)
4646
assert(!isa<LeafExprNode>(Parent) &&
4747
"Parent node cannot be a LeafExprNode");
48-
}
48+
}
49+
50+
virtual ~Node() { }
51+
52+
// Recursively coalesce BinaryOperatorNodes having the same commutative
53+
// and associative operator.
54+
// @param[in] this is the current node of the AST.
55+
// @param[in] Changed indicates whether a node was coalesced. We need this
56+
// to control when to stop recursive coalescing.
57+
// @param[in] Error indicates whether an error occurred during coalescing.
58+
virtual void Coalesce(bool &Changed, bool &Error) = 0;
59+
60+
// Recursively descend a Node to sort the children of all
61+
// BinaryOperatorNodes if the binary operator is commutative.
62+
// @param[in] this is the current node of the AST.
63+
// @param[in] Lex is used to lexicographically compare Exprs and Decls
64+
// that occur within nodes.
65+
virtual void Sort(Lexicographic Lex) = 0;
66+
67+
// Constant fold integer expressions.
68+
// @param[in] this is the current node of the AST.
69+
// @param[in] Changed indicates whether constant folding was done. We need
70+
// this to control when to stop recursive constant folding.
71+
// @param[in] Error indicates whether an error occurred during constant
72+
// folding.
73+
// @param[in] Ctx is used to create constant expressions.
74+
virtual void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx) = 0;
75+
76+
// Compare nodes according to their kind.
77+
// @param[in] this is the current node of the AST.
78+
// @param[in] Other is the node to compare to this.
79+
// @return Returns a Lexicographic::Result indicating the comparison
80+
// between this and Other according to their node kinds.
81+
Result CompareKinds(const Node *Other) const {
82+
if (Kind < Other->Kind)
83+
return Result::LessThan;
84+
if (Kind > Other->Kind)
85+
return Result::GreaterThan;
86+
return Result::Equal;
87+
}
88+
89+
// Compare two nodes lexicographically.
90+
// @param[in] this is the current node of the AST.
91+
// @param[in] Other the node to compare to this.
92+
// @param[in] Lex is used to lexicographically compare Exprs and Decls
93+
// that occur within nodes.
94+
// @return Returns a Lexicographic::Result indicating the comparison
95+
// between this and Other.
96+
virtual Result Compare(const Node *Other, Lexicographic Lex) const = 0;
97+
98+
// Print the node.
99+
// @param[in] this is the current node of the AST.
100+
virtual void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const = 0;
101+
102+
// Cleanup the memory consumed by this node.
103+
// @param[in] this is the current node of the AST.
104+
virtual void Cleanup() {
105+
delete this;
106+
}
49107
};
50108

51109
class BinaryOperatorNode : public Node {
@@ -69,6 +127,18 @@ namespace clang {
69127
bool IsOpCommutativeAndAssociative() {
70128
return Opc == BO_Add || Opc == BO_Mul;
71129
}
130+
131+
// Determines if the BinaryOperatorNode could be coalesced into its parent.
132+
// @param[in] this is the current node.
133+
// @return Returns true if this can be coalesced into its parent, false
134+
// otherwise.
135+
bool CanCoalesce();
136+
void Coalesce(bool &Changed, bool &Error);
137+
void Sort(Lexicographic Lex);
138+
void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx);
139+
Result Compare(const Node *Other, Lexicographic Lex) const;
140+
void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const;
141+
void Cleanup();
72142
};
73143

74144
class UnaryOperatorNode : public Node {
@@ -83,6 +153,13 @@ namespace clang {
83153
static bool classof(const Node *N) {
84154
return N->Kind == NodeKind::UnaryOperatorNode;
85155
}
156+
157+
void Coalesce(bool &Changed, bool &Error);
158+
void Sort(Lexicographic Lex);
159+
void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx);
160+
Result Compare(const Node *Other, Lexicographic Lex) const;
161+
void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const;
162+
void Cleanup();
86163
};
87164

88165
class MemberNode : public Node {
@@ -98,6 +175,13 @@ namespace clang {
98175
static bool classof(const Node *N) {
99176
return N->Kind == NodeKind::MemberNode;
100177
}
178+
179+
void Coalesce(bool &Changed, bool &Error);
180+
void Sort(Lexicographic Lex);
181+
void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx);
182+
Result Compare(const Node *Other, Lexicographic Lex) const;
183+
void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const;
184+
void Cleanup();
101185
};
102186

103187
class ImplicitCastNode : public Node {
@@ -112,6 +196,13 @@ namespace clang {
112196
static bool classof(const Node *N) {
113197
return N->Kind == NodeKind::ImplicitCastNode;
114198
}
199+
200+
void Coalesce(bool &Changed, bool &Error);
201+
void Sort(Lexicographic Lex);
202+
void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx);
203+
Result Compare(const Node *Other, Lexicographic Lex) const;
204+
void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const;
205+
void Cleanup();
115206
};
116207

117208
class LeafExprNode : public Node {
@@ -125,6 +216,12 @@ namespace clang {
125216
static bool classof(const Node *N) {
126217
return N->Kind == NodeKind::LeafExprNode;
127218
}
219+
220+
void Coalesce(bool &Changed, bool &Error);
221+
void Sort(Lexicographic Lex);
222+
void ConstantFold(bool &Changed, bool &Error, ASTContext &Ctx);
223+
Result Compare(const Node *Other, Lexicographic Lex) const;
224+
void PrettyPrint(llvm::raw_ostream &OS, ASTContext &Ctx) const;
128225
};
129226

130227
} // end namespace clang
@@ -143,8 +240,46 @@ namespace clang {
143240
// @param[in] Parent is the parent of the new node.
144241
void Create(Expr *E, Node *Parent = nullptr);
145242

243+
// Create a BinaryOperatorNode for the expression E.
244+
// @param[in] E is the expression whose LHS and RHS subexpressions
245+
// will be added to a new node.
246+
// @param[in] Parent is the parent of the new node.
247+
void CreateBinaryOperator(BinaryOperator *E, Node *Parent);
248+
249+
// Create a UnaryOperatorNode or a LeafExprNode for the expression E.
250+
// @param[in] E is the expression that is used to create a new node.
251+
// @param[in] Parent is the parent of the new node.
252+
void CreateUnaryOperator(UnaryOperator *E, Node *Parent);
253+
254+
// Create a UnaryOperatorNode with the sub expression Child and the
255+
// Deref unary operator.
256+
// @param[in] Child is the expression that is the child of a new node.
257+
// @param[in] Parent is the parent of the new node.
258+
void CreateDereference(Expr *Child, Node *Parent);
259+
260+
// Create a MemberNode for the expression E.
261+
// @param[in] E is the expression whose Base and Field will be added to
262+
// a new node.
263+
// @param[in] Parent is the parent of the new node.
264+
void CreateMember(MemberExpr *E, Node *Parent);
265+
266+
// Create an ImplicitCastNode for the expression.
267+
// @param[in] E is the expression whose CastKind and sub expression will
268+
// be added to a new node.
269+
// @param[in] Parent is the parent of the new node.
270+
void CreateImplicitCast(ImplicitCastExpr *E, Node *Parent);
271+
146272
// Create a BinaryOperatorNode with an addition operator and two children
147273
// (E and 0), and attach the created BinaryOperatorNode to the Parent node.
274+
// This method is used to maintain an invariant that an expression `e` is
275+
// equivalent to `e + 0`. This invariant must hold when:
276+
// 1. `e` is the root expression that is used to create the PreorderAST.
277+
// 2. `e` is the subexpression of a dereference expression. For example:
278+
// a. `*e` and `*(e + 0)` must have the same canonical form.
279+
// b. `e1[e2]` is equivalent to `*(e1 + e2)`, so `*(e1 + e2)` and
280+
// `*(e1 + e2 + 0)` must have the same canonical form.
281+
// c. `e->f`, `*e.f`, `(e + 0)->f`, `*(e + 0).f`, and `e[0].f` must have
282+
// the same canonical form.
148283
// @param[in] E is the expression that is one of the two children of
149284
// the created BinaryOperatorNode (the other child is 0).
150285
// @param[in] Parent is the parent of the created BinaryOperatorNode.
@@ -155,48 +290,6 @@ namespace clang {
155290
// @param[in] Parent is the parent of the node to be attached.
156291
void AttachNode(Node *N, Node *Parent);
157292

158-
// Coalesce the BinaryOperatorNode B with its parent. This involves moving
159-
// the children (if any) of node B to its parent and then removing B.
160-
// @param[in] B is the current node. B should be a BinaryOperatorNode.
161-
void CoalesceNode(BinaryOperatorNode *B);
162-
163-
// Determines if a BinaryOperatorNode could be coalesced into its parent.
164-
// @param[in] B is the current node. B should be a BinaryOperatorNode.
165-
// @return Return true if B can be coalesced into its parent, false
166-
// otherwise.
167-
bool CanCoalesceNode(BinaryOperatorNode *B);
168-
169-
// Recursively coalesce BinaryOperatorNodes having the same commutative
170-
// and associative operator.
171-
// @param[in] N is current node of the AST. Initial value is Root.
172-
// @param[in] Changed indicates whether a node was coalesced. We need this
173-
// to control when to stop recursive coalescing.
174-
void Coalesce(Node *N, bool &Changed);
175-
176-
// Recursively descend the PreorderAST to sort the children of all
177-
// BinaryOperatorNodes if the binary operator is commutative.
178-
// @param[in] N is current node of the AST. Initial value is Root.
179-
void Sort(Node *N);
180-
181-
// Compare nodes N1 and N2 to sort them. This function is invoked by a
182-
// lambda which is passed to the llvm::sort function.
183-
// @param[in] N1 is the first node to compare.
184-
// @param[in] N2 is the second node to compare.
185-
// return A boolean indicating the relative ordering between N1 and N2.
186-
bool CompareNodes(const Node *N1, const Node *N2);
187-
188-
// Constant fold integer expressions.
189-
// @param[in] N is current node of the AST. Initial value is Root.
190-
// @param[in] Changed indicates whether constant folding was done. We need
191-
// this to control when to stop recursive constant folding.
192-
void ConstantFold(Node *N, bool &Changed);
193-
194-
// Constant fold integer expressions within a BinaryOperatorNode.
195-
// @param[in] N is current node of the AST.
196-
// @param[in] Changed indicates whether constant folding was done. We need
197-
// this to control when to stop recursive constant folding.
198-
void ConstantFoldOperator(BinaryOperatorNode *N, bool &Changed);
199-
200293
// Get the deref offset from the DerefExpr. The offset represents the
201294
// possible amount by which the bounds of an ntptr could be widened.
202295
// @param[in] UpperExpr is the upper bounds expr for the ntptr.
@@ -209,24 +302,9 @@ namespace clang {
209302
bool GetDerefOffset(Node *UpperExpr, Node *DerefExpr,
210303
llvm::APSInt &Offset);
211304

212-
// Lexicographically compare two AST nodes N1 and N2.
213-
// @param[in] N1 is the first node.
214-
// @param[in] N2 is the second node.
215-
// @return Returns a Lexicographic::Result indicating the comparison
216-
// of N1 and N2.
217-
Result Compare(const Node *N1, const Node *N2) const;
218-
219305
// Set Error in case an error occurs during transformation of the AST.
220306
void SetError() { Error = true; }
221307

222-
// Print the PreorderAST.
223-
// @param[in] N is the current node of the AST. Initial value is Root.
224-
void PrettyPrint(Node *N);
225-
226-
// Cleanup the memory consumed by node N.
227-
// @param[in] N is the current node of the AST. Initial value is Root.
228-
void Cleanup(Node *N);
229-
230308
public:
231309
PreorderAST(ASTContext &Ctx, Expr *E) :
232310
Ctx(Ctx), Lex(Lexicographic(Ctx, nullptr)), OS(llvm::outs()),
@@ -257,7 +335,9 @@ namespace clang {
257335
// @param[in] P is the second AST.
258336
// @return Returns a Lexicographic::Result indicating the comparison between
259337
// the two ASTs.
260-
Result Compare(const PreorderAST P) const { return Compare(Root, P.Root); }
338+
Result Compare(const PreorderAST P) const {
339+
return Root->Compare(P.Root, Lex);
340+
}
261341

262342
// Check if an error has occurred during transformation of the AST. This
263343
// is intended to be called from outside this class to check if an error
@@ -268,7 +348,7 @@ namespace clang {
268348
// Cleanup the memory consumed by the AST. This is intended to be called
269349
// from outside this class and invokes Cleanup on the root node which
270350
// recursively deletes the AST.
271-
void Cleanup() { Cleanup(Root); }
351+
void Cleanup() { Root->Cleanup(); }
272352

273353
bool operator<(PreorderAST &Other) const {
274354
return Compare(Other) == Result::LessThan;

0 commit comments

Comments
 (0)