From f21774f3865e506b6dea912af8f8be16fd29dacb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 27 May 2022 11:16:39 -0700 Subject: OptimizeInstructions: Turn call_ref of a select into an if over two direct calls (#4660) This extends the existing call_indirect code to do the same for call_ref, basically. The shared code is added to a new helper utility. --- src/passes/call-utils.h | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/passes/call-utils.h (limited to 'src/passes/call-utils.h') diff --git a/src/passes/call-utils.h b/src/passes/call-utils.h new file mode 100644 index 000000000..175946c0e --- /dev/null +++ b/src/passes/call-utils.h @@ -0,0 +1,153 @@ +/* + * Copyright 2022 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_ir_function_h +#define wasm_ir_function_h + +#include + +#include "ir/type-updating.h" +#include "wasm.h" + +namespace wasm::CallUtils { + +// Define a variant to describe the information we know about an indirect call, +// which is one of three things: +// * Unknown: Nothing is known this call. +// * Trap: This call target is invalid and will trap at runtime. +// * Known: This call goes to a known static call target, which is provided. +struct Unknown : public std::monostate {}; +struct Trap : public std::monostate {}; +struct Known { + Name target; +}; +using IndirectCallInfo = std::variant; + +// Converts indirect calls that target selects between values into ifs over +// direct calls. For example, consider this input: +// +// (call_ref +// (select +// (ref.func A) +// (ref.func B) +// (..condition..) +// ) +// ) +// +// We'll check if the input falls into such a pattern, and if so, return the new +// form: +// +// (if +// (..condition..) +// (call $A) +// (call $B) +// ) +// +// If we fail to find the expected pattern, or we decide it is not worth +// optimizing it for some reason, we return nullptr. +// +// If this returns the new form, it will modify the function as necessary, +// adding new locals etc., which later passes should optimize. +// +// |getCallInfo| is given one of the arms of the select and should return an +// IndirectCallInfo that says what we know about it. We may know nothing, or +// that it will trap, or that it will go to a known static target. +template +inline Expression* +convertToDirectCalls(T* curr, + std::function getCallInfo, + Function& func, + Module& wasm) { + auto* select = curr->target->template dynCast