diff --git a/cross-project-tests/lit.cfg.py b/cross-project-tests/lit.cfg.py index b35c643ac898c..7b95c09bbcfa0 100644 --- a/cross-project-tests/lit.cfg.py +++ b/cross-project-tests/lit.cfg.py @@ -19,7 +19,7 @@ config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. -config.suffixes = [".c", ".cl", ".cpp", ".m"] +config.suffixes = [".c", ".cl", ".cpp", ".m", ".s"] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent diff --git a/llvm/include/llvm/MC/MCInstrAnalysis.h b/llvm/include/llvm/MC/MCInstrAnalysis.h index 63a4e02a92360..4b21b56d0d98d 100644 --- a/llvm/include/llvm/MC/MCInstrAnalysis.h +++ b/llvm/include/llvm/MC/MCInstrAnalysis.h @@ -19,6 +19,7 @@ #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Compiler.h" #include #include @@ -178,9 +179,15 @@ class LLVM_ABI MCInstrAnalysis { /// Given a branch instruction try to get the address the branch /// targets. Return true on success, and the address in Target. - virtual bool - evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const; + virtual bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target, + const MCSubtargetInfo *STI = nullptr) const; + + /// Given an instruction that accesses a memory address, try to compute + /// the target address. Return true on success, and the address in \p Target. + virtual bool evaluateInstruction(const MCInst &Inst, uint64_t Addr, + uint64_t Size, uint64_t &Target, + const MCSubtargetInfo &STI) const; /// Given an instruction tries to get the address of a memory operand. Returns /// the address on success. diff --git a/llvm/lib/MC/MCInstrAnalysis.cpp b/llvm/lib/MC/MCInstrAnalysis.cpp index cea905d092e0b..0104ab9ef17fd 100644 --- a/llvm/lib/MC/MCInstrAnalysis.cpp +++ b/llvm/lib/MC/MCInstrAnalysis.cpp @@ -24,9 +24,15 @@ bool MCInstrAnalysis::clearsSuperRegisters(const MCRegisterInfo &MRI, return false; } -bool MCInstrAnalysis::evaluateBranch(const MCInst & /*Inst*/, uint64_t /*Addr*/, - uint64_t /*Size*/, - uint64_t & /*Target*/) const { +bool MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, + uint64_t Size, uint64_t &Target, + const MCSubtargetInfo *STI) const { + return false; +} + +bool MCInstrAnalysis::evaluateInstruction(const MCInst &Inst, uint64_t Addr, + uint64_t Size, uint64_t &Target, + const MCSubtargetInfo &STI) const { return false; } diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp index b7959e02ec268..02d18876c2e26 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -394,7 +394,8 @@ class AArch64MCInstrAnalysis : public MCInstrAnalysis { AArch64MCInstrAnalysis(const MCInstrInfo *Info) : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { // Search for a PC-relative argument. // This will handle instructions like bcc (where the first argument is the // condition code) and cbz (where it is a register). diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp index c692895d84c00..b3c5afaa51664 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp @@ -137,7 +137,8 @@ class AMDGPUMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { if (Inst.getNumOperands() == 0 || !Inst.getOperand(0).isImm() || Info->get(Inst.getOpcode()).operands()[0].OperandType != MCOI::OPERAND_PCREL) diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp index c756bff3b501a..3e32a394df02a 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -413,7 +413,8 @@ class ARMMCInstrAnalysis : public MCInstrAnalysis { } bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { const MCInstrDesc &Desc = Info->get(Inst.getOpcode()); // Find the PC-relative immediate operand in the instruction. diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp index caf84701b999f..ce14253099c14 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp @@ -77,7 +77,8 @@ class BPFMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { // The target is the 3rd operand of cond inst and the 1st of uncond inst. int32_t Imm; if (isConditionalBranch(Inst)) { diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp index bb122f683644b..2df356aede9cb 100644 --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp @@ -113,7 +113,8 @@ class CSKYMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { if (isConditionalBranch(Inst) || isUnconditionalBranch(Inst)) { int64_t Imm; Imm = Inst.getOperand(Inst.getNumOperands() - 1).getImm(); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 91051cd4e2d51..3407e5eddb679 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -716,8 +716,9 @@ class HexagonMCInstrAnalysis : public MCInstrAnalysis { return MCInstrAnalysis::isConditionalBranch(Inst); } - bool evaluateBranch(MCInst const &Inst, uint64_t Addr, - uint64_t Size, uint64_t &Target) const override { + bool evaluateBranch(MCInst const &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target, + const MCSubtargetInfo *STI) const override { if (!(isCall(Inst) || isUnconditionalBranch(Inst) || isConditionalBranch(Inst))) return false; diff --git a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp index 4a381c033b384..7eb92f847e8a8 100644 --- a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp +++ b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp @@ -94,7 +94,8 @@ class LanaiMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { if (Inst.getNumOperands() == 0) return false; if (!isConditionalBranch(Inst) && !isUnconditionalBranch(Inst) && diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp index 3ec070e5cbdd3..7d0d197b430b9 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp @@ -100,7 +100,8 @@ class LoongArchMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { unsigned NumOps = Inst.getNumOperands(); if ((isBranch(Inst) && !isIndirectBranch(Inst)) || Inst.getOpcode() == LoongArch::BL) { diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp index add36d87b9eff..1ffbe6b7db478 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -231,7 +231,8 @@ class MipsMCInstrAnalysis : public MCInstrAnalysis { MipsMCInstrAnalysis(const MCInstrInfo *Info) : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { unsigned NumOps = Inst.getNumOperands(); if (NumOps == 0) return false; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp index 03a034182ae15..a1329fa562f2b 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -456,7 +456,8 @@ class PPCMCInstrAnalysis : public MCInstrAnalysis { : MCInstrAnalysis(Info) {} bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { unsigned NumOps = Inst.getNumOperands(); if (NumOps == 0 || Info->get(Inst.getOpcode()).operands()[NumOps - 1].OperandType != diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp index f3b93f032588c..ccee5688e642b 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp @@ -29,7 +29,9 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include +#include #define GET_INSTRINFO_MC_DESC #define ENABLE_INSTR_PREDICATE_VERIFIER @@ -182,6 +184,17 @@ class RISCVMCInstrAnalysis : public MCInstrAnalysis { } switch (Inst.getOpcode()) { + case RISCV::C_LUI: + case RISCV::LUI: { + setGPRState(Inst.getOperand(0).getReg(), + SignExtend64<32>(Inst.getOperand(1).getImm() << 12)); + break; + } + case RISCV::AUIPC: { + setGPRState(Inst.getOperand(0).getReg(), + Addr + SignExtend64<32>(Inst.getOperand(1).getImm() << 12)); + break; + } default: { // Clear the state of all defined registers for instructions that we don't // explicitly support. @@ -193,15 +206,12 @@ class RISCVMCInstrAnalysis : public MCInstrAnalysis { } break; } - case RISCV::AUIPC: - setGPRState(Inst.getOperand(0).getReg(), - Addr + SignExtend64<32>(Inst.getOperand(1).getImm() << 12)); - break; } } bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override { + uint64_t &Target, + const MCSubtargetInfo *STI) const override { if (isConditionalBranch(Inst)) { int64_t Imm; if (Size == 2) @@ -213,6 +223,8 @@ class RISCVMCInstrAnalysis : public MCInstrAnalysis { } switch (Inst.getOpcode()) { + default: + return false; case RISCV::C_J: case RISCV::C_JAL: case RISCV::QC_E_J: @@ -229,8 +241,85 @@ class RISCVMCInstrAnalysis : public MCInstrAnalysis { } return false; } + case RISCV::C_ADDI: + case RISCV::ADDI: { + if (!STI) + return false; + unsigned int ArchRegWidth = + STI->getTargetTriple().getArchPointerBitWidth(); + MCRegister Reg = Inst.getOperand(1).getReg(); + auto TargetRegState = getGPRState(Reg); + if (TargetRegState && Reg != RISCV::X0) { + Target = *TargetRegState + Inst.getOperand(2).getImm(); + Target &= maskTrailingOnes(ArchRegWidth); + return true; + } + break; + } + case RISCV::C_ADDIW: + case RISCV::ADDIW: { + MCRegister Reg = Inst.getOperand(1).getReg(); + auto TargetRegState = getGPRState(Reg); + if (TargetRegState && Reg != RISCV::X0) { + Target = *TargetRegState + Inst.getOperand(2).getImm(); + Target = SignExtend64<32>(Target); + return true; + } + break; + } + case RISCV::LB: + case RISCV::LH: + case RISCV::LD: + case RISCV::LW: + case RISCV::LBU: + case RISCV::LHU: + case RISCV::LWU: + case RISCV::SB: + case RISCV::SH: + case RISCV::SW: + case RISCV::SD: + case RISCV::FLH: + case RISCV::FLW: + case RISCV::FLD: + case RISCV::FSH: + case RISCV::FSW: + case RISCV::FSD: + case RISCV::C_LD: + case RISCV::C_SD: + case RISCV::C_FLD: + case RISCV::C_FSD: + case RISCV::C_SW: + case RISCV::C_LW: + case RISCV::C_FSW: + case RISCV::C_FLW: + case RISCV::C_LBU: + case RISCV::C_LH: + case RISCV::C_LHU: + case RISCV::C_SB: + case RISCV::C_SH: + case RISCV::C_LWSP: + case RISCV::C_SWSP: + case RISCV::C_LDSP: + case RISCV::C_SDSP: + case RISCV::C_FLWSP: + case RISCV::C_FSWSP: + case RISCV::C_FLDSP: + case RISCV::C_FSDSP: + case RISCV::C_LD_RV32: + case RISCV::C_SD_RV32: + case RISCV::C_SDSP_RV32: + case RISCV::LD_RV32: + case RISCV::C_LDSP_RV32: + case RISCV::SD_RV32: { + MCRegister Reg = Inst.getOperand(1).getReg(); + auto TargetRegState = getGPRState(Reg); + if (TargetRegState) { + Target = *TargetRegState + Inst.getOperand(2).getImm(); + return true; + } + break; + } } - return false; } @@ -344,12 +433,11 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() { TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer); TargetRegistry::RegisterObjectTargetStreamer( *T, createRISCVObjectTargetStreamer); - TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis); - // Register the asm target streamer. TargetRegistry::RegisterAsmTargetStreamer(*T, createRISCVAsmTargetStreamer); // Register the null target streamer. TargetRegistry::RegisterNullTargetStreamer(*T, createRISCVNullTargetStreamer); + TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis); } } diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp index 2eb22b239aa48..5b811dcafc292 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp @@ -515,7 +515,8 @@ class X86MCInstrAnalysis : public MCInstrAnalysis { const MCSubtargetInfo &STI) const override; bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, - uint64_t &Target) const override; + uint64_t &Target, + const MCSubtargetInfo *STI) const override; std::optional evaluateMemoryOperandAddress(const MCInst &Inst, const MCSubtargetInfo *STI, uint64_t Addr, uint64_t Size) const override; @@ -640,8 +641,9 @@ X86MCInstrAnalysis::findPltEntries(uint64_t PltSectionVA, } } -bool X86MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, - uint64_t Size, uint64_t &Target) const { +bool X86MCInstrAnalysis::evaluateBranch( + const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target, + const MCSubtargetInfo *STI = nullptr) const { if (Inst.getNumOperands() == 0 || Info->get(Inst.getOpcode()).operands()[0].OperandType != MCOI::OPERAND_PCREL) diff --git a/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg b/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg new file mode 100644 index 0000000000000..9dd5a0eedea08 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if "RISCV" not in config.targets_to_build: + config.unsupported = True diff --git a/llvm/test/tools/llvm-objdump/RISCV/riscv32-ar-coverage.s b/llvm/test/tools/llvm-objdump/RISCV/riscv32-ar-coverage.s new file mode 100644 index 0000000000000..a730ff0788c12 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/RISCV/riscv32-ar-coverage.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc -riscv-add-build-attributes -triple=riscv32 -filetype=obj -mattr=+zclsd,+zilsd %s -o %t +# RUN: llvm-objdump -d %t | FileCheck %s + +# CHECK: 00000000 <_start>: +# CHECK-NEXT 0: 00000517 auipc a0, 0x0 +# CHECK-NEXT 4: 0559 addi a0, a0, 0x16 +# CHECK-NEXT 6: 00000517 auipc a0, 0x0 +# CHECK-NEXT a: 6910 ld a2, 0x10(a0) +# CHECK-NEXT c: 00000517 auipc a0, 0x0 +# CHECK-NEXT 10: 00c53523 sd a2, 0xa(a0) +# CHECK-NEXT 14: 0000 unimp + +## The structure of this test file is similar to that of riscv64-ar-coverage +## with the major difference being that these tests are focused on instructions +## for 32 bit architecture. + +.global _start +.text +_start: + auipc a0, 0x0 + addi a0, a0, 0x16 ## addi -- behavior changes with different architectures. + + ## Test Zclsd and Zilsd instructions respectively + auipc a0, 0x0 + c.ld a2, 0x10(a0) + + auipc a0, 0x0 + sd a2, 0xa(a0) + +.skip 0x2 +target: + ret: diff --git a/llvm/test/tools/llvm-objdump/RISCV/riscv64-ar-coverage.s b/llvm/test/tools/llvm-objdump/RISCV/riscv64-ar-coverage.s new file mode 100644 index 0000000000000..3d2dda4bd673a --- /dev/null +++ b/llvm/test/tools/llvm-objdump/RISCV/riscv64-ar-coverage.s @@ -0,0 +1,99 @@ +# RUN: llvm-mc -riscv-add-build-attributes -triple=riscv64 -filetype=obj -mattr=+f,+c,+zcb %s -o %t +# RUN: llvm-objdump -d %t | FileCheck %s + +# CHECK: 0000000000000000 <_start>: +# CHECK-NEXT: 0: 00010517 auipc a0, 0x10 +# CHECK-NEXT: 4: 00450513 addi a0, a0, 0x4 +# CHECK-NEXT: 8: 00010517 auipc a0, 0x10 +# CHECK-NEXT: c: 1571 addi a0, a0, -0x4 +# CHECK-NEXT: e: 6541 lui a0, 0x10 +# CHECK-NEXT: 10: 0045059b addiw a1, a0, 0x4 +# CHECK-NEXT: 14: 6541 lui a0, 0x10 +# CHECK-NEXT: 16: 2511 addiw a0, a0, 0x4 +# CHECK-NEXT: 18: 00110537 lui a0, 0x110 +# CHECK-NEXT: 1c: c50c sw a1, 0x8(a0) +# CHECK-NEXT: 1e: 00110537 lui a0, 0x110 +# CHECK-NEXT: 22: 4508 lw a0, 0x8(a0) +# CHECK-NEXT: 24: 6541 lui a0, 0x10 +# CHECK-NEXT: 26: 6585 lui a1, 0x1 +# CHECK-NEXT: 28: 0306 slli t1, t1, 0x1 +# CHECK-NEXT: 2a: 0511 addi a0, a0, 0x4 +# CHECK-NEXT: 2c: 0505 addi a0, a0, 0x1 +# CHECK-NEXT: 2e: 00002427 fsw ft0, 0x8(zero) <_start+0x8> +# CHECK-NEXT: 32: 00110097 auipc ra, 0x110 +# CHECK-NEXT: 36: fda080e7 jalr -0x26(ra) +# CHECK-NEXT: 3a: 6445 lui s0, 0x11 +# CHECK-NEXT: 3c: 8800 sb s0, 0x0(s0) +# CHECK-NEXT: 3e: 4522 lw a0, 0x8(sp) + +## The core of the feature being added was address resolution for instruction +## sequences where a register is populated by immediate values via two +## separate instructions. First by an instruction that provides the upper bits +## (auipc, lui, etc) followed by another instruction for the lower bits (addi, +## jalr, ld, etc.). + +.global _start +.text + +_start: + ## Test block 1-3 each focus on a certain starting instruction in a sequence. + ## Starting instructions are the ones that provide the upper bits. The other + ## instruction in the sequence is the one that provides the lower bits. The + ## second instruction is arbitrarily chosen to increase code coverage. + + ## Test block #1. + lla a0, target + auipc a0, 0x10 + c.addi a0, -0x4 + + ## Test block #2. + c.lui a0, 0x10 + addiw a1, a0, 0x4 + c.lui a0, 0x10 + c.addiw a0, 0x4 + + ## Test block #3. + lui a0, 0x110 + sw a1, 0x8(a0) + lui a0, 0x110 + c.lw a0, 0x8(a0) + + ## Test block 4 tests instruction interleaving. Essentially the code's + ## ability to keep track of a valid sequence even if multiple other unrelated + ## instructions separate the two. + lui a0, 0x10 + lui a1, 0x1 ## Unrelated instruction. + slli t1, t1, 0x1 ## Unrelated instruction. + addi a0, a0, 0x4 + addi a0, a0, 0x1 ## Verify register tracking terminates. + + ## Test 5 checks instructions providing upper bits do not change the tracked + ## value of zero register. Also ensures load/store instructions accessing data + ## relative to the zero register trigger address resolution. The latter kind + ## of instructions are essentially memory accesses relative to the zero + ## register. + fsw f0, 0x8(x0) + + ## Test 6 ensures that the newly added functionality is compatible with + ## code that already worked for branch instructions. + call func + + ## Test #7 -- zcb extension. + lui x8, 0x11 + c.sb x8, 0(x8) + + ## Test #8 -- stack based load/stores. + c.lwsp a0, 0x8(sp) + +## These are the labels that the instructions above are expected to resolve to. +.skip 0xffc4 +target: + .word 1 +.skip 0xff8 +zcb: + .word 1 +.skip 0xff004 +far_target: + .word 2 +func: + ret diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 5ecb33375943f..af9791fa4e4c1 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -1520,8 +1520,8 @@ collectLocalBranchTargets(ArrayRef Bytes, MCInstrAnalysis *MIA, if (MIA) { if (Disassembled) { uint64_t Target; - bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); - if (TargetKnown && (Target >= Start && Target < End) && + bool BranchTargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); + if (BranchTargetKnown && (Target >= Start && Target < End) && !Targets.count(Target)) { // On PowerPC and AIX, a function call is encoded as a branch to 0. // On other PowerPC platforms (ELF), a function call is encoded as @@ -2356,8 +2356,8 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, llvm::raw_ostream *TargetOS = &FOS; uint64_t Target; bool PrintTarget = DT->InstrAnalysis->evaluateBranch( - Inst, SectionAddr + Index, Size, Target); - + Inst, SectionAddr + Index, Size, Target, + DT->SubtargetInfo.get()); if (!PrintTarget) { if (std::optional MaybeTarget = DT->InstrAnalysis->evaluateMemoryOperandAddress( @@ -2430,7 +2430,7 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, break; } - // Branch targets are printed just after the instructions. + // Instruction targets are printed just after the instructions. // Print the labels corresponding to the target if there's any. bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target); bool LabelAvailable = AllLabels.count(Target);