Comment rédiger un laissez-passer intermodulaire personnalisé en LLVM?

j'ai écrit un passe D'analyse standard en LLVM, en prolongeant le FunctionPass classe. Tout semble faire sens.

maintenant, ce que j'aimerais faire, c'est écrire quelques passages intermodulaires, c'est-à-dire des passages qui me permettent d'analyser plus d'un module à la fois. Le but d'un tel col est de construire un graphe d'appel de l'ensemble de l'application. Le but de l'autre passe, c'est que j'ai une idée pour une optimisation impliquant des appels de fonction et de leur paramètre.

je sais à propos de interprocedural passe dans LLVM, via l'extension de l' ModulePass classe, mais qui ne permet l'analyse dans un seul module.

je sais link time optimization (LTO) dans LLVM, mais (a) Je ne suis pas tout à fait clair si c'est ce que je veux et (b) Je n'ai trouvé aucun exemple ou de la documentation sur la façon de réellement écrire un LTO pass.

Comment puis-je écrire une passe intermodulaire, c.-à-d. une passe qui a accès à tous les modules d'une application, en LLVM?

10
demandé sur stepthom 2015-05-12 21:01:58

3 réponses

j'ai trouvé un moyen pour atteindre mon objectif: écrire un programme simple qui utilise llvm::parseBitcodeFile() lire dans un fichier bitcode et créer un Module objet qui peut être parcouru et analysé. Ce N'est pas idéal, car ce N'est pas un laissez-passer qui peut être exécuté dans le cadre du LLVM. Cependant, il une façon d'atteindre mon objectif d'analyser plusieurs modules à la fois.

Pour les futurs lecteurs, voici ce que j'ai fait.

créer un outil simple pour lire dans un fichier bitcode et produire un 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;
}

Compiler l'outil

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

créer un fichier bitcode pour analyser

$ 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

Exécuter reader outil sur le bitcode

$ ./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
3
répondu stepthom 2015-05-13 13:05:43

cela peut être fait en utilisant un module pass. Ci-dessous mon code, et si vous avez besoin d'aide en l'exécutant, vous pouvez regarder ici.

bar.c

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

Squelette.rpc

#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);

Sortie:

| => 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

sortie: si vous incluez un lien de fichier d'en-tête vers la barre.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
3
répondu 2016-03-30 15:40:23

dans LTO tous les modules sont combinés et vous pouvez voir le programme entier IR dans un module.

vous devez écrire un pass de module comme n'importe quel pass de module et l'ajouter à la liste des passes de LTO dans la fonction populateLTOPassManager dans PassManagerBuilder.rpc. Voici le doc pour PassManagerBuilder: http://llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html

quand vous faites ceci, votre passe sera exécutée avec d'autres passes LTO.

2
répondu Anil Altinay 2016-12-13 01:45:00