//===-- WebAssemblyFixFunctionBitcasts.cpp - Fix function bitcasts --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// Fix bitcasted functions. /// /// WebAssembly requires caller and callee signatures to match, however in LLVM, /// some amount of slop is vaguely permitted. Detect mismatch by looking for /// bitcasts of functions and rewrite them to use wrapper functions instead. /// /// This doesn't catch all cases, such as when a function's address is taken in /// one place and casted in another, but it works for many common cases. /// /// Note that LLVM already optimizes away function bitcasts in common cases by /// dropping arguments as needed, so this pass only ends up getting used in less /// common cases. /// //===----------------------------------------------------------------------===// #include "WebAssembly.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" usingnamespacellvm; #define DEBUG_TYPE … namespace { class FixFunctionBitcasts final : public ModulePass { … }; } // End anonymous namespace char FixFunctionBitcasts::ID = …; INITIALIZE_PASS(…) ModulePass *llvm::createWebAssemblyFixFunctionBitcasts() { … } // Recursively descend the def-use lists from V to find non-bitcast users of // bitcasts of V. static void findUses(Value *V, Function &F, SmallVectorImpl<std::pair<CallBase *, Function *>> &Uses) { … } // Create a wrapper function with type Ty that calls F (which may have a // different type). Attempt to support common bitcasted function idioms: // - Call with more arguments than needed: arguments are dropped // - Call with fewer arguments than needed: arguments are filled in with undef // - Return value is not needed: drop it // - Return value needed but not present: supply an undef // // If the all the argument types of trivially castable to one another (i.e. // I32 vs pointer type) then we don't create a wrapper at all (return nullptr // instead). // // If there is a type mismatch that we know would result in an invalid wasm // module then generate wrapper that contains unreachable (i.e. abort at // runtime). Such programs are deep into undefined behaviour territory, // but we choose to fail at runtime rather than generate and invalid module // or fail at compiler time. The reason we delay the error is that we want // to support the CMake which expects to be able to compile and link programs // that refer to functions with entirely incorrect signatures (this is how // CMake detects the existence of a function in a toolchain). // // For bitcasts that involve struct types we don't know at this stage if they // would be equivalent at the wasm level and so we can't know if we need to // generate a wrapper. static Function *createWrapper(Function *F, FunctionType *Ty) { … } // Test whether a main function with type FuncTy should be rewritten to have // type MainTy. static bool shouldFixMainFunction(FunctionType *FuncTy, FunctionType *MainTy) { … } bool FixFunctionBitcasts::runOnModule(Module &M) { … }