@@ -343,6 +343,27 @@ struct Walker : public VisitorType {
343343 Module* currModule = nullptr ; // current module being processed
344344};
345345
346+ // Define which expression classes are leaves. We can handle them more
347+ // optimally below. The accuracy of this list is tested in leaves.cpp.
348+ template <typename T> struct IsLeaf : std::false_type {};
349+
350+ template <> struct IsLeaf <LocalGet> : std::true_type {};
351+ template <> struct IsLeaf <GlobalGet> : std::true_type {};
352+ template <> struct IsLeaf <AtomicFence> : std::true_type {};
353+ template <> struct IsLeaf <Pause> : std::true_type {};
354+ template <> struct IsLeaf <DataDrop> : std::true_type {};
355+ template <> struct IsLeaf <Const> : std::true_type {};
356+ template <> struct IsLeaf <MemorySize> : std::true_type {};
357+ template <> struct IsLeaf <RefNull> : std::true_type {};
358+ template <> struct IsLeaf <RefFunc> : std::true_type {};
359+ template <> struct IsLeaf <TableSize> : std::true_type {};
360+ template <> struct IsLeaf <ElemDrop> : std::true_type {};
361+ template <> struct IsLeaf <Rethrow> : std::true_type {};
362+ template <> struct IsLeaf <Nop> : std::true_type {};
363+ template <> struct IsLeaf <Unreachable> : std::true_type {};
364+ template <> struct IsLeaf <Pop> : std::true_type {};
365+ template <> struct IsLeaf <StringConst> : std::true_type {};
366+
346367// Walks in post-order, i.e., children first. When there isn't an obvious
347368// order to operands, we follow them in order of execution.
348369
@@ -369,6 +390,10 @@ struct PostWalker : public Walker<SubType, VisitorType> {
369390 // Note that even if this ends up being a runtime check, it should be faster
370391 // than pushing empty tasks, as the check is much faster than the push/pop/
371392 // call, and a large number of our calls (most, perhaps) are not overridden.
393+ //
394+ // If we do *not* have an empty visitor, we can still optimize in the case
395+ // of a leaf: leaves have no children, so we can just call doVisit* rather
396+ // than push that task, pop it later, and call that.
372397#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 11
373398#define DELEGATE_START (id ) \
374399 if (&SubType::visit##id != \
@@ -377,17 +402,22 @@ struct PostWalker : public Walker<SubType, VisitorType> {
377402 self->pushTask (SubType::doVisit##id, currp); \
378403 } \
379404 [[maybe_unused]] auto * cast = curr->cast <id>();
380- #else
405+ #else // constexpr
381406#define DELEGATE_START (id ) \
382407 if constexpr (&SubType::visit##id != \
383408 &Visitor<SubType, \
384409 typename SubType::ReturnType>::visit##id || \
385410 &SubType::doVisit##id != \
386411 &Walker<SubType, VisitorType>::doVisit##id) { \
412+ if constexpr (IsLeaf<id>::value && \
413+ &SubType::scan == &PostWalker<SubType, VisitorType>::scan) { \
414+ SubType::doVisit##id (self, currp); \
415+ return ; \
416+ } \
387417 self->pushTask (SubType::doVisit##id, currp); \
388418 } \
389419 [[maybe_unused]] auto * cast = curr->cast <id>();
390- #endif
420+ #endif // constexpr
391421
392422#define DELEGATE_GET_FIELD (id, field ) cast->field
393423
0 commit comments