1 /*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "remove_unused_functions.h"
17 #include "llvm_ark_interface.h"
18 #include "inline_ir_utils.h"
19 #include "llvm_compiler_options.h"
20
21 #include <llvm/Pass.h>
22 #include <llvm/IR/InlineAsm.h>
23 #include <llvm/IR/Module.h>
24 #include <llvm/IR/Verifier.h>
25 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
26 #include <llvm/Transforms/IPO/FunctionImport.h>
27
28 #define DEBUG_TYPE "remove-unused-functions"
29
30 using llvm::Argument;
31 using llvm::BasicBlock;
32 using llvm::cast;
33 using llvm::convertToDeclaration;
34 using llvm::DenseSet;
35 using llvm::Function;
36 using llvm::InlineAsm;
37 using llvm::isa;
38 using llvm::User;
39 using llvm::Value;
40
41 namespace ark::llvmbackend::passes {
42
ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions * options)43 bool RemoveUnusedFunctions::ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions *options)
44 {
45 return options->doIrtocInline;
46 }
47
run(llvm::Module & module,llvm::ModuleAnalysisManager &)48 llvm::PreservedAnalyses RemoveUnusedFunctions::run(llvm::Module &module, llvm::ModuleAnalysisManager & /*AM*/)
49 {
50 DenseSet<Function *> usedFunctions;
51 for (auto &function : module.functions()) {
52 if (function.getMetadata(LLVMArkInterface::FUNCTION_MD_INLINE_MODULE) != nullptr) {
53 LLVM_DEBUG(llvm::dbgs() << "Skip " << function.getName() << " from inline module\n");
54 continue;
55 }
56 if (function.isDeclaration()) {
57 continue;
58 }
59 LLVM_DEBUG(llvm::dbgs() << function.getName() << " is root\n");
60 DenseSet<Value *> seen;
61 VisitValue(usedFunctions, function, seen);
62 }
63
64 bool changed = false;
65 for (auto &function : module.functions()) {
66 if (!usedFunctions.contains(&function)) {
67 LLVM_DEBUG(llvm::dbgs() << "Deleted body of " << function.getName() << "\n");
68 convertToDeclaration(function);
69 changed = true;
70 }
71 }
72
73 changed |= ark::llvmbackend::RemoveDanglingAliases(module);
74 return changed ? llvm::PreservedAnalyses::none() : llvm::PreservedAnalyses::all();
75 }
VisitValue(DenseSet<Function * > & usedFunctions,Value & value,DenseSet<Value * > & seenValues)76 void RemoveUnusedFunctions::VisitValue(DenseSet<Function *> &usedFunctions, Value &value, DenseSet<Value *> &seenValues)
77 {
78 if (seenValues.contains(&value)) {
79 return;
80 }
81
82 seenValues.insert(&value);
83
84 if (isa<Function>(value)) {
85 auto &function = cast<Function>(value);
86 if (usedFunctions.contains(&function)) {
87 return;
88 }
89
90 usedFunctions.insert(&function);
91 DenseSet<Value *> seen;
92 for (auto &basicBlock : function) {
93 VisitValue(usedFunctions, basicBlock, seen);
94 }
95 } else if (isa<BasicBlock>(value)) {
96 auto &basicBlock = cast<BasicBlock>(value);
97 for (auto &instruction : basicBlock) {
98 VisitValue(usedFunctions, instruction, seenValues);
99 }
100 } else if (isa<User>(value)) {
101 auto &user = cast<User>(value);
102 for (auto operand : user.operand_values()) {
103 VisitValue(usedFunctions, *operand, seenValues);
104 }
105 } else {
106 if (isa<Argument, llvm::MetadataAsValue, InlineAsm>(value)) {
107 return;
108 }
109 LLVM_DEBUG(llvm::dbgs() << "Value = ");
110 LLVM_DEBUG(value.print(llvm::dbgs()));
111 LLVM_DEBUG(llvm::dbgs() << "\n");
112 llvm_unreachable("Unexpected value");
113 }
114 }
115
116 } // namespace ark::llvmbackend::passes
117