llc
でLLVM IRからアセンブリ言語を生成する場合、バックエンドのターゲットとして大きく分けて以下の3つを指定する。
./bin/llc -march=myriscvx32 -mcpu=simple32 -mattr=-64bit
それぞれが意味を持っている。
-march
まず、-march
によってターゲットアーキテクチャを指定する。これはTriple
で登録したmyriscvx32
かmyriscvx64
を指定しなければならない。-mattr
-mattr
では、そのアーキテクチャの機能を記述する。例えば、RISC-Vだと拡張命令セットとしてM,A,F,Dなどの拡張命令セットをサポートしている。
どの命令セットを拡張するか、このattrで指定することができる。これはLLVMの中でFeatureとして設定される。
MYRISCVXでは、Feature
として以下を追加した。
lib/Target/MYRISCVX/MYRISCVX.td
def FeatureMExt : SubtargetFeature<"m", "is_enable_M", "true", "'M' (Integer Multiplication and Division) support">; def FeatureAExt : SubtargetFeature<"a", "is_enable_A", "true", "'A' (Atomic) support">; def FeatureFExt : SubtargetFeature<"f", "is_enable_F", "true", "'F' (Singple Precision Floating Point) support">; def FeatureDExt : SubtargetFeature<"d", "is_enable_D", "true", "'D' (Double Precision Floating Point) support">; def FeatureCExt : SubtargetFeature<"c", "is_enable_C", "true", "'C' (Compressed Instruction) support">; def FeatureRV64 : SubtargetFeature<"64bit", "HasRV64", "true", "RV64 support">;
サブターゲットの記述には要素が4つ並んでいる。
- Featureの名前
- Featureの属性(実装時に追加される変数の名前)
- Featureの値(属性に設定される値)
- Featureの説明。
この記述を加えることによって、tdファイルから生成されるMYRISCVXGenSubtargetInfo.inc
にはSubtargetFeatureに基づく変数制御が追加される。
build-myriscvx/lib/Target/MYRISCVX/MYRISCVXGenSubtargetInfo.inc
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::FeatureAExt]) is_enable_A = true; if (Bits[MYRISCVX::FeatureCExt]) is_enable_C = true; if (Bits[MYRISCVX::FeatureDExt]) is_enable_D = true; if (Bits[MYRISCVX::FeatureFExt]) is_enable_F = true; if (Bits[MYRISCVX::FeatureMExt]) is_enable_M = true; if (Bits[MYRISCVX::FeatureRV64]) HasRV64 = true; }
したがって、MYRISCVXSubtarget
クラスには、これらのメソッドを追加する必要がある。
llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVXSubtarget.h
class MYRISCVXSubtarget : public MYRISCVXGenSubtargetInfo { virtual void anchor(); public: protected: bool is_enable_M = false; bool is_enable_A = false; bool is_enable_F = false; bool is_enable_D = false; bool is_enable_C = false; bool HasRV64 = false;
-mcpu
ターゲットアーキテクチャの中で、さらに特定のCPUを指定するために記述する。 特定のCPUを定義することによって、さまざまなFeatureをまとめて1つのCPU情報として記述することができる。 ここでは、以下の2つを定義した。simple32 : 32ビットのシンプルなMYRISCVX実装。M/A/F/Dの拡張命令は実装していない。
- rocket64 : 64ビットのRISC-V実装。M/A/F/Dの拡張命令を実装している。
という訳でMYRISCVX.td
に以下の2つのProcessorModelを追加する。
llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVX.td
def : ProcessorModel<"simple32", NoSchedModel, []>; def : ProcessorModel<"rocket64", NoSchedModel, [FeatureRV64, FeatureMExt, FeatureAExt, FeatureFExt, FeatureDExt, FeatureCExt]>;
これにより、MYRISCVXGenSubtargetInfo
クラスに以下の情報が追加される。
build-myriscvx/lib/Target/MYRISCVX/MYRISCVXGenSubtargetInfo.inc
// Sorted (by key) array of values for CPU subtype. extern const llvm::SubtargetFeatureKV MYRISCVXSubTypeKV[] = { { "rocket64", "Select the rocket64 processor", { MYRISCVX::FeatureRV64, MYRISCVX::FeatureMExt, MYRISCVX::FeatureAExt, MYRISCVX::FeatureFExt, MYRISCVX::FeatureDExt, MYRISCVX::FeatureCExt }, { } }, { "simple32", "Select the simple32 processor", { }, { } }, };
-mcpu
オプションを指定すると、Featureの設定されたCPUが生成される、という仕組みである。
llvm-myriscvx/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.cpp
/// Select the MYRISCVX Architecture Feature for the given triple and cpu name. /// The function will be called at command 'llvm-objdump -d' for MYRISCVX elf input. static StringRef selectMYRISCVXArchFeature(const Triple &TT, StringRef CPU) { if (TT.getArch() == Triple::ArchType::myriscvx64) { return "+64bit"; } else if (TT.getArch() == Triple::ArchType::myriscvx32) { return "-64bit"; } return ""; } static MCSubtargetInfo *createMYRISCVXMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { std::string ArchFS = selectMYRISCVXArchFeature(TT, CPU); if (!FS.empty()) { if (!ArchFS.empty()) ArchFS = ArchFS + "," + FS.str(); else ArchFS = FS; } // createMYRISCVXMCSubtargetInfoImpl defined in MYRISCVXGenSubtargetInfo.inc return createMYRISCVXMCSubtargetInfoImpl(TT, CPU, ArchFS); }