前文Clang的RISCV支持1介紹了Clang中有關RISCV的代碼主要集中在三個地方:Driver部分、Basic部分和CodeGen部分,並且對Basic部分和CodeGen部分的內容和關係進行了介紹,只有Driver部分因爲涉及到了ToolChain、Tool和Command(job)等概念體系而未進行深入介紹。
在介紹完ToolChain、Tool和Command(job)等概念和調用關係之後,我們在本文再對Clang的RISCV支持的Driver部分進行深入分析。
一、Driver部分涉及到RISCV是從ToolChain相關操作開始的,這裏最早的介入點位於clang/lib/Driver/Driver.cpp中的Compilation *Driver::BuildCompilation(ArrayRef<constchar *> ArgList) 函數,它首先調用了getToolChain函數。位於同個文件下的getToolChain函數之中,逐步拆解了目標的操作系統、環境和目標平臺,具體代碼如下:
const ToolChain &Driver::getToolChain(const ArgList &Args,
const llvm::Triple &Target) const {
auto &TC = ToolChains[Target.str()];
if (!TC) {
switch (Target.getOS()) {
case llvm::Triple::AIX:
TC = std::make_unique<toolchains::AIX>(*this, Target, Args);
break;
...
case llvm::Triple::Win32:
switch (Target.getEnvironment()) {
default:
if (Target.isOSBinFormatELF())
TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
TC = std::make_unique<toolchains::MachO>(*this, Target, Args);
else
TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
break;
case llvm::Triple::GNU:
TC = std::make_unique<toolchains::MinGW>(*this, Target, Args);
break;
...
}
break;
...
default:
// Of these targets, Hexagon is the only one that might have
// an OS of Linux, in which case it got handled above already.
switch (Target.getArch()) {
case llvm::Triple::tce:
TC = std::make_unique<toolchains::TCEToolChain>(*this, Target, Args);
break;
...
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
TC = std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
break;
default:
...
}
}
}
// Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA
// compiles always need two toolchains, the CUDA toolchain and the host
// toolchain. So the only valid way to create a CUDA toolchain is via
// CreateOffloadingDeviceToolChains.
return *TC;
}
這裏最早出現了有關RISCV的內容,構建所需要的ToolChain:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
TC = std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
break;
二、上文RISCVToolChain的定義和實現,以及爲其所用的RISCV相關的Tool,均位於下列兩個文件裏:
clang/lib/Driver/ToolChains/RISCVToolchain.h
clang/lib/Driver/ToolChains/RISCVToolchain.cpp
下面進行分類討論:
1、ToolChain方面:定義了RISCVToolChain,它繼承於Generic_ELF,Generic_ELF繼承於Generic_GCC,Generic_GCC繼承於ToolChain。在源碼上的體現:
clang/lib/Driver/ToolChains/RISCVToolchain.h
class LLVM_LIBRARY_VISIBILITY RISCVToolChain : public Generic_ELF {
clang/lib/Driver/ToolChains/Gnu.h
namespace toolchains {
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
2、Tool方面:定義了RISCV::Linker,它繼承於GnuTool ,GnuTool 繼承於Tool。源碼上的體現:
clang/lib/Driver/ToolChains/RISCVToolchain.h
namespace tools {
namespace RISCV {
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
clang/lib/Driver/ToolChains/Gnu.h
namespace tools {
/// Base class for all GNU tools that provide the same behavior when
/// it comes to response files support
class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool {
三、Driver部分,還有兩個相關文件RISCV.h和RISCV.cpp,他們的完整路徑爲:
clang/lib/Driver/ToolChains/Arch/RISCV.h
clang/lib/Driver/ToolChains/Arch/RISCV.cpp
這兩個文件主要提供了獲取ABI、Arch和RISCV目標特徵的接口,具體代碼表示如下:
clang/lib/Driver/ToolChains/Arch/RISCV.h
namespace clang {
namespace driver {
namespace tools {
namespace riscv {
void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
StringRef getRISCVABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
StringRef getRISCVArch(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
} // end namespace riscv
} // namespace tools
} // end namespace driver
} // end namespace clang
其中,在實現層面,getRISCVTargetFeatures還會調用getRISCVArch,並且調用getArchFeatures獲取Arch特徵。getArchFeatures則通過getExtensionVersion獲取擴展版本號,然後通過getExtensionFeatures獲取擴展特徵。所以,具體的擴展版本號、以及擴展特徵要進行改動的話,都是在clang/lib/Driver/ToolChains/Arch/RISCV.cpp這個文件裏更新。
這裏的信息與Basic部分信息不同,Basic部分主要是生成代碼所需要的基本信息,而這裏則是詳細的擴展版本、擴展特徵檢查和校驗。後續會對這裏getRISCVABI、getRISCVArch和getRISCVTargetFeatures的被調用關係進行分析。
1、上面所提到的getRISCVABI函數,被調用的地方主要有:
1)Clang、ClangAs這兩個Tool子類的AddRISCVTargetArgs函數;(clang/lib/Driver/ToolChains/Clang.h、clang/lib/Driver/ToolChains/Clang.cpp)
2)Assembler這個tool的tools::gnutools::Assembler::ConstructJob函數;
(clang/lib/Driver/ToolChains/Gnu.h、clang/lib/Driver/ToolChains/Gnu.cpp)
3)Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs函數所調用的findRISCVMultilibs函數之中,以及findRISCVMultilibs函數所調用的findRISCVBareMetalMultilibs函數之中;
(clang/lib/Driver/ToolChains/Gnu.h、clang/lib/Driver/ToolChains/Gnu.cpp)
4)Linux這個toolchain的構造函數,以及它的std::string Linux::getDynamicLinker函數之中。
(clang/lib/Driver/ToolChains/Linux.h、clang/lib/Driver/ToolChains/Linux.cpp)
2、上面所提到的getRISCVArch,被調用的地方在:
1) Assembler這個tool的tools::gnutools::Assembler::ConstructJob函數;
(clang/lib/Driver/ToolChains/Gnu.h、clang/lib/Driver/ToolChains/Gnu.cpp)
2)Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs函數所調用的findRISCVMultilibs函數所調用的findRISCVBareMetalMultilibs函數之中;
(clang/lib/Driver/ToolChains/Gnu.h、clang/lib/Driver/ToolChains/Gnu.cpp)
3、上面所提到的getRISCVTargetFeatures,被調用的地方在getTargetFeatures函數之中,這個函數主要被Clang這個tool的Clang::RenderTargetOptions函數和Clang::ConstructJob函數、ClangAs這個tool的ClangAs::ConstructJob函數所調用。(clang/lib/Driver/ToolChains/Clang.cpp)
可以看到,這三個函數主要的應用場景還是給Tool的一些子類進行調用。