Files
MobileGL/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameBuiltinShadowingFunctionsPass.cpp
T
BZLZHH b228f813c0 [Perf] (MG_Util): replace the builtin-shadowing string scans with one tokenize and a SPIR-V OpName pass
RenameBuiltinShadowingFunction probed the whole source ten times per compile
(5 names x mask + scan, each a full-text pass) and still had two blind spots:
a 5-name list and single-line-definition-only detection. On Complementary-scale
packs (4.5MB of sources) that was ~68% of the compile phase.

The rename is now split by FAILURE LAYER, both halves sharing one name table
header so they cannot drift:

- A SPIR-V OpName pass in SanitizeAndOptimizeBinary covers the full ESSL 3.20
  builtin set (~146 names). Renaming a function id is safe by construction:
  builtin calls are GLSL.std.450 instructions and can never resolve to a user
  OpFunction, overloads are distinct ids (a helper overload delegating to the
  real builtin keeps working), dead preprocessor branches never reach SPIR-V,
  and macro-expanded definitions are covered. ESSL 3.x is the only consumer
  that forbids the redefinitions, and this pass runs before its transpile.

- A lexical pass covers only the 5 names whose exact-signature redefinitions
  glslang's relaxed parse rejects outright (never producing SPIR-V for the
  backstop): the historical fma/max3/min3/round/tanh. One TokenizeCode pass;
  definition detection requires brace depth 0, a type-identifier previous
  token that is neither a statement keyword nor a directive tail, and skips
  files whose token-level braces do not balance (preprocessor-asymmetric
  arms) - over-detection is unrecoverable, so every ambiguity falls through
  to the backstop.

Measured on the compile phase (prefix-diff, 3-run medians, Espryt/NVIDIA):
complementary-reimagined 20.0s -> 5.5s, BSL 2.14s -> 1.85s. bliss (the pack
that ships from-scratch fma/tanh helpers) stays at SSIM 0.999962.

Tests: end-to-end ESSL assertions for the multiline-definition and
new-overload shapes, the three adversarial-review reproductions (statement-
keyword call under asymmetric braces, dead-#if compat shim, overload
delegating to the shadowed builtin), and a source-level assertion pinning
the lexical half specifically.
2026-08-08 03:11:38 -04:00

63 lines
2.6 KiB
C++

// MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameBuiltinShadowingFunctionsPass.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include "RenameBuiltinShadowingFunctionsPass.h"
#include <string>
#include <string_view>
#include "../EsslBuiltinFunctionNames.h"
#include "spirv.hpp"
#include "source/opt/def_use_manager.h"
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "source/util/make_unique.h"
namespace MobileGL {
namespace MG_Util {
namespace ShaderTranspiler {
spvtools::opt::Pass::Status RenameBuiltinShadowingFunctionsPass::Process() {
Bool modified = false;
auto* irContext = context();
auto* defUseMgr = irContext->get_def_use_mgr();
for (auto& debugInst : irContext->debugs2()) {
if (debugInst.opcode() != spv::Op::OpName || debugInst.NumInOperands() < 2) {
continue;
}
const auto* target = defUseMgr->GetDef(debugInst.GetSingleWordInOperand(0));
if (target == nullptr || target->opcode() != spv::Op::OpFunction) {
continue;
}
// glslang mangles function OpNames as "name(<paramcodes>"; the base name is
// everything before the '(' (entry points like "main" carry no mangling).
const std::string mangled = debugInst.GetInOperand(1).AsString();
const std::string_view baseName =
std::string_view(mangled).substr(0, mangled.find('('));
if (!IsEsslBuiltinFunctionName(baseName)) {
continue;
}
debugInst.SetInOperand(1, spvtools::utils::MakeVector<spvtools::opt::Operand::OperandData>(
"mg_" + mangled));
modified = true;
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
spvtools::Optimizer::PassToken
RenameBuiltinShadowingFunctionsPass::CreateRenameBuiltinShadowingFunctionsPass() {
return spvtools::Optimizer::PassToken(MakeUnique<RenameBuiltinShadowingFunctionsPass>());
}
} // namespace ShaderTranspiler
} // namespace MG_Util
} // namespace MobileGL