我只是LLVM和(https://www.cs.cornell.edu/~asampson/blog/llvm.html)网页以及堆栈溢出的初学者,而我的研究员也为我提供了很多帮助。 首先,我想说明一下我正在尝试解决的问题,然后将介绍解决该问题所采用的方法。 然后,如果我有任何缺失,我需要您的建议和指导。
我的输入是一个C程序,输出是它的SSA形式,其前缀表示形式打印在输出文件中。 例如,如果C代码段是:
x=4;
x++;
z=x+7;
以前缀表示的输出SSA形式为:
( = x0 4)
( = x1 (+ x0 1) )
( = z (x1 + 7) )
请暂时忽略实际的IR指令,仅假设我能够读取IR并将其转换为这种形式,并带有一些额外的语句(为便于阅读,此处不再赘述)。
using namespace llvm;
namespace {
struct TestPass: public ModulePass {
IRssa::ptr ir_ssa = IRssa::ptr(new IRssa());
static char ID;
typedef std::list<std::pair<std::string, std::list<Instruction *> > > funcDump;
TestPass() : ModulePass(ID) { }
std::map<std::string, funcDump> workingList;
bool runOnModule(Module &M) {
std::string funcName, bkName;
for (Function &F : M) { //Found a new Function
if (isa<Function>(F) && !(F.getName().startswith("llvm."))) {
funcName = F.getName();
std::pair<std::string, std::list<Instruction *> > funcBlockList;
std::list<std::pair<std::string, std::list<Instruction *> > > wholeFuncBlocks;
for (BasicBlock &B : F) { //Blocks of the Function
if (isa<BasicBlock>(B)) {
bkName = B.getName();
}
std::list<Instruction *> listInst;
for (auto &I : B) {
Instruction *ins;
ins = &I;
listInst.push_back(ins);
}
funcBlockList.first = bkName;
funcBlockList.second = listInst;
wholeFuncBlocks.push_back(funcBlockList);
}
workingList[funcName] = wholeFuncBlocks;//Mapping of the functions
}
}
ir_ssa->setFunctionDump(workingList);
funcDump funcData;
funcData = workingList["start_program"]; //Starting from the start_program function
convertFunctionToSSA(funcData, ir_ssa);
std::ofstream outFile;
outFile.open("Out.ssa");
printSSA_toFile(outFile, ir_ssa);
return false;
}
};
}
char TestPass::ID = 0;
static RegisterPass<TestPass> X("testPass", "Testing A Pass");
static void registerTestPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) {
PM.add(new TestPass());
}
static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_ModuleOptimizerEarly, registerTestPass);
static RegisterStandardPasses RegisterMyPass0(PassManagerBuilder::EP_EnabledOnOptLevel0, registerTestPass);
//Automatically enable the pass (http://adriansampson.net/blog/clangpass.html)
如上所述,我正在调用runOnModule()并将程序中每个功能的所有块的所有IR指令收集到workingList数据结构中(在这种情况下为std :: map)。给定程序中的所有功能读取完后,我便一次完成读取红外线指令的必要任务,逐个功能逐个块读取(在用户定义的函数convertFunctionToSSA(funcData,ir_ssa)中使用整个函数将IR作为参数,并在参数ir_ssa中返回处理这些IR的结果。我还将ir_ssa的结果值打印到输出文件outFile中。
clang -O1 -g -Xclang -emit-llvm -c someProgram.c -o test.bc
opt -O1 -instnamer -mem2reg -simplifycfg -loops -lcssa -loop-simplify -loop-rotate -loop-unroll -unroll-count=15 -unroll-allow-partial -load src/libTestPass.so -testPass test.bc -o test
根据我的理解,我假设以上两个命令将执行以下操作。 第一个clang使用程序someProgram.c并生成IR作为输出文件“ test.bc”。 下一个命令opt,使用文件“ test.bc”,然后逐个应用上述所有步骤,直到最后一个步骤“ -unroll-allow-partial”,并且它还链接了我的库libTestPass.so(此.so文件是然后在编译上述ModulePass程序时生成),最后,传递“ -testPass”,我认为这是我正在执行我的过程(转换为SSA前缀表示形式)的传递。
我不确定LLVM是否按照我所假设的顺序实际运行(我的期望)。如果我缺少任何东西或我的假设不正确,请发表评论。另外,如有必要,请随时询问更多详细信息。
我能够成功转换大多数C程序,但是在一个特定程序上,我遇到了一些错误。调试该错误使我认为我对LLVM的这种工作方式缺乏思索,或者关于clang和opt的调用顺序的假设是不正确的。
我们非常感谢您的帮助。