Clang編譯選項和Pass構建


編譯選項相關:

想要添加的選項,以我添加的-fdpu為例子

能通過clang --help得到的選項,整體需要一個解析文件(好像在LLVM項目中都是通過后綴名為xxx.tdxxx.def的文件來進行存儲的,然后通過xxx.h聲明,xxx.cpp真正進行解析)

比如添加-fdpu,是在clang/include/Driver/Options.td添加相應的選項(其實就是憑感覺加,感覺和哪個比較像就對應加一個,具體的內容沒研究明白),我是加成了這樣:

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

  HelpText<"Enable DPU extensions">;

這個里邊的選項都是直接面向用戶的,因此加的時候可以不是那么嚴謹,里邊的Flags是標記作為DriverOption和要傳遞給CC1CC1真正完成編譯工作,里邊才是我們需要添加的動作)

但是也不要亂加,這個里邊其實是有定義Group的,比如ActionGroup中定義的都是動作,其他像M_Group等的,都是各種語言相應的Group。而且這個Group的定義是有相應的動作,比如像源源變換等操作,最好就再建立一個Action相關的選項,留給CC1使用

我的實現是在clang/include/Driver/CC1Options.td中添加了一個要實現源源變化的Action

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

  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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM