FPGA開発日記

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

RISC-V 64-bit LLVM Backendを試す (10. サブターゲットのエラーを解析する)

f:id:msyksphinz:20190109233324p:plain

LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。 少しずつ進んでいるが、まだターゲットのプログラムを正しくバイナリに変換することができない。

SubtargetFeature.cppを確認してみると、このアサーションで落ちている。 確かに、Featureの文字列を設定した場所がどこにも確認できない。

  • lib/MC/SubtargetFeature.cpp
static inline bool hasFlag(StringRef Feature) {
  assert(!Feature.empty() && "Empty string");
  // Get first character
  char Ch = Feature[0];
  // Check if first character is '+' or '-' flag
  return Ch == '+' || Ch =='-';
}

MIPSの実装では、以下で設定がされているようだった。

  • lib/Target/Mips/MipsTargetMachine.cpp
MipsTargetMachine::MipsTargetMachine(const Target &T, const Triple &TT,
                                     StringRef CPU, StringRef FS,
...
      NoMips16Subtarget(TT, CPU, FS.empty() ? "-mips16" : FS.str() + ",-mips16",
                        isLittle, *this, Options.StackAlignmentOverride),
      Mips16Subtarget(TT, CPU, FS.empty() ? "+mips16" : FS.str() + ",+mips16",
                      isLittle, *this, Options.StackAlignmentOverride) {
...
}

同じような実装で、RISCV(本家の実装)の場合は設定がされていない?これはなぜだろう。RISC-Vもターゲットを追加して再度ビルドして様子を見た。

RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,
                                       StringRef CPU, StringRef FS,
                                       const TargetOptions &Options,
...
      TLOF(make_unique<RISCVELFTargetObjectFile>()),
      Subtarget(TT, CPU, FS, *this) {
  initAsmInfo();
...

ターゲットをRISC-Vとしてllcを起動すると、+64bit-64bitが使われている。これはどこで登録されているんだろう?

 ./bin/llc -march=riscv32 -relocation-model=pic -filetype=asm ch3.riscv64.bc -o -
Feature : -64bit
Feature : -64bit
Feature : +64bit
Feature : +64bit
...

RISCV.tdに登録されている以下が気になる。

  • lib/Target/RISCV/RISCV.td
def RV64           : HwMode<"+64bit">;
def RV32           : HwMode<"-64bit">;
$ ./bin/llc -march=myriscvx -relocation-model=pic -filetype=asm ch3.riscv64.bc -o -
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
        .text
        .section .mdebug.abilp64
        .previous
        .file   "ch3.cpp"
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
ExpandIntegerResult #0: t2: i64 = FrameIndex<0>

Do not know how to expand the result of this operator!
UNREACHABLE executed at /home/msyksphinz/work/riscv/llvm-myriscvx64/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp:1369!
Stack dump:

いろいろ調べていって、結局FeatureStringを登録するためにの方法が分かってきた。 一つは、MipsのようにSubtargetを登録する際に追加すること。

  • lib/Target/Mips/MipsTargetMachine.cpp
MipsTargetMachine::MipsTargetMachine(const Target &T, const Triple &TT,
                                     StringRef CPU, StringRef FS,

      NoMips16Subtarget(TT, CPU, FS.empty() ? "-mips16" : FS.str() + ",-mips16",
                        isLittle, *this, Options.StackAlignmentOverride),
      Mips16Subtarget(TT, CPU, FS.empty() ? "+mips16" : FS.str() + ",+mips16",
                      isLittle, *this, Options.StackAlignmentOverride) {
...

const MipsSubtarget *
MipsTargetMachine::getSubtargetImpl(const Function &F) const {
  if (hasMips16Attr)
    FS += FS.empty() ? "+mips16" : ",+mips16";
  else if (hasNoMips16Attr)
    FS += FS.empty() ? "-mips16" : ",-mips16";
  if (HasMicroMipsAttr)
    FS += FS.empty() ? "+micromips" : ",+micromips";
  else if (HasNoMicroMipsAttr)
    FS += FS.empty() ? "-micromips" : ",-micromips";
  if (softFloat)
    FS += FS.empty() ? "+soft-float" : ",+soft-float";

もう一つは、RISC-Vのように生成された関数を使用することだ。

  • lib/Target/RISCV/RISCVSubtarget.cpp
RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies(StringRef CPU,
                                                                StringRef FS,
                                                                bool Is64Bit) {
...
  ParseSubtargetFeatures(CPUName, FS);
...
  • (ビルドディレクトリ側)lib/Target/RISCV/RISCVGenSubtargetInfo.inc
// ParseSubtargetFeatures - Parses features string setting specified
// subtarget options.
void llvm::RISCVSubtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {
  LLVM_DEBUG(dbgs() << "\nFeatures:" << FS);
  LLVM_DEBUG(dbgs() << "\nCPU:" << CPU << "\n\n");
  InitMCProcessorInfo(CPU, FS);
...
  • lib/MC/MCSubtargetInfo.cpp
static FeatureBitset getFeatures(StringRef CPU, StringRef FS,
                                 ArrayRef<SubtargetFeatureKV> ProcDesc,
                                 ArrayRef<SubtargetFeatureKV> ProcFeatures) {
  SubtargetFeatures Features(FS);
  return Features.getFeatureBits(CPU, ProcDesc, ProcFeatures);
}

void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef FS) {
  FeatureBits = getFeatures(CPU, FS, ProcDesc, ProcFeatures);
  if (!CPU.empty())
    CPUSchedModel = &getSchedModelForCPU(CPU);
  else
    CPUSchedModel = &MCSchedModel::GetDefaultSchedModel();
}
...

まずは手動でFSの文字列を追加してみた。

diff --git a/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp b/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp
index 2f60ab55..91466345 100644
--- a/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp
+++ b/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp
@@ -97,7 +97,7 @@ MYRISCVXTargetMachine::getSubtargetImpl(const Function &F) const {
                        ? FSAttr.getValueAsString().str()
                        : TargetFS;

-  // FS += "+myriscvx64";
+  FS += "+myriscvx64";

   auto &I = SubtargetMap[CPU + FS];
   if (!I) {

これで再度ビルドすると、Assertionのエラーは発生しなくなった。

$ ./bin/llc -march=myriscvx -relocation-model=pic -filetype=asm ch3.riscv64.bc -o -
        .text
        .section .mdebug.abilp64
        .previous
        .file   "ch3.cpp"
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
Feature : +myriscvx64
ExpandIntegerResult #0: t2: i64 = FrameIndex<0>

Do not know how to expand the result of this operator!
UNREACHABLE executed at /home/msyksphinz/work/riscv/llvm-myriscvx64/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp:1369!
Stack dump:
...

ただし、今度はDAGの選択に失敗する。これは単純に追加しているDAGが少ないからかな? 解析を進めていこう。