From fcf9270841d53ad6fc308cce65789381ee810d20 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Mon, 11 May 2026 18:20:01 +0000 Subject: [PATCH] No effects for string builtins --- src/ir/CMakeLists.txt | 1 + src/ir/string-builtin-names.cpp | 47 +++++++++++++++++++++++++++++++++ src/ir/string-builtin-names.h | 44 ++++++++++++++++++++++++++++++ src/passes/GlobalEffects.cpp | 9 +++++++ src/passes/StringLowering.cpp | 45 +++++++++++++++++++------------ 5 files changed, 129 insertions(+), 17 deletions(-) create mode 100644 src/ir/string-builtin-names.cpp create mode 100644 src/ir/string-builtin-names.h diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index 919069770c5..11c80fd4331 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -23,6 +23,7 @@ set(ir_SOURCES runtime-global.cpp runtime-table.cpp stack-utils.cpp + string-builtin-names.cpp table-utils.cpp type-updating.cpp module-splitting.cpp diff --git a/src/ir/string-builtin-names.cpp b/src/ir/string-builtin-names.cpp new file mode 100644 index 00000000000..f0cbd9901d7 --- /dev/null +++ b/src/ir/string-builtin-names.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2026 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. + */ + +#include "ir/string-builtin-names.h" + +namespace wasm { + +namespace StringBuiltins { + +const ImportNames fromCharCodeArray{"wasm:js-string", "fromCharCodeArray"}; +const ImportNames fromCodePoint{"wasm:js-string", "fromCodePoint"}; +const ImportNames concat{"wasm:js-string", "concat"}; +const ImportNames intoCharCodeArray{"wasm:js-string", "intoCharCodeArray"}; +const ImportNames equals{"wasm:js-string", "equals"}; +const ImportNames test{"wasm:js-string", "test"}; +const ImportNames compare{"wasm:js-string", "compare"}; +const ImportNames length{"wasm:js-string", "length"}; +const ImportNames charCodeAt{"wasm:js-string", "charCodeAt"}; +const ImportNames substring{"wasm:js-string", "substring"}; + +const std::array allBuiltins = {fromCharCodeArray, + fromCodePoint, + concat, + intoCharCodeArray, + equals, + test, + compare, + length, + charCodeAt, + substring}; + +} // namespace StringBuiltins + +} // namespace wasm diff --git a/src/ir/string-builtin-names.h b/src/ir/string-builtin-names.h new file mode 100644 index 00000000000..6db5e07756c --- /dev/null +++ b/src/ir/string-builtin-names.h @@ -0,0 +1,44 @@ +/* + * Copyright 2026 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_string_builtin_names_h +#define wasm_ir_string_builtin_names_h + +#include "ir/import-names.h" +#include + +namespace wasm { + +namespace StringBuiltins { + +extern const ImportNames fromCharCodeArray; +extern const ImportNames fromCodePoint; +extern const ImportNames concat; +extern const ImportNames intoCharCodeArray; +extern const ImportNames equals; +extern const ImportNames test; +extern const ImportNames compare; +extern const ImportNames length; +extern const ImportNames charCodeAt; +extern const ImportNames substring; + +extern const std::array allBuiltins; + +} // namespace StringBuiltins + +} // namespace wasm + +#endif // wasm_ir_string_builtin_names_h diff --git a/src/passes/GlobalEffects.cpp b/src/passes/GlobalEffects.cpp index ca82b2b3aea..cdccd7c2fb6 100644 --- a/src/passes/GlobalEffects.cpp +++ b/src/passes/GlobalEffects.cpp @@ -21,6 +21,7 @@ #include "ir/effects.h" #include "ir/module-utils.h" +#include "ir/string-builtin-names.h" #include "pass.h" #include "support/graph_traversal.h" #include "support/strongly_connected_components.h" @@ -50,6 +51,14 @@ std::map analyzeFuncs(Module& module, ModuleUtils::ParallelFunctionAnalysis analysis( module, [&](Function* func, FuncInfo& funcInfo) { if (func->imported()) { + ImportNames importName{func->module, func->base}; + auto& allBuiltins = StringBuiltins::allBuiltins; + if (std::find(allBuiltins.begin(), allBuiltins.end(), importName) != + allBuiltins.end()) { + funcInfo.effects.emplace(passOptions, module); + return; + } + // Imports can do anything, so we need to assume the worst anyhow, // which is the same as not specifying any effects for them in the // map (which we do by not setting funcInfo.effects). diff --git a/src/passes/StringLowering.cpp b/src/passes/StringLowering.cpp index bd753efaf91..df86cafcb71 100644 --- a/src/passes/StringLowering.cpp +++ b/src/passes/StringLowering.cpp @@ -37,6 +37,7 @@ #include "ir/module-utils.h" #include "ir/names.h" +#include "ir/string-builtin-names.h" #include "ir/type-updating.h" #include "ir/utils.h" #include "pass.h" @@ -355,14 +356,15 @@ struct StringLowering : public StringGathering { // Creates an imported string function, returning its name (which is equal to // the true name of the import, if there is no conflict). - Name addImport(Module* module, Name trueName, Type params, Type results) { - auto name = Names::getValidFunctionName(*module, trueName); + Name + addImport(Module* module, ImportNames importName, Type params, Type results) { + auto name = Names::getValidFunctionName(*module, importName.name); auto sig = Signature(params, results); Builder builder(*module); auto* func = module->addFunction( builder.makeFunction(name, Type(sig, NonNullable, Inexact), {})); - func->module = WasmStringsModule; - func->base = trueName; + func->module = importName.module; + func->base = importName.name; return name; } @@ -371,31 +373,40 @@ struct StringLowering : public StringGathering { // parallel work. Optimizations can remove unneeded ones later. // string.fromCharCodeArray: array, start, end -> ext - fromCharCodeArrayImport = addImport( - module, "fromCharCodeArray", {nullArray16, Type::i32, Type::i32}, nnExt); + fromCharCodeArrayImport = addImport(module, + StringBuiltins::fromCharCodeArray, + {nullArray16, Type::i32, Type::i32}, + nnExt); // string.fromCodePoint: codepoint -> ext - fromCodePointImport = addImport(module, "fromCodePoint", Type::i32, nnExt); + fromCodePointImport = + addImport(module, StringBuiltins::fromCodePoint, Type::i32, nnExt); // string.concat: string, string -> string - concatImport = addImport(module, "concat", {nullExt, nullExt}, nnExt); + concatImport = + addImport(module, StringBuiltins::concat, {nullExt, nullExt}, nnExt); // string.intoCharCodeArray: string, array, start -> num written intoCharCodeArrayImport = addImport(module, - "intoCharCodeArray", + StringBuiltins::intoCharCodeArray, {nullExt, nullArray16, Type::i32}, Type::i32); // string.equals: string, string -> i32 - equalsImport = addImport(module, "equals", {nullExt, nullExt}, Type::i32); + equalsImport = + addImport(module, StringBuiltins::equals, {nullExt, nullExt}, Type::i32); // string.test: externref -> i32 - testImport = addImport(module, "test", {nullExt}, Type::i32); + testImport = addImport(module, StringBuiltins::test, {nullExt}, Type::i32); // string.compare: string, string -> i32 - compareImport = addImport(module, "compare", {nullExt, nullExt}, Type::i32); + compareImport = + addImport(module, StringBuiltins::compare, {nullExt, nullExt}, Type::i32); // string.length: string -> i32 - lengthImport = addImport(module, "length", nullExt, Type::i32); + lengthImport = + addImport(module, StringBuiltins::length, nullExt, Type::i32); // string.codePointAt: string, offset -> i32 - charCodeAtImport = - addImport(module, "charCodeAt", {nullExt, Type::i32}, Type::i32); + charCodeAtImport = addImport( + module, StringBuiltins::charCodeAt, {nullExt, Type::i32}, Type::i32); // string.substring: string, start, end -> string - substringImport = - addImport(module, "substring", {nullExt, Type::i32, Type::i32}, nnExt); + substringImport = addImport(module, + StringBuiltins::substring, + {nullExt, Type::i32, Type::i32}, + nnExt); // Replace the string instructions in parallel. struct Replacer : public WalkerPass> {