Clang编译选项和Pass构建

编译选项相关:前端

想要添加的选项,以我添加的-fdpu为例子frontend

能经过clang --help获得的选项,总体须要一个解析文件(好像在LLVM项目中都是经过后缀名为xxx.tdxxx.def的文件来进行存储的,而后经过xxx.h声明,xxx.cpp真正进行解析)函数

好比添加-fdpu,是在clang/include/Driver/Options.td添加相应的选项(其实就是凭感受加,感受和哪一个比较像就对应加一个,具体的内容没研究明白),我是加成了这样:工具

def fdpu : Flag<["-"], "fdpu">, Flags<[DriverOption, CC1Option]>,ui

  HelpText<"Enable DPU extensions">;url

这个里边的选项都是直接面向用户的,所以加的时候能够不是那么严谨,里边的Flags是标记做为DriverOption和要传递给CC1CC1真正完成编译工做,里边才是咱们须要添加的动做)spa

可是也不要乱加,这个里边实际上是有定义Group的,好比ActionGroup中定义的都是动做,其余像M_Group等的,都是各类语言相应的Group。并且这个Group的定义是有相应的动做,好比像源源变换等操做,最好就再创建一个Action相关的选项,留给CC1使用blog

个人实现是在clang/include/Driver/CC1Options.td中添加了一个要实现源源变化的Action继承

def rewrite_dpu : Flag<["-"], "rewrite-dpu">,ip

  HelpText<"Rewrite dpu source to C">;

上边也说了,这个是一个要驱动进行源源变换的Action,因此被放在了Action_Group组内。

以前也提到了,咱们添加的选项但愿都是由用户指定的,在OptionsCC1Options中添加了选项还不算完,还须要在clang/include/Driver/Types.def中添加两种选项,具体用法还不是特别清楚,只知道最后一个”u”告诉编译器,这是一个用户指定的选项(user specified)

TYPE("dpu-cpp-output",           PP_DPU,       INVALID,         "dpui",  "u")

TYPE("dpu",                      DPU,          PP_DPU,          "c",     "u")

这里不是使用的都是TYPE么,因此后边就会出现TY_XXX的东西

clang/lib/Driver/Types.cpp中对Types.def文件进行了解析,这个函数完成的是文件名后缀字符串的解析types::ID types::lookupTypeForExtension(llvm::StringRef Ext)

咱们在其中添加dpu的解析:

.Case("dpu", TY_DPU)

.Case("dpui", TY_PP_DPU)

也就是咱们这里假设会出现一种专用于DPU平台的xxx.dpui的代码(留做之后使用,目前其实没啥用)

这里作了改动之后,须要在clang能够接受的类型中添加对应的处理,其实就是在

bool types::isAcceptedByClang(ID Id)函数中添加

case TY_DPU: case TY_PP_DPU:

有了类型处理之后,真正进入处理过程。

clang/lib/Driver/Tools.cpp

void Clang::ConstructJob(Compilation &C, const JobAction &JA,

                         const InputInfo &Output, const InputInfoList &Inputs,

                         const ArgList &Args, const char *LinkingOutput) const

这个函数内包含着编译的各个phase的编译工做,好比

isa<AnalyzeJobAction>(JA)

isa<PrecompileJobAction>(JA)

添加对DPU的支持,是在

(isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool.")分支内添加

else if (JA.getType() == types::TY_DPU) {

      CmdArgs.push_back("-fdpu");

  CmdArgs.push_back("-rewrite-dpu");

}

其实就是在真正的编译过程当中加入-fdpu-rewrite-dpu两个选项

这只是在编译过程当中加了选项,还要根据选项添加编译任务。在clang/lib/Driver/Driver.cpp中添加各个阶段真正的任务

好比我是在phases::Compile:阶段添加了

if (Args.hasArg(options::OPT_fdpu)) {

      return new CompileJobAction(Input, types::TY_DPU);

}

同时为了能在最后一个阶段有必定的做用,在

phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg) const

也添加了相应的处理代码

// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.  这个分支下添加

(PhaseArg = DAL.getLastArg(options::OPT_fdpu) ) ||

编译的阶段和编译的任务都添加好了,以后就是具体的Action实现了。整体来讲就是在Frontend中添加响应的Action

先定义好InputKind,在clang/include/clang/Frontend/FrontendOptions.henum InputKind中加入

IK_DPU,

IK_PreprocessedDPU

由于要作个源源变换的工具,在ActionKind中添加响应的项

RewriteDPU,     ///< Run DPU

上边说过了,定义了IK_DPUIK_PreprocessedDPU这两个符号,可是,该怎么解析才能肯定是这两个符号。所以在clang/lib/Frontend/FrontendOptions.cpp中的

InputKind FrontendOptions::getInputKindForExtension(StringRef Extension)中添加

.Case("dpui", IK_PreprocessedDPU)

.Case("dpu",  IK_DPU)

意思就是遇到这样的字符串,就解析成这两个值

clang/lib/Frontend/FrontendActions.cpp中的void PrintPreambleAction::ExecuteAction() 中添加IK_DPUIK_PreprocessedDPU的支持

case IK_DPU:

   break;

case IK_PreprocessedDPU:

前期准备工做基本上差很少了,Action也准备好了,就差真正的调用了。

clang/lib/Frontend/CompilerInstance.cpp中,存在了大量对CompileInstance的设置和修改,为了能对DPU中的输入文件进行兼容,在

static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts)中添加了相应的处理

if (LangOpts.DPU)

    return IK_DPU;

CompileInstance修改好,终于到了真正的调用过程CompileInvocation

clang/lib/Frontend/CompilerInvocation.cpp

static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,

                                   DiagnosticsEngine &Diags,

                                   bool &IsHeaderFile)函数中

是针对前端进行的处理,前边提到了咱们把前端的处理做为ActionGroup中一个子项rewrite_dpu,那么这里的处理代码就应该加在

 if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {

switch (A->getOption().getID())

下边,具体以下:

case OPT_rewrite_dpu:

      Opts.ProgramAction = frontend::RewriteDPU; break;

前边说过,这个是要进行源源变换的,源源变换的输出是c或者dpui

所以在该函数下半部分针对字符串进行解析的时候,添加对应的处理,也就是在

DashX = llvm::StringSwitch<InputKind>(A->getValue())

添加

.Case("dpu", IK_DPU)

.Case("dpu-cpp-output", IK_PreprocessedDPU)

这里一样能够对语言进行设置,我这里是针对

void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,

                                         const llvm::Triple &T,

                                         PreprocessorOptions &PPOpts,

                                         LangStandard::Kind LangStd)函数

if (LangStd == LangStandard::lang_unspecified)分之下进行了支持

case IK_DPU:

    case IK_PreprocessedDPU:

      LangStd = LangStandard::lang_gnu11; //C++ 11的支持

      break;

等等,这里只有一个类型的声明,具体的调用咱们尚未看到,咱们但愿看到的是具体的new classA相似的调用过程。所以,在具体的clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp中的

static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(CompilerInstance &CI)函数内存着真正的调用过程,添加处理以下:

case RewriteDPU:             return llvm::make_unique<RewriteDPUAction>();

RewriteDPUAction这个类是咱们真正实现的类。

这个类须要继承至public ASTFrontendAction

实现特别简单

std::unique_ptr<ASTConsumer> RewriteDPUAction::CreateASTConsumer(CompilerInstance &CI,

                                                   StringRef InFile) {

  if (std::unique_ptr<raw_ostream> OS = CI.createDefaultOutputFile(false, InFile)) {

    return CreateDPUConsumer(CI, InFile ,std::move(OS));

  }

  return nullptr;

}

 

bool RewriteDPUAction::BeginInvocation(CompilerInstance &CI) {

  return true;

}

剩下全部的东西都交给DPUConsumer这个消费者来处理

我在DPUConsumer中添加了对public SemaConsumer, public PassManager的继承,以此对Pass管理器和语法消费者的支持,从而准备支持制导。

在这个层次,就能够为所欲为的添加本身想要的Pass

目前还在开发中,代码不方便open,以后应该会做为一个开源项目在GitHub上见到,有什么问题能够给我发消息。最近也比较忙,没时间修改格式,待假期有空修改。

http://www.cnblogs.com/jourluohua

相关文章
相关标签/搜索