前回に引き続き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. ...
このサブターゲットを定義するためのクラスMYRISCVXSubTarget
はMYRISCVX.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;