Skip to content
Open
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
52ebb65
Remove changes affecting non-RISCV targets
arjunUpatel Jun 10, 2025
49f276e
Update test output to match previous functionality
arjunUpatel Jun 12, 2025
5e1cf12
Add support for zclsd and zilsd extensions + tests
arjunUpatel Jun 17, 2025
11c50dc
Pass subtargetinfo as function argument
arjunUpatel Jun 18, 2025
2241583
Run clang format
arjunUpatel Jun 18, 2025
7635b70
Remove precanned binaries from tests and invoke clang during tests
arjunUpatel Jun 19, 2025
9dff558
Fix typo
arjunUpatel Jun 20, 2025
b738bf1
Enable address resolution for load/store instructions relative to zer…
arjunUpatel Jun 20, 2025
9361828
Edit comments to follow LLVM coding style
arjunUpatel Jun 23, 2025
e942f63
Use llvm-mc over clang for compilation in tests
arjunUpatel Jun 24, 2025
86d6bd5
Update comments
arjunUpatel Jun 24, 2025
1e1a37c
Differentiate comments in tests from llvm-lit directives
arjunUpatel Jun 24, 2025
b2a8928
Merge evaluateInstruction into evaluateBranch
arjunUpatel Jun 26, 2025
6034372
Run clang format
arjunUpatel Jun 26, 2025
3723ffe
Rename evaluateBranch to findTargetAddress for MCInstrAnalysis
arjunUpatel Jul 3, 2025
4156098
Update documentation for findTargetAddress
arjunUpatel Jul 3, 2025
dc35c0b
Formatting nits
arjunUpatel Jul 3, 2025
4f92b91
Revert changes to cross-project-tests
arjunUpatel Jul 30, 2025
090519f
Delete 32 bit tests
arjunUpatel Jul 30, 2025
06841d3
Fix linux build error
arjunUpatel Jul 30, 2025
49d69e1
Update tests. Improve test comments
arjunUpatel Aug 22, 2025
b356402
Rename test
arjunUpatel Aug 22, 2025
d666747
Add unit tests
arjunUpatel Aug 22, 2025
279d53b
Update llvm/include/llvm/MC/MCInstrAnalysis.h
arjunUpatel Aug 22, 2025
f3b6d7b
Format unit tests + address nits
arjunUpatel Aug 25, 2025
8c4cf89
Merge branch 'main' into riscv-address-resolution
arjunUpatel Aug 29, 2025
d177ccf
Add CMakeList for new unit test
arjunUpatel Aug 30, 2025
15b7ece
Update RISCVMCInstAnalysis.cpp
arjunUpatel Aug 31, 2025
ec109f9
Update llvm/test/tools/llvm-objdump/RISCV/riscv-disassembly-address-r…
arjunUpatel Sep 4, 2025
dab085a
Update llvm/test/tools/llvm-objdump/RISCV/riscv-disassembly-address-r…
arjunUpatel Sep 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions llvm/unittests/MC/RISCV/RISCVMCInstAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//===- RISCVMCInstAnalysis.cpp - Unit tests for RISCV MCInstrAnalysis ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSubTargetInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/MathExtras.h"
#include "gtest/gtest.h"
#include <cstdint>
#include <memory>

using namespace llvm;

namespace {

struct TestContext {
const char *TripleName = "riscv32-unknown-elf";
std::unique_ptr<MCRegisterInfo> MRI;
std::unique_ptr<MCAsmInfo> MAI;
std::unique_ptr<MCInstrInfo> MII;
std::unique_ptr<MCInstrAnalysis> MIA;
std::unique_ptr<MCContext> Ctx;
std::unique_ptr<const MCSubtargetInfo> STI;

TestContext(const char *TripleName) {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();

std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
if (!TheTarget)
return;

MRI.reset(TheTarget->createMCRegInfo(TripleName));
MII.reset(TheTarget->createMCInstrInfo());
MIA.reset(TheTarget->createMCInstrAnalysis(MII.get()));
MCTargetOptions MCOptions;
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
Ctx = std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(), /*MSTI=*/nullptr);
const char *MCPU = "generic";
std::string Features = ""; // No extensions, just RV32I
STI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features));
}

operator bool() { return Ctx.get() && MIA.get(); }
operator MCContext &() { return *Ctx; }
MCInstrAnalysis &getInstrAnalysis() { return *MIA; }
};

TestContext &getTestContext() {
static TestContext Ctx;
return Ctx;
}

} // end anonymous namespace

// Helper to create an MCInst with register and immediate operands
static MCInst makeInst(unsigned Opcode, std::initializer_list<MCOperand> Ops) {
MCInst Inst;
Inst.setOpcode(Opcode);
for (const auto &Op : Ops)
Inst.addOperand(Op);
return Inst;
}

TEST(RISCVMCInstrAnalysis, FindTargetAddressWithRegisterState) {
if (!getTestContext())
GTEST_SKIP();
auto &MIA = getTestContext().getInstrAnalysis();

// Set up variables.
uint64_t Addr = 0x2, Target;
uint32_t mask = ~(0); // All bits set to 1.
uint64_t lowerImm = 0xfff; // Lower 12 bits set to 1.
bool found;

// ------------ Test 1 --------------
// Verifies accuracy of the result when ADDI (and related instructions, see
// switch case in RISCVTargetDesc.cpp) is involved in an instruction sequence.
// ADDI only retains the bottom XLEN bits, making it dependent on the target.
// This masking is especially apparent in 32-bit targets as overflow must
// correctly be discarded
uint64_t upperImm1 = 0 | mask;
upperImm1 >>= 12; // Bottom 20 bits set to 1.

// 1. AUIPC x5, 0xFFFFF.
MCInst auipc = makeInst(/*AUIPC=*/23, {MCOperand::createReg(5), MCOperand::createImm(upperImm1)});
// 2. ADDI x5, x5, 0xFFF.
MCInst addi = makeInst(/*ADDI=*/13, {MCOperand::createReg(5), MCOperand::createReg(5), MCOperand::createImm(lowerImm)});

MIA.updateState(auipc, Addr);
found = MIA.findTargetAddress(addi, Addr, 4, Target, nullptr);
EXPECT_TRUE(found);

uint64_t expected1 = ((upperImm1 << 12) + lowerImm + Addr) & maskTrailingOnes<uint64_t>(32);
EXPECT_EQ(Target, expected1);
MIA.resetState();

// ------------------- Test 2 -----------------
// Verifies the correctness when ADDIW is involved in a sequence. ADDIW
// performs a sign extension up to 64 bits based on the 32nd bit after the
// result has been computed.
mask >>= 1; // Bottom 31 bits set to 1.

uint64_t upper_bits2 = 0 | mask;
upper_bits2 >>= 12; // Bottom 19 bits set to 1.

// 1. AUIPC x6, 0x7FFFF.
MCInst auipc2 = makeInst(/*AUIPC=*/23, {MCOperand::createReg(6), MCOperand::createImm(upper_bits2)});
// 2. ADDIW x6, x6, 0xFFF.
MCInst addiw = makeInst(/*ADDIW=*/15, {MCOperand::createReg(6), MCOperand::createReg(6), MCOperand::createImm(lowerImm)});

MIA.updateState(auipc2, Addr);
found = MIA.findTargetAddress(addiw, Addr, 4, Target, nullptr);
EXPECT_TRUE(found);

uint64_t expected2 = SignExtend64((upper_bits2 << 12) + lowerImm + Addr, 32);
EXPECT_EQ(Target, expected2);
MIA.resetState();

// All other instructions simply add the immediate to the value loaded in the
// corresponding register by the previous instruction in the sequence. This
// correctness check is implicitly performed in the tests above. For more
// tests related to this feature, check
// llvm/test/tools/llvm-objdump/RISCV/riscv64-ar-coverage.s
}