diff --git a/llvm/include/llvm/Transforms/IPO/StripSymbols.h b/llvm/include/llvm/Transforms/IPO/StripSymbols.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/IPO/StripSymbols.h @@ -0,0 +1,47 @@ +//===- StripSymbols.h - Strip symbols and debug info from a module --------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// The StripSymbols transformation implements code stripping. Specifically, it +// can delete: +// +// * names for virtual registers +// * symbols for internal globals and functions +// * debug information +// +// Note that this transformation makes code much less readable, so it should +// only be used in situations where the 'strip' utility would be used, such as +// reducing code size or making it harder to reverse engineer code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_IPO_STRIPSYMBOLS_H +#define LLVM_TRANSFORMS_IPO_STRIPSYMBOLS_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct StripSymbolsPass : PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +struct StripNonDebugSymbolsPass : PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +struct StripDebugDeclarePass : PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +struct StripDeadDebugInfoPass : PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_IPO_STRIPSYMBOLS_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -101,6 +101,7 @@ #include "llvm/Transforms/IPO/SCCP.h" #include "llvm/Transforms/IPO/SampleProfile.h" #include "llvm/Transforms/IPO/StripDeadPrototypes.h" +#include "llvm/Transforms/IPO/StripSymbols.h" #include "llvm/Transforms/IPO/SyntheticCountsPropagation.h" #include "llvm/Transforms/IPO/WholeProgramDevirt.h" #include "llvm/Transforms/InstCombine/InstCombine.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -88,7 +88,11 @@ buildInlinerPipeline(OptimizationLevel::Oz, ThinLTOPhase::None, DebugLogging)) MODULE_PASS("oz-module-optimizer", buildModuleOptimizationPipeline(OptimizationLevel::Oz, DebugLogging, /*LTOPreLink*/false)) +MODULE_PASS("strip", StripSymbolsPass()) +MODULE_PASS("strip-dead-debug-info", StripDeadDebugInfoPass()) MODULE_PASS("strip-dead-prototypes", StripDeadPrototypesPass()) +MODULE_PASS("strip-debug-declare", StripDebugDeclarePass()) +MODULE_PASS("strip-nondebug", StripNonDebugSymbolsPass()) MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation()) MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass(nullptr, nullptr)) MODULE_PASS("verify", VerifierPass()) diff --git a/llvm/lib/Transforms/IPO/StripSymbols.cpp b/llvm/lib/Transforms/IPO/StripSymbols.cpp --- a/llvm/lib/Transforms/IPO/StripSymbols.cpp +++ b/llvm/lib/Transforms/IPO/StripSymbols.cpp @@ -19,18 +19,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/StripSymbols.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/TypeFinder.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Utils/Local.h" + using namespace llvm; namespace { @@ -249,9 +252,7 @@ return StripSymbolNames(M, true); } -bool StripDebugDeclare::runOnModule(Module &M) { - if (skipModule(M)) - return false; +static bool stripDebugDeclareImpl(Module &M) { Function *Declare = M.getFunction("llvm.dbg.declare"); std::vector DeadConstants; @@ -289,17 +290,13 @@ return true; } -/// Remove any debug info for global variables/functions in the given module for -/// which said global variable/function no longer exists (i.e. is null). -/// -/// Debugging information is encoded in llvm IR using metadata. This is designed -/// such a way that debug info for symbols preserved even if symbols are -/// optimized away by the optimizer. This special pass removes debug info for -/// such symbols. -bool StripDeadDebugInfo::runOnModule(Module &M) { +bool StripDebugDeclare::runOnModule(Module &M) { if (skipModule(M)) return false; + return stripDebugDeclareImpl(M); +} +static bool stripDeadDebugInfoImpl(Module &M) { bool Changed = false; LLVMContext &C = M.getContext(); @@ -380,3 +377,40 @@ return Changed; } + +/// Remove any debug info for global variables/functions in the given module for +/// which said global variable/function no longer exists (i.e. is null). +/// +/// Debugging information is encoded in llvm IR using metadata. This is designed +/// such a way that debug info for symbols preserved even if symbols are +/// optimized away by the optimizer. This special pass removes debug info for +/// such symbols. +bool StripDeadDebugInfo::runOnModule(Module &M) { + if (skipModule(M)) + return false; + return stripDeadDebugInfoImpl(M); +} + +PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) { + StripDebugInfo(M); + StripSymbolNames(M, false); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M, + ModuleAnalysisManager &AM) { + StripSymbolNames(M, true); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripDebugDeclarePass::run(Module &M, + ModuleAnalysisManager &AM) { + stripDebugDeclareImpl(M); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripDeadDebugInfoPass::run(Module &M, + ModuleAnalysisManager &AM) { + stripDeadDebugInfoImpl(M); + return PreservedAnalyses::all(); +} diff --git a/llvm/test/Transforms/StripSymbols/2007-01-15-llvm.used.ll b/llvm/test/Transforms/StripSymbols/2007-01-15-llvm.used.ll --- a/llvm/test/Transforms/StripSymbols/2007-01-15-llvm.used.ll +++ b/llvm/test/Transforms/StripSymbols/2007-01-15-llvm.used.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -strip -S | FileCheck %s +; RUN: opt < %s -passes=strip -S | FileCheck %s ; CHECK: foo ; CHECK: bar diff --git a/llvm/test/Transforms/StripSymbols/2010-06-30-StripDebug.ll b/llvm/test/Transforms/StripSymbols/2010-06-30-StripDebug.ll --- a/llvm/test/Transforms/StripSymbols/2010-06-30-StripDebug.ll +++ b/llvm/test/Transforms/StripSymbols/2010-06-30-StripDebug.ll @@ -31,4 +31,4 @@ !6 = !{!0} !7 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !2, file: !2, line: 2, type: !8, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: true, unit: !5) !8 = !DISubroutineType(types: !9) -!9 = !{null}!10 = !DILocalVariable(name: "y", scope: !11, file: !2, line: 3, type: !3)!11 = distinct !DILexicalBlock(scope: !7, file: !2, line: 2)!12 = !DIExpression()!13 = !DILocation(line: 3, scope: !11)!14 = !DILocation(line: 4, scope: !11) \ No newline at end of file +!9 = !{null}!10 = !DILocalVariable(name: "y", scope: !11, file: !2, line: 3, type: !3)!11 = distinct !DILexicalBlock(scope: !7, file: !2, line: 2)!12 = !DIExpression()!13 = !DILocation(line: 3, scope: !11)!14 = !DILocation(line: 4, scope: !11) diff --git a/llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll b/llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll --- a/llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll +++ b/llvm/test/Transforms/StripSymbols/strip-dead-debug-info.ll @@ -1,4 +1,5 @@ ; RUN: opt -strip-dead-debug-info -verify %s -S | FileCheck %s +; RUN: opt -passes='strip-dead-debug-info,verify' %s -S | FileCheck %s ; CHECK: ModuleID = '{{.*}}' ; CHECK-NOT: "bar"