12

通过扩展FunctionPass类,我在 LLVM 中编写了标准分析传递。一切似乎都说得通。

现在我想做的是编写几个模块间通道,即允许我一次分析多个模块的通道。一个这样的传递的目的是构建整个应用程序的调用图。另一个这样的传递的目的是我对涉及函数调用及其参数的优化有一个想法。

我通过扩展ModulePass类了解 LLVM 中的过程间传递,但这仅允许在单个模块内进行分析。

我知道LLVM 中的链接时间优化 (LTO),但是 (a) 我不太清楚这是否是我想要的,并且 (b) 我没有找到关于如何实际编写LTO 通行证的示例或文档。

如何在 LLVM 中编写模块间传递,即可以访问应用程序中所有模块的传递?

4

3 回答 3

7

我找到了实现目标的一种方法:编写一个简单的程序,用于llvm::parseBitcodeFile()读取位码文件并创建一个Module可以遍历和分析的对象。这并不理想,因为它不是可以在 LLVM 框架内运行的 Pass。但是,这实现我一次分析多个模块的目标的一种方式。

对于未来的读者,这就是我所做的。

创建一个简单的工具来读取位码文件并生成一个Module

//ReadBitcode.cpp
#include <iostream>
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Bitcode/ReaderWriter.h"

using namespace llvm;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " bitcode_filename" << std::endl;
        return 1;
    }
    StringRef filename = argv[1];
    LLVMContext context;

    ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr = MemoryBuffer::getFileOrSTDIN(filename);
    if (std::error_code ec = fileOrErr.getError())
    {
        std::cerr << "Error opening input file: " + ec.message() << std::endl;
        return 2;
    }

    ErrorOr<llvm::Module *> moduleOrErr = parseBitcodeFile(fileOrErr.get()->getMemBufferRef(), context);
    if (std::error_code ec = fileOrErr.getError())
    {
        std::cerr << "Error reading Module: " + ec.message() << std::endl;
        return 3;
    }

    Module *m = moduleOrErr.get();
    std::cout << "Successfully read Module:" << std::endl;
    std::cout << " Name: " << m->getName().str() << std::endl;
    std::cout << " Target triple: " << m->getTargetTriple() << std::endl;

    for (auto iter1 = m->getFunctionList().begin(); iter1 != m->getFunctionList().end(); iter1++)
    {
        Function &f = *iter1;
        std::cout << "  Function: " << f.getName().str() << std::endl;
        for (auto iter2 = f.getBasicBlockList().begin(); iter2 != f.getBasicBlockList().end();
             iter2++)
        {
            BasicBlock &bb = *iter2;
            std::cout << "    BasicBlock: " << bb.getName().str() << std::endl;
            for (auto iter3 = bb.begin(); iter3 != bb.end(); iter3++)
            {
                Instruction &i = *iter3;
                std::cout << "      Instruction: " << i.getOpcodeName() << std::endl;
            }
        }
    }
    return 0;
}

编译工具

$ clang++ ReadBitcode.cpp -o reader `llvm-config --cxxflags --libs --ldflags --system-libs`

创建要分析的位码文件

$ cat foo.c 
int my_fun(int arg1){
    int x = arg1;
    return x+1;
}

int main(){
    int a = 11;
    int b = 22;
    int c = 33;
    int d = 44;
    if (a > 10){
        b = c;
    } else {
        b = my_fun(d);
    }
    return b;
}

$ clang -emit-llvm -o foo.bc -c foo.c

在位码上运行该reader工具

$ ./reader foo.bc
Successfully read Module:
 Name: foo.bc
 Target triple: x86_64-pc-linux-gnu
  Function: my_fun
    BasicBlock: 
      Instruction: alloca
      Instruction: alloca
      Instruction: store
      Instruction: load
      Instruction: store
      Instruction: load
      Instruction: add
      Instruction: ret
  Function: main
    BasicBlock: 
      Instruction: alloca
      Instruction: alloca
      Instruction: alloca
      Instruction: alloca
      Instruction: alloca
      Instruction: store
      Instruction: store
      Instruction: store
      Instruction: store
      Instruction: store
      Instruction: load
      Instruction: icmp
      Instruction: br
    BasicBlock: 
      Instruction: load
      Instruction: store
      Instruction: br
    BasicBlock: 
      Instruction: load
      Instruction: call
      Instruction: store
      Instruction: br
    BasicBlock: 
      Instruction: load
      Instruction: ret
于 2015-05-13T13:05:43.223 回答
5

这可以使用模块传递来完成。下面是我的代码,如果你需要帮助运行它,你可以看这里

酒吧.c

int your_fun(int arg2) {
    int x = arg2;
    return x+2;
}

骨架.cpp

#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;

namespace {
  struct SkeletonPass : public ModulePass {
    static char ID;
    SkeletonPass() : ModulePass(ID) {}

    virtual bool runOnModule(Module &M) {
        for (auto& F : M) {
            errs() << "\tFunction: " << F.getName() << "\n";

            for (auto& BB : F) {
                errs() << "\t\tBasic Block: " << BB.getName() << "\n";

                for (auto& I : BB) {
                    errs() << "\t\t\tInstruction: " << I.getOpcodeName() << "\n";
                }
            }
        }

        return false;
    }
  };
}

char SkeletonPass::ID = 0;

// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder &,
                         legacy::PassManagerBase &PM) {
  PM.add(new SkeletonPass());
}

static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_ModuleOptimizerEarly,
                                                registerSkeletonPass);

static RegisterStandardPasses RegisterMyPass1(PassManagerBuilder::EP_EnabledOnOptLevel0,
                                                registerSkeletonPass);

输出:

| => clang -Xclang -load -Xclang build/skeleton/libSkeletonPass.so foo.c bar.c
Module: foo.c!
        Function: my_fun!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: load
            Instruction: store
            Instruction: load
            Instruction: add
            Instruction: ret
        Function: main!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: load
            Instruction: icmp
            Instruction: br
            Basicblock: if.then!
            Instruction: load
            Instruction: store
            Instruction: br
            Basicblock: if.else!
            Instruction: load
            Instruction: call
            Instruction: store
            Instruction: br
            Basicblock: if.end!
            Instruction: load
            Instruction: ret
Module: bar.c!
        Function: your_fun!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: load
            Instruction: store
            Instruction: load
            Instruction: add
            Instruction: ret

输出:如果包含链接到 bar.c 的头文件

Module: foo.c!
        Function: your_fun!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: load
            Instruction: store
            Instruction: load
            Instruction: add
            Instruction: ret
        Function: my_fun!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: load
            Instruction: store
            Instruction: load
            Instruction: add
            Instruction: ret
        Function: main!
            Basicblock: entry!
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: alloca
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: store
            Instruction: load
            Instruction: icmp
            Instruction: br
            Basicblock: if.then!
            Instruction: load
            Instruction: store
            Instruction: br
            Basicblock: if.else!
            Instruction: load
            Instruction: call
            Instruction: store
            Instruction: load
            Instruction: call
            Instruction: store
            Instruction: br
            Basicblock: if.end!
            Instruction: load
            Instruction: ret
于 2016-03-29T17:55:47.893 回答
4

在 LTO 中,所有模块都组合在一起,您可以在一个模块中看到整个程序 IR。

您需要像任何模块通行证一样编写模块通行证,并将其添加到 PassManagerBuilder.cpp 中 populateLTOPassManager 函数中的 LTO 通行证列表中。这是 PassManagerBuilder 的文档:http: //llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html

执行此操作时,您的通行证将与其他 LTO 通行证一起执行。

于 2016-12-13T01:45:00.933 回答