//===----- HipStdPar.cpp - HIP C++ Standard Parallelism Support Passes ----===// // // 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 // //===----------------------------------------------------------------------===// // This file implements two passes that enable HIP C++ Standard Parallelism // Support: // // 1. AcceleratorCodeSelection (required): Given that only algorithms are // accelerated, and that the accelerated implementation exists in the form of // a compute kernel, we assume that only the kernel, and all functions // reachable from it, constitute code that the user expects the accelerator // to execute. Thus, we identify the set of all functions reachable from // kernels, and then remove all unreachable ones. This last part is necessary // because it is possible for code that the user did not expect to execute on // an accelerator to contain constructs that cannot be handled by the target // BE, which cannot be provably demonstrated to be dead code in general, and // thus can lead to mis-compilation. The degenerate case of this is when a // Module contains no kernels (the parent TU had no algorithm invocations fit // for acceleration), which we handle by completely emptying said module. // **NOTE**: The above does not handle indirectly reachable functions i.e. // it is possible to obtain a case where the target of an indirect // call is otherwise unreachable and thus is removed; this // restriction is aligned with the current `-hipstdpar` limitations // and will be relaxed in the future. // // 2. AllocationInterposition (required only when on-demand paging is // unsupported): Some accelerators or operating systems might not support // transparent on-demand paging. Thus, they would only be able to access // memory that is allocated by an accelerator-aware mechanism. For such cases // the user can opt into enabling allocation / deallocation interposition, // whereby we replace calls to known allocation / deallocation functions with // calls to runtime implemented equivalents that forward the requests to // accelerator-aware interfaces. We also support freeing system allocated // memory that ends up in one of the runtime equivalents, since this can // happen if e.g. a library that was compiled without interposition returns // an allocation that can be validly passed to `free`. //===----------------------------------------------------------------------===// #include "llvm/Transforms/HipStdPar/HipStdPar.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include <cassert> #include <string> #include <utility> usingnamespacellvm; template<typename T> static inline void eraseFromModule(T &ToErase) { … } static inline bool checkIfSupported(GlobalVariable &G) { … } static inline void clearModule(Module &M) { … } static inline void maybeHandleGlobals(Module &M) { … } template<unsigned N> static inline void removeUnreachableFunctions( const SmallPtrSet<const Function *, N>& Reachable, Module &M) { … } static inline bool isAcceleratorExecutionRoot(const Function *F) { … } static inline bool checkIfSupported(const Function *F, const CallBase *CB) { … } PreservedAnalyses HipStdParAcceleratorCodeSelectionPass::run(Module &M, ModuleAnalysisManager &MAM) { … } static constexpr std::pair<StringLiteral, StringLiteral> ReplaceMap[]{ … }; PreservedAnalyses HipStdParAllocationInterpositionPass::run(Module &M, ModuleAnalysisManager&) { … }