[llvm-extract] Add -keep-const-init commandline option

Summary:
This adds -keep-const-init option to llvm-extract which preserves initializers of
used global constants.

For example:

```
$ cat a.ll
@g = constant i32 0
define i32 @f() {
  %v = load i32, i32* @g
  ret i32 %v
}

$ llvm-extract --func=f a.ll -S -o -
@g = external constant i32
define i32 @f() { .. }

$ llvm-extract --func=f a.ll -keep-const-init -S -o -
@g = constant i32 0
define i32 @f() { .. }
```

This option is useful in checking whether a function that uses a constant global is optimized correctly.

Reviewers: jsji, MaskRay, david2050

Reviewed By: MaskRay

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73833
This commit is contained in:
Juneyoung Lee 2020-02-02 02:34:10 +09:00
parent 47f309d963
commit 578d2e2cb1
5 changed files with 33 additions and 8 deletions

View File

@ -55,6 +55,10 @@ OPTIONS
bitcode. All global variables matching the regular expression will be bitcode. All global variables matching the regular expression will be
extracted. May be specified multiple times. extracted. May be specified multiple times.
**--keep-const-init**
Preserve the values of constant globals.
**-help** **-help**
Print a summary of command line options. Print a summary of command line options.

View File

@ -84,10 +84,12 @@ ModulePass *createEliminateAvailableExternallyPass();
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// createGVExtractionPass - If deleteFn is true, this pass deletes /// createGVExtractionPass - If deleteFn is true, this pass deletes
/// the specified global values. Otherwise, it deletes as much of the module as /// the specified global values. Otherwise, it deletes as much of the module as
/// possible, except for the global values specified. /// possible, except for the global values specified. If keepConstInit is true,
/// the initializers of global constants are not deleted even if they are
/// unused.
/// ///
ModulePass *createGVExtractionPass(std::vector<GlobalValue*>& GVs, bool ModulePass *createGVExtractionPass(std::vector<GlobalValue*>& GVs, bool
deleteFn = false); deleteFn = false, bool keepConstInit = false);
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// This pass performs iterative function importing from other modules. /// This pass performs iterative function importing from other modules.

View File

@ -54,6 +54,7 @@ namespace {
class GVExtractorPass : public ModulePass { class GVExtractorPass : public ModulePass {
SetVector<GlobalValue *> Named; SetVector<GlobalValue *> Named;
bool deleteStuff; bool deleteStuff;
bool keepConstInit;
public: public:
static char ID; // Pass identification, replacement for typeid static char ID; // Pass identification, replacement for typeid
@ -61,8 +62,9 @@ namespace {
/// Otherwise, it deletes as much of the module as possible, except for the /// Otherwise, it deletes as much of the module as possible, except for the
/// global values specified. /// global values specified.
explicit GVExtractorPass(std::vector<GlobalValue*> &GVs, explicit GVExtractorPass(std::vector<GlobalValue*> &GVs,
bool deleteS = true) bool deleteS = true, bool keepConstInit = false)
: ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS) {} : ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
keepConstInit(keepConstInit) {}
bool runOnModule(Module &M) override { bool runOnModule(Module &M) override {
if (skipModule(M)) if (skipModule(M))
@ -83,7 +85,8 @@ namespace {
for (Module::global_iterator I = M.global_begin(), E = M.global_end(); for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) { I != E; ++I) {
bool Delete = bool Delete =
deleteStuff == (bool)Named.count(&*I) && !I->isDeclaration(); deleteStuff == (bool)Named.count(&*I) && !I->isDeclaration() &&
(!I->isConstant() || !keepConstInit);
if (!Delete) { if (!Delete) {
if (I->hasAvailableExternallyLinkage()) if (I->hasAvailableExternallyLinkage())
continue; continue;
@ -156,6 +159,6 @@ namespace {
} }
ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs, ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs,
bool deleteFn) { bool deleteFn, bool keepConstInit) {
return new GVExtractorPass(GVs, deleteFn); return new GVExtractorPass(GVs, deleteFn, keepConstInit);
} }

View File

@ -0,0 +1,12 @@
; RUN: llvm-extract -func foo -keep-const-init -S < %s | FileCheck %s
; RUN: llvm-extract -func foo -S < %s | FileCheck %s --check-prefix=CHECK2
; CHECK: @cv = constant i32 0
; CHECK2: @cv = external constant i32
@cv = constant i32 0
define i32 @foo() {
%v = load i32, i32* @cv
ret i32 %v
}

View File

@ -53,6 +53,10 @@ static cl::opt<bool> DeleteFn("delete",
cl::desc("Delete specified Globals from Module"), cl::desc("Delete specified Globals from Module"),
cl::cat(ExtractCat)); cl::cat(ExtractCat));
static cl::opt<bool> KeepConstInit("keep-const-init",
cl::desc("Keep initializers of constants"),
cl::cat(ExtractCat));
static cl::opt<bool> static cl::opt<bool>
Recursive("recursive", cl::desc("Recursively extract all called functions"), Recursive("recursive", cl::desc("Recursively extract all called functions"),
cl::cat(ExtractCat)); cl::cat(ExtractCat));
@ -333,7 +337,7 @@ int main(int argc, char **argv) {
{ {
std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end()); std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end());
legacy::PassManager Extract; legacy::PassManager Extract;
Extract.add(createGVExtractionPass(Gvs, DeleteFn)); Extract.add(createGVExtractionPass(Gvs, DeleteFn, KeepConstInit));
Extract.run(*M); Extract.run(*M);
// Now that we have all the GVs we want, mark the module as fully // Now that we have all the GVs we want, mark the module as fully