MYRISCVXTargetMachine.{h,cpp}
その名の通りターゲットマシンを定義するファイルだ。MYRISCVXTargetMachine
はLLVMTargetMachine
を継承したクラスで、ターゲットマシンのすべての情報を集約する。
このクラスには、サブターゲットの情報も含まれている。
MYRISCVXTargetMachine.h
namespace llvm { class MYRISCVXTargetMachine : public LLVMTargetMachine { std::unique_ptr<TargetLoweringObjectFile> TLOF; // Selected ABI MYRISCVXABIInfo ABI; MYRISCVXSubtarget DefaultSubtarget; ...
また、MYRISCVXTargetMachine
を継承したクラスとして、リトルエンディアンの実装であるMYRISCVXelTargetMachine
が定義される。
MIPSなどのバイエンディアンのアーキテクチャでは、リトルエンディアンとビックエンディアンの両方が定義されるが、RISC-Vではリトルエンディアンしか存在しないので1種類しか不要なのだが、ここでは32ビット版と64ビット版のターゲットマシンを作りたいので、MYRISCVX32TargetMachine
とMYRISCVX64TargetMachine
を定義する。
MYRISCVXTargetMachine.h
/// MYRISCVX32TargetMachine - MYRISCVX32 little endian target machine. /// class MYRISCVX32TargetMachine : public MYRISCVXTargetMachine { virtual void anchor(); public: MYRISCVX32TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT); }; /// MYRISCVX64TargetMachine - MYRISCVX64 little endian target machine. /// class MYRISCVX64TargetMachine : public MYRISCVXTargetMachine { virtual void anchor(); public: MYRISCVX64TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT); };
TargetMachine
には何を記述すべきなのか
MYRISCVXTargetMachine.cpp
には、ターゲットアーキテクチャの様々なことを記述する必要がある。
- コンストラクタ
MYRISCVXTargetMachine (...)
: 親クラスLLVMTargetMachine
を呼び出して基本的な情報の登録を行う。基本的な情報とは、ビッグエンディアン・リトルエンディアン、ABI、リロケーションモデルなどだ。MYRISCVX32TargetMachine
とMYRISCVX64TargetMachine
は両方ともリトルエンディアンなので、とりあえず現時点ではコンストラクタに渡す引数は同じだ。
MYRISCVX32TargetMachine::MYRISCVX32TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) : MYRISCVXTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {} void MYRISCVX64TargetMachine::anchor() { } MYRISCVX64TargetMachine::MYRISCVX64TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) : MYRISCVXTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
// MYRISCVX32TargetMachine / MYRISCVX64TargetMachineが呼び出す先のコンストラクタ MYRISCVXTargetMachine::MYRISCVXTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT, bool isLittle) : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options, isLittle), TT, CPU, FS, Options, getEffectiveRelocModel(JIT, RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), isLittle(isLittle), TLOF(make_unique<MYRISCVXTargetObjectFile>()), ABI(MYRISCVXABIInfo::computeTargetABI()), DefaultSubtarget(TT, CPU, FS, isLittle, *this) { }
LLVMTargetMachine
クラスのインスタンス化にあたり必要な情報は、以下の関数で算出している。
computeDataLayout(TT, CPU, Options, isLittle)
xxx節で説明した。getEffectiveRelocModel(JIT, RM)
: MYRISCVXの有効なリロケーションモデルを返す。リロケーションモデルには以下が定義されている。include/llvm/Support/CodeGen.h
cpp // Relocation model types. namespace Reloc { enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI }; }
getEffectiveCodeModel(CM, CodeModel::Small)
: MYRISCVXのコードモデルを設定する。コードモデルというのは命令生成に置いてメモリアドレスの計算の方法を示し、現在のPCに対してコードとデータの相対的な関係に対する制限を付け加えることができる。ここでは、Default値としてCodeModel::Small
が設定されている。
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; }