From 8895a2417d37e3444c98f0023e98ab9151d04290 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 Oct 2021 15:45:43 -0700 Subject: Optimize call_indirect of a select of two constants (#4208) (call_indirect ..args.. (select (i32.const x) (i32.const y) (condition) ) ) => (if (condition) (call $func-for-x ..args.. ) (call $func-for-y ..args.. ) ) To do this we must reorder the condition with the args, and also use the args more than once, so place them all in locals. This works towards the goal of polymorphic devirtualization, that is, turning an indirect call of more than one possible target into more than one direct call. --- src/passes/Directize.cpp | 129 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 0f04b5f4c..5a9b1b984 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -23,6 +23,7 @@ #include #include "ir/table-utils.h" +#include "ir/type-updating.h" #include "ir/utils.h" #include "pass.h" #include "wasm-builder.h" @@ -50,30 +51,65 @@ struct FunctionDirectizer : public WalkerPass> { auto& flatTable = it->second; - if (auto* c = curr->target->dynCast()) { - Index index = c->value.geti32(); - // If the index is invalid, or the type is wrong, we can - // emit an unreachable here, since in Binaryen it is ok to - // reorder/replace traps when optimizing (but never to - // remove them, at least not by default). - if (index >= flatTable.names.size()) { - replaceWithUnreachable(curr); - return; - } - auto name = flatTable.names[index]; - if (!name.is()) { - replaceWithUnreachable(curr); - return; - } - auto* func = getModule()->getFunction(name); - if (curr->sig != func->getSig()) { - replaceWithUnreachable(curr); - return; + // If the target is constant, we can emit a direct call. + if (curr->target->is()) { + std::vector operands(curr->operands.begin(), + curr->operands.end()); + replaceCurrent(makeDirectCall(operands, curr->target, flatTable, curr)); + return; + } + + // If the target is a select of two different constants, we can emit two + // direct calls. + // TODO: handle 3+ + // TODO: handle the case where just one arm is a constant? + if (auto* select = curr->target->dynCast