FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LLVMのバックエンドを作るための第一歩 (10. サブターゲットを追加するためのSubtargetFeature)

f:id:msyksphinz:20190425001356p:plain
LLVM Compiler Infrastructure

前回に引き続きLLVMのバックエンドを作るために必要なファイルを読み解いていく。

MYRISCVXSubTarget.{h,cpp}

サブターゲットはMYRISCVXの中でもアーキテクチャのバリエーションを付けるために使用されるもので、その名の通りサブのターゲットだ。 llcにおいてアーキテクチャ-march=myriscvx32で指定するが、サブターゲットは-mcpu=で指定する。 例えば、同じMIPSアーキテクチャの中でも、ISAのバージョン違いや実装の違いによってさまざまなバリエーションがある。

  • lib/Target/Mips/Mips.td
  def FeatureNoABICalls  : SubtargetFeature<"noabicalls", "NoABICalls", "true",
                                  "Disable SVR4-style position-independent code">;
  def FeaturePTR64Bit    : SubtargetFeature<"ptr64", "IsPTR64bit", "true",
                                  "Pointers are 64-bit wide">;
  def FeatureGP64Bit     : SubtargetFeature<"gp64", "IsGP64bit", "true",
                                  "General Purpose Registers are 64-bit wide">;
  def FeatureFP64Bit     : SubtargetFeature<"fp64", "IsFP64bit", "true",
                                  "Support 64-bit FP registers">;
  ...
./bin/llc -march=mips -mcpu=help
...

Available features for this target:

  mips1                    - Mips I ISA Support [highly experimental].
  mips16                   - Mips16 mode.
  mips2                    - Mips II ISA Support [highly experimental].
  mips3                    - MIPS III ISA Support [highly experimental].
  mips32                   - Mips32 ISA Support.
...
  noabicalls               - Disable SVR4-style position-independent code.
...

このサブターゲットを定義するためのクラスMYRISCVXSubTargetMYRISCVX.tdから生成された自動生成クラスMYRISCVXGenSubtargetInfoから生成される。

RISC-Vの場合、アーキテクチャに大きなバリエーションがある訳ではないのだが、ISAのどのモジュールが使用できるのか、例えば乗除算命令は使用できるのか、Compressed命令は使用できるのか、浮動小数点命令は使用できるのかなどのバリエーションが作れそうだ。

  • lib/Target/MYRISCVX/MYRISCVXSubtarget.h
    class MYRISCVXSubtarget : public MYRISCVXGenSubtargetInfo {
  ...
       protected:
      bool is_enable_M = false;
      bool is_enable_A = false;
      bool is_enable_F = false;
      bool is_enable_D = false;
  ...
  • lib/Target/MYRISCVX/MYRISCVXSubtarget.cpp
  MYRISCVXSubtarget &
  MYRISCVXSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS,
                                                     const TargetMachine &TM) {
    if (TargetTriple.getArch() == Triple::myriscvx32) {
      if (CPU.empty() || CPU == "generic") {
        CPU = "cpu-rv32";
      }
    } else if (TargetTriple.getArch() == Triple::myriscvx64) {
      if (CPU.empty() || CPU == "generic") {
        CPU = "cpu-rv64";
      }
    } else {
      errs() << "!!!Error, TargetTriple.getArch() = " << TargetTriple.getArch()
             <<  "CPU = " << CPU << "\n";
      exit(0);
    }
  
    // Parse features string.
    ParseSubtargetFeatures(CPU, FS);
    // Initialize scheduling itinerary for the specified CPU.
    InstrItins = getInstrItineraryForCPU(CPU);
  
    return *this;
  }

このSubtargetFeatureではアーキテクチャのバリエーションを指定するので、今回は32ビットモードと64ビットモードのサブターゲットを追加してみる。 デフォルトでは32ビットで、オプションで64ビットに設定されるようにする。

  • lib/Target/MYRISCVX/MYRISCVX.td
//===----------------------------------------------------------------------===//
// MYRISCVX subtarget features and instruction predicates.
//===----------------------------------------------------------------------===//

def FeatureRV64 : SubtargetFeature<"64bit", "HasRV64", "true", "RV64 support">;

サブターゲットの記述には要素が4つ並んでいる。

  • Featureの名前
  • Featureの属性(実装時に追加される変数の名前)
  • Featureの値(属性に設定される値)
  • Featureの説明。

この記述を加えることによって、tdファイルから生成されるMYRISCVXGenSubtargetInfo.incにはSubtargetFeatureに基づく変数制御が追加される。

  • lib/Target/MYRISCVX/MYRISCVXGenSubtargetInfo.inc
// Sorted (by key) array of values for CPU features.
extern const llvm::SubtargetFeatureKV MYRISCVXFeatureKV[] = {
  { "64bit", "RV64 support", { MYRISCVX::FeatureRV64 }, { } },
};

// Sorted (by key) array of values for CPU subtype.
extern const llvm::SubtargetFeatureKV MYRISCVXSubTypeKV[] = {
  { "cpu-rv32", "Select the cpu-rv32 processor", { }, { } },
  { "cpu-rv64", "Select the cpu-rv64 processor", { MYRISCVX::FeatureRV64 }, { } },
};
...
// ParseSubtargetFeatures - Parses features string setting specified
// subtarget options.
void llvm::MYRISCVXSubtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {
  LLVM_DEBUG(dbgs() << "\nFeatures:" << FS);
  LLVM_DEBUG(dbgs() << "\nCPU:" << CPU << "\n\n");
  InitMCProcessorInfo(CPU, FS);
  const FeatureBitset& Bits = getFeatureBits();
  if (Bits[MYRISCVX::FeatureRV64]) HasRV64 = true;
}

したがって、MYRISCVXSubtargetクラスにはメンバ変数HasRV64を追加する必要がある。

  • lib/Target/MYRISCVX/MYRISCVXSubtarget.h
  class MYRISCVXSubtarget : public MYRISCVXGenSubtargetInfo {
...
        bool HasRV64 = false;