diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Register.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" @@ -93,6 +94,45 @@ return new RISCVTargetAsmStreamer(S, OS); } +namespace { + +class RISCVMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit RISCVMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + if (isConditionalBranch(Inst)) { + int64_t Imm; + if (Size == 2) + Imm = Inst.getOperand(1).getImm(); + else + Imm = Inst.getOperand(2).getImm(); + Target = Addr + Imm; + return true; + } + + if (Inst.getOpcode() == RISCV::C_JAL || Inst.getOpcode() == RISCV::C_J) { + Target = Addr + Inst.getOperand(0).getImm(); + return true; + } + + if (Inst.getOpcode() == RISCV::JAL) { + Target = Addr + Inst.getOperand(1).getImm(); + return true; + } + + return false; + } +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) { + return new RISCVMCInstrAnalysis(Info); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); @@ -104,6 +144,7 @@ TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo); TargetRegistry::RegisterObjectTargetStreamer( *T, createRISCVObjectTargetStreamer); + TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis); // Register the asm target streamer. TargetRegistry::RegisterAsmTargetStreamer(*T, createRISCVAsmTargetStreamer); diff --git a/llvm/test/MC/Disassembler/RISCV/branch-targets.txt b/llvm/test/MC/Disassembler/RISCV/branch-targets.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/RISCV/branch-targets.txt @@ -0,0 +1,27 @@ +# RUN: llvm-mc -assemble -triple riscv32 -mattr=+c -filetype=obj %s -o - 2>&1 | \ +# RUN: llvm-objdump -d --mattr=+c -M no-aliases - | FileCheck %s +# RUN: llvm-mc -assemble -triple riscv64 -mattr=+c -filetype=obj %s -o - 2>&1 | \ +# RUN: llvm-objdump -d --mattr=+c -M no-aliases - | FileCheck %s + +label1: +.option norvc + j label1 + j label2 + bnez a0, label1 + bnez a0, label2 +.option rvc + j label1 + j label2 + bnez a0, label1 + bnez a0, label2 +# CHECK-LABEL: : +# CHECK-NEXT: jal zero, 0 +# CHECK-NEXT: jal zero, 20 +# CHECK-NEXT: bne a0, zero, -8 +# CHECK-NEXT: bne a0, zero, 12 +# CHECK-NEXT: c.j -16 +# CHECK-NEXT: c.j 6 +# CHECK-NEXT: c.bnez a0, -20 +# CHECK-NEXT: c.bnez a0, 2 + +label2: