深入研究Clang(十五) Clang的RISCV支持1
Posted snsn1984
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入研究Clang(十五) Clang的RISCV支持1相关的知识,希望对你有一定的参考价值。
一、Clang/LLVM对RISCV的支持概况
目前已经有一系列的C类编译器和库开始支持RISCV,这其中包括了GCC和Clang/LLVM。从RISCV的官方网站,可以获取目前的支持状态。具体内容如下:
网址:https://riscv.org/software-status/#c-compilers-and-libraries
该列表中还包含了所支持的License和Maintainers。其中,Clang/LLVM的Maintainers是Alex Bradbury,这位大神是LLVMWEEKLY的创建者和维护者,这个周报目前已经做到了331期,地址:http://llvmweekly.org/。
Alex Bradbury目前在剑桥一家叫lowRISC的非营利性机构里,这家机构也是RISCV基金会的成员(Silver级别),lowRISC的官网地址:https://www.lowrisc.org/。
二、Clang源码中的RISCV支持概况
目前Clang源码之中的RISCV相关代码,主要位于以下几个部分:
1、Driver部分
clang/lib/Driver/ToolChains/RISCVToolchain.h
clang/lib/Driver/ToolChains/RISCVToolchain.cpp
clang/lib/Driver/ToolChains/Arch/RISCV.h
clang/lib/Driver/ToolChains/Arch/RISCV.cpp
这部分代码,主要是用来构建Clang的RISCV toolchain。toolchain是Clang中的一个概念,这个概念主要是用来访问一个平台的多个tools的(注释原文:ToolChain - Access to tools for a single platform.)。有关ToolChain的内容,可以做专门的文章分析,此处不展开。
2、Basic部分
clang/lib/Basic/Targets/RISCV.h
clang/lib/Basic/Targets/RISCV.cpp
这部分代码,主要用来声明RISCV的目标平台信息对象,简单的可以认为是保存目标平台的相关信息。在RISCV上,可以分为32位和64位的目标平台,具体针对了头文件RISCV.h中的RISCV32TargetInfo和RISCV64TargetInfo,这两个类继承于RISCVTargetInfo,而RISCVTargetInfo继承于TargetInfo类。
构建和使用RISCV32TargetInfo和RISCV64TargetInfo的代码位于/clang/lib/Basic/Targets.cpp之中的TargetInfo *AllocateTarget(const llvm::Triple &Triple, const TargetOptions &Opts)函数,其具体代码为:
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
TargetInfo *AllocateTarget(const llvm::Triple &Triple,
const TargetOptions &Opts)
llvm::Triple::OSType os = Triple.getOS();
switch (Triple.getArch())
default:
return nullptr;
case llvm::Triple::arc:
return new ARCTargetInfo(Triple, Opts);
case llvm::Triple::xcore:
return new XCoreTargetInfo(Triple, Opts);
...
case llvm::Triple::riscv32:
// TODO: add cases for NetBSD, RTEMS once tested.
switch (os)
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<RISCV32TargetInfo>(Triple, Opts);
case llvm::Triple::Linux:
return new LinuxTargetInfo<RISCV32TargetInfo>(Triple, Opts);
default:
return new RISCV32TargetInfo(Triple, Opts);
case llvm::Triple::riscv64:
// TODO: add cases for NetBSD, RTEMS once tested.
switch (os)
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts);
case llvm::Triple::Fuchsia:
return new FuchsiaTargetInfo<RISCV64TargetInfo>(Triple, Opts);
case llvm::Triple::Linux:
return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts);
default:
return new RISCV64TargetInfo(Triple, Opts);
...
case llvm::Triple::renderscript32:
return new LinuxTargetInfo<RenderScript32TargetInfo>(Triple, Opts);
case llvm::Triple::renderscript64:
return new LinuxTargetInfo<RenderScript64TargetInfo>(Triple, Opts);
// namespace targets
// namespace clang
3、CodeGen部分
clang/lib/CodeGen/TargetInfo.cpp
1)这部分代码,有两个RISCV相关的类:一个是RISCVABIInfo,继承于DefaultABIInfo,DefaultABIInfo继承于ABIInfo;一个是RISCVTargetCodeGenInfo,继承于TargetCodeGenInfo。RISCVABIInfo在RISCVTargetCodeGenInfo构造函数中被使用:
RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
unsigned FLen)
: TargetCodeGenInfo(std::make_unique<RISCVABIInfo>(CGT, XLen, FLen))
RISCVTargetCodeGenInfo是被const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo()函数所调用,调用时需满足条件:
switch (Triple.getArch())
......
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
也就是这里的Triple.getArch()为riscv32或者riscv64,调用该部分内容。
2)CodeGenModule::getTargetCodeGenInfo()实际调用RISCVTargetCodeGenInfo的时候,传给RISCVTargetCodeGenInfo的是自己的Types:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
StringRef ABIStr = getTarget().getABI();
unsigned XLen = getTarget().getPointerWidth(0);
unsigned ABIFLen = 0;
if (ABIStr.endswith("f"))
ABIFLen = 32;
else if (ABIStr.endswith("d"))
ABIFLen = 64;
return SetCGInfo(new RISCVTargetCodeGenInfo(Types, XLen, ABIFLen));
这个Types在clang/lib/CodeGen/CodeGenModule.h之中可以看到定义为:
// This should not be moved earlier, since its initializati on depends on some
// of the previous reference members being already initialized and also checks
// if TheTargetCodeGenInfo is NULL
CodeGenTypes Types;
这个Types是在/clang/lib/CodeGen/CodeGenModule.cpp中CodeGenModule的构造函数中做的初始化:
CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
const PreprocessorOptions &PPO,
const CodeGenOptions &CGO, llvm::Module &M,
DiagnosticsEngine &diags,
CoverageSourceInfo *CoverageInfo)
: Context(C), LangOpts(C.getLangOpts()), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
VMContext(M.getContext()), Types(*this), VTables(*this),
SanitizerMD(new SanitizerMetadata(*this))
3)本部分代码和Baisc部分代码的关系
CodeGenModule::getTargetCodeGenInfo()函数中,关于RISCV的代码有如下两行:
StringRef ABIStr =getTarget().getABI();
unsigned XLen =getTarget().getPointerWidth(0);
这两行代码都使用了getTarget()这个成员函数。这个成员函数是CodeGenModule的成员函数,其定义位于clang/lib/CodeGen/CodeGenModule.h之中:
const TargetInfo &getTarget() const return Target;
其中的Target定义为:
const TargetInfo &Target;
这里用到的TargetInfo的定义位于clang/include/clang/Basic/TargetInfo.h,它正是RISCVTargetInfo的父类。至此,已经和Basic部分联系上了。/clang/lib/CodeGen/目录之下虽然也有TargetInfo.h和TargetInfo.cpp文件,但是这两个文件里并没有TargetInfo类。
——————
另外,之前在BILIBILI做了一个小视频,内容和本文相似,简单聊Clang对RISCV的支持,感兴趣的也可以看看:https://www.bilibili.com/video/BV1b7411j7S6
编辑于 2020-05-18
以上是关于深入研究Clang(十五) Clang的RISCV支持1的主要内容,如果未能解决你的问题,请参考以下文章
深入研究Clang(十六) Clang Driver库的ToolChain
深入研究Clang(十六) Clang Driver库的ToolChain