summaryrefslogtreecommitdiff
path: root/src/wasm-delegations-fields.h
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2020-11-11 15:35:13 -0800
committerGitHub <noreply@github.com>2020-11-11 15:35:13 -0800
commitd0d96a815fb2e6c397dce76fb1b74b803fd431f4 (patch)
tree93f9c624592a4dd38a53b6ba5ca047cadc7a2d76 /src/wasm-delegations-fields.h
parent32171f1d6ff57fdb31f55d8aa554eac15cb5d8f5 (diff)
downloadbinaryen-d0d96a815fb2e6c397dce76fb1b74b803fd431f4.tar.gz
binaryen-d0d96a815fb2e6c397dce76fb1b74b803fd431f4.tar.bz2
binaryen-d0d96a815fb2e6c397dce76fb1b74b803fd431f4.zip
Avoid boilerplate in ExpressionAnalyzer comparing & hashing (#3332)
Expands on #3294: * Scope names must be distinguished as either defs or uses. * Error when a core #define is missing, which is less error-prone, as suggested by @tlively * Add DELEGATE_GET_FIELD which lets one define "get the field" once and then all the loops can use it. This helps avoid boilerplate for loops at least in some cases (when there is a single object on which to get the field). With those, it is possible to replace boilerplate in comparisons and hashing logic. This also fixes a bug where BrOnExn::sent was not scanned there. Add some unit tests for hashing. We didn't have any, and hashing can be subtly wrong without observable external effects (just more collisions).
Diffstat (limited to 'src/wasm-delegations-fields.h')
-rw-r--r--src/wasm-delegations-fields.h149
1 files changed, 103 insertions, 46 deletions
diff --git a/src/wasm-delegations-fields.h b/src/wasm-delegations-fields.h
index fef4a9f7c..df2309474 100644
--- a/src/wasm-delegations-fields.h
+++ b/src/wasm-delegations-fields.h
@@ -15,89 +15,144 @@
*/
// Implements a switch on an expression class ID, and has a case for each id
-// in which it runs delegates on the fields and immediates. All the delegates
-// are optional, so you can just provide what you want, and no code will be
-// emitted for the others.
+// in which it runs delegates on the fields and immediates. You should include
+// this file after defining the relevant DELEGATE_* macros.
//
-// (The only mandatory thing to define is DELEGATE_ID which is the key for the
-// switch.)
+// All defines used here are undefed automatically at the end for you.
//
-// All #defines used here are undefed automatically at the end for you.
+// Most of the defines are necessary, and you will get an error if you forget
+// them, but some are optional and some imply others, see below.
//
-// Child pointers are emitted in reverse order (which is convenient for walking
-// by pushing them to a stack first).
+// The defines are as follows:
+//
+// DELEGATE_START(id) - called at the start of a case for an expression class.
+//
+// DELEGATE_END(id) - called at the end of a case.
+//
+// DELEGATE_GET_FIELD(id, name) - called to get a field by its name. This must
+// know the object on which to get it, so it is just useful for the case
+// where you operate on a single such object, but in that case it is nice
+// because then other things can be defined automatically for you, see later.
+//
+// DELEGATE_FIELD_CHILD(id, name) - called for each child field (note: children
+// are visited in reverse order, which is convenient for walking by pushing
+// them to a stack first).
+//
+// DELEGATE_FIELD_OPTIONAL_CHILD(id, name) - called for a child that may not be
+// present (like a Return's value). If you do not define this then
+// DELEGATE_FIELD_CHILD is called.
+//
+// DELEGATE_FIELD_CHILD_VECTOR(id, name) - called for a variable-sized vector of
+// child pointers. If this is not defined, and DELEGATE_GET_FIELD is, then
+// DELEGATE_FIELD_CHILD is called on them.
+//
+// DELEGATE_FIELD_INT(id, name) - called for an integer field (bool, enum,
+// Index, int32, or int64).
+//
+// DELEGATE_FIELD_INT_ARRAY(id, name) - called for a std::array of fixed size of
+// integer values (like a SIMD mask). If this is not defined, and
+// DELEGATE_GET_FIELD is, then DELEGATE_FIELD_INT is called on them.
+//
+// DELEGATE_FIELD_LITERAL(id, name) - called for a Literal.
+//
+// DELEGATE_FIELD_NAME(id, name) - called for a Name.
+//
+// DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) - called for a scope name definition
+// (like a block's name).
+//
+// DELEGATE_FIELD_SCOPE_NAME_USE(id, name) - called for a scope name use (like
+// a break's target).
+//
+// DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name) - called for a variable-sized
+// vector of scope names (like a switch's targets). If this is not defined,
+// and DELEGATE_GET_FIELD is, then DELEGATE_FIELD_SCOPE_NAME_USE is called on
+// them.
+//
+// DELEGATE_FIELD_SIGNATURE(id, name) - called for a Signature.
+//
+// DELEGATE_FIELD_TYPE(id, name) - called for a Type.
+//
+// DELEGATE_FIELD_ADDRESS(id, name) - called for an Address.
-// Emits code at the start of the case for a class.
#ifndef DELEGATE_START
#define DELEGATE_START(id)
#endif
-// Emits code at the end of the case for a class.
#ifndef DELEGATE_END
#define DELEGATE_END(id)
#endif
-// Emits code to handle a child pointer.
#ifndef DELEGATE_FIELD_CHILD
-#define DELEGATE_FIELD_CHILD(id, name)
+#error please define DELEGATE_FIELD_CHILD(id, name)
#endif
-// Emits code to handle an optional child pointer (if this is not defined, then
-// DELEGATE_FIELD_CHILD is called on it).
#ifndef DELEGATE_FIELD_OPTIONAL_CHILD
#define DELEGATE_FIELD_OPTIONAL_CHILD(id, name) DELEGATE_FIELD_CHILD(id, name)
#endif
-// Emits code to handle a variable-sized vector of child pointers.
#ifndef DELEGATE_FIELD_CHILD_VECTOR
-#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name) \
+ for (Index i = 0; i < (DELEGATE_GET_FIELD(id, name)).size(); i++) { \
+ DELEGATE_FIELD_CHILD(id, name[i]); \
+ }
+#else
+#error please define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#endif
#endif
-// Emits code to handle an integer value (bool, enum, Index, int32, or int64).
#ifndef DELEGATE_FIELD_INT
-#define DELEGATE_FIELD_INT(id, name)
+#error please define DELEGATE_FIELD_INT(id, name)
#endif
-// Emits code to handle a std::array of fixed size of integer values (like a
-// SIMD mask).
#ifndef DELEGATE_FIELD_INT_ARRAY
-#define DELEGATE_FIELD_INT_ARRAY(id, name)
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_INT_ARRAY(id, name) \
+ for (Index i = 0; i < (DELEGATE_GET_FIELD(id, name)).size(); i++) { \
+ DELEGATE_FIELD_INT(id, name[i]); \
+ }
+#else
+#error please define DELEGATE_FIELD_INT_ARRAY(id, name)
+#endif
#endif
-// Emits code to handle a Literal.
#ifndef DELEGATE_FIELD_LITERAL
-#define DELEGATE_FIELD_LITERAL(id, name)
+#error please define DELEGATE_FIELD_LITERAL(id, name)
#endif
-// Emits code to handle a name (like a call target).
#ifndef DELEGATE_FIELD_NAME
-#define DELEGATE_FIELD_NAME(id, name)
+#error please define DELEGATE_FIELD_NAME(id, name)
#endif
-// Emits code to handle a scope name (like a br target).
-#ifndef DELEGATE_FIELD_SCOPE_NAME
-#define DELEGATE_FIELD_SCOPE_NAME(id, name)
+#ifndef DELEGATE_FIELD_SCOPE_NAME_DEF
+#error please define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
#endif
-// Emits code to handle a variable-sized vector of scope names (like a switch's
-// targets).
-#ifndef DELEGATE_FIELD_SCOPE_NAME_VECTOR
-#define DELEGATE_FIELD_SCOPE_NAME_VECTOR(id, name)
+#ifndef DELEGATE_FIELD_SCOPE_NAME_USE
+#error please define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name) \
+ for (Index i = 0; i < (DELEGATE_GET_FIELD(id, name)).size(); i++) { \
+ DELEGATE_FIELD_SCOPE_NAME_USE(id, name[i]); \
+ }
+#else
+#error please define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
+#endif
#endif
-// Emits code to handle a Signature.
#ifndef DELEGATE_FIELD_SIGNATURE
-#define DELEGATE_FIELD_SIGNATURE(id, name)
+#error please define DELEGATE_FIELD_SIGNATURE(id, name)
#endif
-// Emits code to handle a type.
#ifndef DELEGATE_FIELD_TYPE
-#define DELEGATE_FIELD_TYPE(id, name)
+#error please define DELEGATE_FIELD_TYPE(id, name)
#endif
-// Emits code to handle an address.
#ifndef DELEGATE_FIELD_ADDRESS
-#define DELEGATE_FIELD_ADDRESS(id, name)
+#error please define DELEGATE_FIELD_ADDRESS(id, name)
#endif
switch (DELEGATE_ID) {
@@ -108,7 +163,7 @@ switch (DELEGATE_ID) {
case Expression::Id::BlockId: {
DELEGATE_START(Block);
DELEGATE_FIELD_CHILD_VECTOR(Block, list);
- DELEGATE_FIELD_SCOPE_NAME(Block, name);
+ DELEGATE_FIELD_SCOPE_NAME_DEF(Block, name);
DELEGATE_END(Block);
break;
}
@@ -123,7 +178,7 @@ switch (DELEGATE_ID) {
case Expression::Id::LoopId: {
DELEGATE_START(Loop);
DELEGATE_FIELD_CHILD(Loop, body);
- DELEGATE_FIELD_SCOPE_NAME(Loop, name);
+ DELEGATE_FIELD_SCOPE_NAME_DEF(Loop, name);
DELEGATE_END();
break;
}
@@ -131,7 +186,7 @@ switch (DELEGATE_ID) {
DELEGATE_START(Break);
DELEGATE_FIELD_OPTIONAL_CHILD(Break, condition);
DELEGATE_FIELD_OPTIONAL_CHILD(Break, value);
- DELEGATE_FIELD_SCOPE_NAME(Break, name);
+ DELEGATE_FIELD_SCOPE_NAME_USE(Break, name);
DELEGATE_END();
break;
}
@@ -139,8 +194,8 @@ switch (DELEGATE_ID) {
DELEGATE_START(Switch);
DELEGATE_FIELD_CHILD(Switch, condition);
DELEGATE_FIELD_OPTIONAL_CHILD(Switch, value);
- DELEGATE_FIELD_SCOPE_NAME(Switch, default_);
- DELEGATE_FIELD_SCOPE_NAME_VECTOR(Switch, targets);
+ DELEGATE_FIELD_SCOPE_NAME_USE(Switch, default_);
+ DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(Switch, targets);
DELEGATE_END();
break;
}
@@ -447,7 +502,7 @@ switch (DELEGATE_ID) {
case Expression::Id::BrOnExnId: {
DELEGATE_START(BrOnExn);
DELEGATE_FIELD_CHILD(BrOnExn, exnref);
- DELEGATE_FIELD_SCOPE_NAME(BrOnExn, name);
+ DELEGATE_FIELD_SCOPE_NAME_USE(BrOnExn, name);
DELEGATE_FIELD_NAME(BrOnExn, event);
DELEGATE_FIELD_TYPE(BrOnExn, sent);
DELEGATE_END();
@@ -576,9 +631,11 @@ switch (DELEGATE_ID) {
#undef DELEGATE_FIELD_CHILD_VECTOR
#undef DELEGATE_FIELD_INT
#undef DELEGATE_FIELD_INT_ARRAY
+#undef DELEGATE_FIELD_LITERAL
#undef DELEGATE_FIELD_NAME
-#undef DELEGATE_FIELD_SCOPE_NAME
-#undef DELEGATE_FIELD_SCOPE_NAME_VECTOR
+#undef DELEGATE_FIELD_SCOPE_NAME_DEF
+#undef DELEGATE_FIELD_SCOPE_NAME_USE
+#undef DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR
#undef DELEGATE_FIELD_SIGNATURE
#undef DELEGATE_FIELD_TYPE
#undef DELEGATE_FIELD_ADDRESS