深入研究Clang(十九) Clang的RISCV支持2

前文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的一些子類進行調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章