編譯選項相關:前端
想要添加的選項,以我添加的-fdpu爲例子frontend
能經過clang --help獲得的選項,總體須要一個解析文件(好像在LLVM項目中都是經過後綴名爲xxx.td和xxx.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和要傳遞給CC1(CC1真正完成編譯工做,裏邊纔是咱們須要添加的動做)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組內。
以前也提到了,咱們添加的選項但願都是由用戶指定的,在Options和CC1Options中添加了選項還不算完,還須要在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.h的enum InputKind中加入
IK_DPU,
IK_PreprocessedDPU
由於要作個源源變換的工具,在ActionKind中添加響應的項
RewriteDPU, ///< Run DPU
上邊說過了,定義了IK_DPU和IK_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_DPU和 IK_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