From 9bcec7c3b726c09f7561c6abfe26353fda538a88 Mon Sep 17 00:00:00 2001 From: Gergely Balint Date: Mon, 25 Aug 2025 13:45:41 +0000 Subject: [PATCH 1/2] [AArch64][NFC] Add MCInstrAnalysis unittests --- llvm/include/llvm/MC/MCInstrAnalysis.h | 4 + llvm/unittests/Target/AArch64/CMakeLists.txt | 1 + .../Target/AArch64/MCInstrAnalysisTest.cpp | 142 ++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp diff --git a/llvm/include/llvm/MC/MCInstrAnalysis.h b/llvm/include/llvm/MC/MCInstrAnalysis.h index 63a4e02a92360..3cfc879b92ef5 100644 --- a/llvm/include/llvm/MC/MCInstrAnalysis.h +++ b/llvm/include/llvm/MC/MCInstrAnalysis.h @@ -81,6 +81,10 @@ class LLVM_ABI MCInstrAnalysis { return Info->get(Inst.getOpcode()).isTerminator(); } + virtual bool isBarrier(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isBarrier(); + } + virtual bool mayAffectControlFlow(const MCInst &Inst, const MCRegisterInfo &MCRI) const { if (isBranch(Inst) || isCall(Inst) || isReturn(Inst) || diff --git a/llvm/unittests/Target/AArch64/CMakeLists.txt b/llvm/unittests/Target/AArch64/CMakeLists.txt index 9387ca90dd31a..3875163772575 100644 --- a/llvm/unittests/Target/AArch64/CMakeLists.txt +++ b/llvm/unittests/Target/AArch64/CMakeLists.txt @@ -34,4 +34,5 @@ add_llvm_target_unittest(AArch64Tests AArch64SVESchedPseudoTest.cpp AArch64SelectionDAGTest.cpp Immediates.cpp + MCInstrAnalysisTest.cpp ) diff --git a/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp new file mode 100644 index 0000000000000..931dfba2193d1 --- /dev/null +++ b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp @@ -0,0 +1,142 @@ +//===- MCInstrAnalysisTest.cpp - AArch64MCInstrAnalysis unit tests --------===// +// +// 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/MCInstrAnalysis.h" +#include "MCTargetDesc/AArch64MCTargetDesc.h" +#include "Utils/AArch64BaseInfo.h" +#include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" + +#include "gtest/gtest.h" + +#include + +using namespace llvm; + +namespace { + +class InstrAnalysisTest : public testing::TestWithParam { +protected: + std::unique_ptr Info; + std::unique_ptr Analysis; + + static void SetUpTestSuite() { + LLVMInitializeAArch64TargetInfo(); + LLVMInitializeAArch64Target(); + LLVMInitializeAArch64TargetMC(); + } + + InstrAnalysisTest() { + std::string Error; + const Target *TheTarget = + TargetRegistry::lookupTarget(Triple::normalize(GetParam()), Error); + Info = std::unique_ptr(TheTarget->createMCInstrInfo()); + Analysis = std::unique_ptr( + TheTarget->createMCInstrAnalysis(Info.get())); + } +}; + +} // namespace + +static MCInst beq() { + return MCInstBuilder(AArch64::Bcc).addImm(AArch64CC::EQ).addReg(AArch64::X0); +} +static MCInst tbz(unsigned Rt = AArch64::X0, unsigned Imm = 0, + unsigned Label = 32) { + return MCInstBuilder(AArch64::TBZX).addReg(Rt).addImm(Imm).addImm(Label); +} +static MCInst b() { return MCInstBuilder(AArch64::B).addImm(32); } +static MCInst bl() { return MCInstBuilder(AArch64::BL).addImm(32); } +static MCInst br(unsigned Rn = AArch64::X0) { + return MCInstBuilder(AArch64::BR).addReg(Rn); +} +static MCInst ret(unsigned Rn = AArch64::LR) { + return MCInstBuilder(AArch64::RET).addReg(Rn); +} +static MCInst hlt() { return MCInstBuilder(AArch64::HLT); } +static MCInst brk() { return MCInstBuilder(AArch64::BRK); } + +TEST_P(InstrAnalysisTest, IsTerminator) { + EXPECT_TRUE(Analysis->isTerminator(beq())); + EXPECT_TRUE(Analysis->isTerminator(tbz())); + EXPECT_TRUE(Analysis->isTerminator(b())); + EXPECT_FALSE(Analysis->isTerminator(bl())); + EXPECT_TRUE(Analysis->isTerminator(br())); + EXPECT_TRUE(Analysis->isTerminator(ret())); + EXPECT_FALSE(Analysis->isTerminator(hlt())); + EXPECT_FALSE(Analysis->isTerminator(brk())); +} + +TEST_P(InstrAnalysisTest, IsBarrier) { + EXPECT_FALSE(Analysis->isBarrier(beq())); + EXPECT_FALSE(Analysis->isBarrier(tbz())); + EXPECT_TRUE(Analysis->isBarrier(b())); + EXPECT_FALSE(Analysis->isBarrier(bl())); + EXPECT_TRUE(Analysis->isBarrier(br())); + EXPECT_TRUE(Analysis->isBarrier(ret())); + EXPECT_FALSE(Analysis->isBarrier(hlt())); + EXPECT_FALSE(Analysis->isBarrier(brk())); +} + +TEST_P(InstrAnalysisTest, IsCall) { + EXPECT_FALSE(Analysis->isCall(beq())); + EXPECT_FALSE(Analysis->isCall(tbz())); + EXPECT_FALSE(Analysis->isCall(b())); + EXPECT_TRUE(Analysis->isCall(bl())); + EXPECT_FALSE(Analysis->isCall(br())); + EXPECT_FALSE(Analysis->isCall(ret())); +} + +TEST_P(InstrAnalysisTest, IsReturn) { + EXPECT_FALSE(Analysis->isReturn(beq())); + EXPECT_FALSE(Analysis->isReturn(tbz())); + EXPECT_FALSE(Analysis->isReturn(b())); + EXPECT_FALSE(Analysis->isReturn(bl())); + EXPECT_FALSE(Analysis->isReturn(br())); + EXPECT_FALSE(Analysis->isReturn(br(AArch64::LR))); + EXPECT_TRUE(Analysis->isReturn(ret())); +} + +TEST_P(InstrAnalysisTest, IsBranch) { + EXPECT_TRUE(Analysis->isBranch(beq())); + EXPECT_TRUE(Analysis->isBranch(tbz())); + EXPECT_TRUE(Analysis->isBranch(b())); + EXPECT_FALSE(Analysis->isBranch(bl())); + EXPECT_TRUE(Analysis->isBranch(br())); + EXPECT_FALSE(Analysis->isBranch(ret())); +} + +TEST_P(InstrAnalysisTest, IsConditionalBranch) { + EXPECT_TRUE(Analysis->isConditionalBranch(beq())); + EXPECT_TRUE(Analysis->isConditionalBranch(tbz())); + EXPECT_FALSE(Analysis->isConditionalBranch(b())); + EXPECT_FALSE(Analysis->isConditionalBranch(bl())); + EXPECT_FALSE(Analysis->isConditionalBranch(ret())); +} + +TEST_P(InstrAnalysisTest, IsUnconditionalBranch) { + EXPECT_FALSE(Analysis->isUnconditionalBranch(beq())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(tbz())); + EXPECT_TRUE(Analysis->isUnconditionalBranch(b())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(bl())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(br())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(ret())); +} + +TEST_P(InstrAnalysisTest, IsIndirectBranch) { + EXPECT_FALSE(Analysis->isIndirectBranch(beq())); + EXPECT_FALSE(Analysis->isIndirectBranch(tbz())); + EXPECT_FALSE(Analysis->isIndirectBranch(b())); + EXPECT_FALSE(Analysis->isIndirectBranch(bl())); + EXPECT_TRUE(Analysis->isIndirectBranch(br())); + EXPECT_FALSE(Analysis->isIndirectBranch(ret())); +} + +INSTANTIATE_TEST_SUITE_P(AArch64, InstrAnalysisTest, + testing::Values("aarch64")); From 1e3cc41311b38590751f6ccc4ed715741b93783c Mon Sep 17 00:00:00 2001 From: Gergely Balint Date: Thu, 28 Aug 2025 08:35:37 +0000 Subject: [PATCH 2/2] [AArch64][NFC] Extend test with more instructions Added blr, cbz, retaa, eret, svc, hvc, smc. --- .../Target/AArch64/MCInstrAnalysisTest.cpp | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp index 931dfba2193d1..271d19ee3a1f9 100644 --- a/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp +++ b/llvm/unittests/Target/AArch64/MCInstrAnalysisTest.cpp @@ -51,91 +51,140 @@ static MCInst tbz(unsigned Rt = AArch64::X0, unsigned Imm = 0, unsigned Label = 32) { return MCInstBuilder(AArch64::TBZX).addReg(Rt).addImm(Imm).addImm(Label); } +static MCInst cbz(unsigned Rt = AArch64::X0, unsigned Label = 32) { + return MCInstBuilder(AArch64::CBZX).addReg(Rt).addImm(Label); +} static MCInst b() { return MCInstBuilder(AArch64::B).addImm(32); } static MCInst bl() { return MCInstBuilder(AArch64::BL).addImm(32); } static MCInst br(unsigned Rn = AArch64::X0) { return MCInstBuilder(AArch64::BR).addReg(Rn); } +static MCInst blr(unsigned Rn = AArch64::X0) { + return MCInstBuilder(AArch64::BLR).addReg(Rn); +} static MCInst ret(unsigned Rn = AArch64::LR) { return MCInstBuilder(AArch64::RET).addReg(Rn); } +static MCInst retaa() { return MCInstBuilder(AArch64::RETAA); } +static MCInst eret() { return MCInstBuilder(AArch64::ERET); } static MCInst hlt() { return MCInstBuilder(AArch64::HLT); } static MCInst brk() { return MCInstBuilder(AArch64::BRK); } +static MCInst svc() { return MCInstBuilder(AArch64::SVC); } +static MCInst hvc() { return MCInstBuilder(AArch64::HVC); } +static MCInst smc() { return MCInstBuilder(AArch64::SMC); } TEST_P(InstrAnalysisTest, IsTerminator) { EXPECT_TRUE(Analysis->isTerminator(beq())); EXPECT_TRUE(Analysis->isTerminator(tbz())); + EXPECT_TRUE(Analysis->isTerminator(cbz())); EXPECT_TRUE(Analysis->isTerminator(b())); EXPECT_FALSE(Analysis->isTerminator(bl())); + EXPECT_FALSE(Analysis->isTerminator(blr())); EXPECT_TRUE(Analysis->isTerminator(br())); EXPECT_TRUE(Analysis->isTerminator(ret())); + EXPECT_TRUE(Analysis->isTerminator(retaa())); + EXPECT_TRUE(Analysis->isTerminator(eret())); EXPECT_FALSE(Analysis->isTerminator(hlt())); EXPECT_FALSE(Analysis->isTerminator(brk())); + EXPECT_FALSE(Analysis->isTerminator(svc())); + EXPECT_FALSE(Analysis->isTerminator(hvc())); + EXPECT_FALSE(Analysis->isTerminator(smc())); } TEST_P(InstrAnalysisTest, IsBarrier) { EXPECT_FALSE(Analysis->isBarrier(beq())); EXPECT_FALSE(Analysis->isBarrier(tbz())); + EXPECT_FALSE(Analysis->isBarrier(cbz())); EXPECT_TRUE(Analysis->isBarrier(b())); EXPECT_FALSE(Analysis->isBarrier(bl())); + EXPECT_FALSE(Analysis->isBarrier(blr())); EXPECT_TRUE(Analysis->isBarrier(br())); EXPECT_TRUE(Analysis->isBarrier(ret())); + EXPECT_TRUE(Analysis->isBarrier(retaa())); + EXPECT_TRUE(Analysis->isBarrier(eret())); EXPECT_FALSE(Analysis->isBarrier(hlt())); EXPECT_FALSE(Analysis->isBarrier(brk())); + EXPECT_FALSE(Analysis->isBarrier(svc())); + EXPECT_FALSE(Analysis->isBarrier(hvc())); + EXPECT_FALSE(Analysis->isBarrier(smc())); } TEST_P(InstrAnalysisTest, IsCall) { EXPECT_FALSE(Analysis->isCall(beq())); EXPECT_FALSE(Analysis->isCall(tbz())); + EXPECT_FALSE(Analysis->isCall(cbz())); EXPECT_FALSE(Analysis->isCall(b())); EXPECT_TRUE(Analysis->isCall(bl())); + EXPECT_TRUE(Analysis->isCall(blr())); EXPECT_FALSE(Analysis->isCall(br())); EXPECT_FALSE(Analysis->isCall(ret())); + EXPECT_FALSE(Analysis->isCall(retaa())); + EXPECT_FALSE(Analysis->isCall(eret())); } TEST_P(InstrAnalysisTest, IsReturn) { EXPECT_FALSE(Analysis->isReturn(beq())); EXPECT_FALSE(Analysis->isReturn(tbz())); + EXPECT_FALSE(Analysis->isReturn(cbz())); EXPECT_FALSE(Analysis->isReturn(b())); EXPECT_FALSE(Analysis->isReturn(bl())); EXPECT_FALSE(Analysis->isReturn(br())); + EXPECT_FALSE(Analysis->isReturn(blr())); EXPECT_FALSE(Analysis->isReturn(br(AArch64::LR))); EXPECT_TRUE(Analysis->isReturn(ret())); + EXPECT_TRUE(Analysis->isReturn(retaa())); + EXPECT_TRUE(Analysis->isReturn(eret())); } TEST_P(InstrAnalysisTest, IsBranch) { EXPECT_TRUE(Analysis->isBranch(beq())); EXPECT_TRUE(Analysis->isBranch(tbz())); + EXPECT_TRUE(Analysis->isBranch(cbz())); EXPECT_TRUE(Analysis->isBranch(b())); EXPECT_FALSE(Analysis->isBranch(bl())); + EXPECT_FALSE(Analysis->isBranch(blr())); EXPECT_TRUE(Analysis->isBranch(br())); EXPECT_FALSE(Analysis->isBranch(ret())); + EXPECT_FALSE(Analysis->isBranch(retaa())); + EXPECT_FALSE(Analysis->isBranch(eret())); } TEST_P(InstrAnalysisTest, IsConditionalBranch) { EXPECT_TRUE(Analysis->isConditionalBranch(beq())); EXPECT_TRUE(Analysis->isConditionalBranch(tbz())); + EXPECT_TRUE(Analysis->isConditionalBranch(cbz())); EXPECT_FALSE(Analysis->isConditionalBranch(b())); EXPECT_FALSE(Analysis->isConditionalBranch(bl())); + EXPECT_FALSE(Analysis->isConditionalBranch(blr())); EXPECT_FALSE(Analysis->isConditionalBranch(ret())); + EXPECT_FALSE(Analysis->isConditionalBranch(retaa())); + EXPECT_FALSE(Analysis->isConditionalBranch(eret())); } TEST_P(InstrAnalysisTest, IsUnconditionalBranch) { EXPECT_FALSE(Analysis->isUnconditionalBranch(beq())); EXPECT_FALSE(Analysis->isUnconditionalBranch(tbz())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(cbz())); EXPECT_TRUE(Analysis->isUnconditionalBranch(b())); EXPECT_FALSE(Analysis->isUnconditionalBranch(bl())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(blr())); EXPECT_FALSE(Analysis->isUnconditionalBranch(br())); EXPECT_FALSE(Analysis->isUnconditionalBranch(ret())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(retaa())); + EXPECT_FALSE(Analysis->isUnconditionalBranch(eret())); } TEST_P(InstrAnalysisTest, IsIndirectBranch) { EXPECT_FALSE(Analysis->isIndirectBranch(beq())); EXPECT_FALSE(Analysis->isIndirectBranch(tbz())); + EXPECT_FALSE(Analysis->isIndirectBranch(cbz())); EXPECT_FALSE(Analysis->isIndirectBranch(b())); EXPECT_FALSE(Analysis->isIndirectBranch(bl())); + EXPECT_FALSE(Analysis->isIndirectBranch(blr())); EXPECT_TRUE(Analysis->isIndirectBranch(br())); EXPECT_FALSE(Analysis->isIndirectBranch(ret())); + EXPECT_FALSE(Analysis->isIndirectBranch(retaa())); + EXPECT_FALSE(Analysis->isIndirectBranch(eret())); } INSTANTIATE_TEST_SUITE_P(AArch64, InstrAnalysisTest,