Skip to content

Commit

Permalink
[LoongArch][MC] Refine MCInstrAnalysis based on registers used (#71276)
Browse files Browse the repository at this point in the history
MCInstrAnalysis can return properties of instructions (e.g., isCall(),
isBranch(),...) based on the informations that MCInstrDesc can get from
*InstrInfo*.td files. These infos are based on opcodes only, but JIRL
can have different properties based on different registers used.

So this patch refines several MCInstrAnalysis methods: isTerminator,
isCall,isReturn,isBranch,isUnconditionalBranch and isIndirectBranch.

This patch also allows BOLT which will be supported on LoongArch later
to get right instruction infos.
  • Loading branch information
zhaoqi5 committed Nov 10, 2023
1 parent fe8c649 commit f7d7847
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 0 deletions.
76 changes: 76 additions & 0 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,82 @@ class LoongArchMCInstrAnalysis : public MCInstrAnalysis {

return false;
}

bool isTerminator(const MCInst &Inst) const override {
if (MCInstrAnalysis::isTerminator(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() == LoongArch::R0;
}
}

bool isCall(const MCInst &Inst) const override {
if (MCInstrAnalysis::isCall(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() != LoongArch::R0;
}
}

bool isReturn(const MCInst &Inst) const override {
if (MCInstrAnalysis::isReturn(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
Inst.getOperand(1).getReg() == LoongArch::R1;
}
}

bool isBranch(const MCInst &Inst) const override {
if (MCInstrAnalysis::isBranch(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
Inst.getOperand(1).getReg() != LoongArch::R1;
}
}

bool isUnconditionalBranch(const MCInst &Inst) const override {
if (MCInstrAnalysis::isUnconditionalBranch(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
Inst.getOperand(1).getReg() != LoongArch::R1;
}
}

bool isIndirectBranch(const MCInst &Inst) const override {
if (MCInstrAnalysis::isIndirectBranch(Inst))
return true;

switch (Inst.getOpcode()) {
default:
return false;
case LoongArch::JIRL:
return Inst.getOperand(0).getReg() == LoongArch::R0 &&
Inst.getOperand(1).getReg() != LoongArch::R1;
}
}
};

} // end namespace
Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/Target/LoongArch/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(LLVM_LINK_COMPONENTS

add_llvm_target_unittest(LoongArchTests
InstSizes.cpp
MCInstrAnalysisTest.cpp
)

set_property(TARGET LoongArchTests PROPERTY FOLDER "Tests/UnitTests/TargetTests")
107 changes: 107 additions & 0 deletions llvm/unittests/Target/LoongArch/MCInstrAnalysisTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//===- MCInstrAnalysisTest.cpp - LoongArchMCInstrAnalysis 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/LoongArchMCTargetDesc.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"

#include "gtest/gtest.h"

#include <memory>

using namespace llvm;

namespace {

class InstrAnalysisTest : public testing::TestWithParam<const char *> {
protected:
std::unique_ptr<const MCInstrInfo> Info;
std::unique_ptr<const MCInstrAnalysis> Analysis;

static void SetUpTestSuite() {
LLVMInitializeLoongArchTargetInfo();
LLVMInitializeLoongArchTarget();
LLVMInitializeLoongArchTargetMC();
}

InstrAnalysisTest() {
std::string Error;
const Target *TheTarget =
TargetRegistry::lookupTarget(Triple::normalize(GetParam()), Error);
Info = std::unique_ptr<const MCInstrInfo>(TheTarget->createMCInstrInfo());
Analysis = std::unique_ptr<const MCInstrAnalysis>(
TheTarget->createMCInstrAnalysis(Info.get()));
}
};

} // namespace

static MCInst beq() {
return MCInstBuilder(LoongArch::BEQ)
.addReg(LoongArch::R0)
.addReg(LoongArch::R1)
.addImm(32);
}

static MCInst bl() { return MCInstBuilder(LoongArch::BL).addImm(32); }

static MCInst jirl(unsigned RD, unsigned RJ = LoongArch::R10) {
return MCInstBuilder(LoongArch::JIRL).addReg(RD).addReg(RJ).addImm(16);
}

TEST_P(InstrAnalysisTest, IsTerminator) {
EXPECT_TRUE(Analysis->isTerminator(beq()));
EXPECT_FALSE(Analysis->isTerminator(bl()));
EXPECT_TRUE(Analysis->isTerminator(jirl(LoongArch::R0)));
EXPECT_FALSE(Analysis->isTerminator(jirl(LoongArch::R5)));
}

TEST_P(InstrAnalysisTest, IsCall) {
EXPECT_FALSE(Analysis->isCall(beq()));
EXPECT_TRUE(Analysis->isCall(bl()));
EXPECT_TRUE(Analysis->isCall(jirl(LoongArch::R1)));
EXPECT_FALSE(Analysis->isCall(jirl(LoongArch::R0)));
}

TEST_P(InstrAnalysisTest, IsReturn) {
EXPECT_FALSE(Analysis->isReturn(beq()));
EXPECT_FALSE(Analysis->isReturn(bl()));
EXPECT_TRUE(Analysis->isReturn(jirl(LoongArch::R0, LoongArch::R1)));
EXPECT_FALSE(Analysis->isReturn(jirl(LoongArch::R0)));
EXPECT_FALSE(Analysis->isReturn(jirl(LoongArch::R1)));
}

TEST_P(InstrAnalysisTest, IsBranch) {
EXPECT_TRUE(Analysis->isBranch(beq()));
EXPECT_FALSE(Analysis->isBranch(bl()));
EXPECT_TRUE(Analysis->isBranch(jirl(LoongArch::R0)));
EXPECT_FALSE(Analysis->isBranch(jirl(LoongArch::R1)));
EXPECT_FALSE(Analysis->isBranch(jirl(LoongArch::R0, LoongArch::R1)));
}

TEST_P(InstrAnalysisTest, IsUnconditionalBranch) {
EXPECT_FALSE(Analysis->isUnconditionalBranch(beq()));
EXPECT_FALSE(Analysis->isUnconditionalBranch(bl()));
EXPECT_TRUE(Analysis->isUnconditionalBranch(jirl(LoongArch::R0)));
EXPECT_FALSE(Analysis->isUnconditionalBranch(jirl(LoongArch::R1)));
EXPECT_FALSE(
Analysis->isUnconditionalBranch(jirl(LoongArch::R0, LoongArch::R1)));
}

TEST_P(InstrAnalysisTest, IsIndirectBranch) {
EXPECT_FALSE(Analysis->isIndirectBranch(beq()));
EXPECT_FALSE(Analysis->isIndirectBranch(bl()));
EXPECT_TRUE(Analysis->isIndirectBranch(jirl(LoongArch::R0)));
EXPECT_FALSE(Analysis->isIndirectBranch(jirl(LoongArch::R1)));
EXPECT_FALSE(Analysis->isIndirectBranch(jirl(LoongArch::R0, LoongArch::R1)));
}

INSTANTIATE_TEST_SUITE_P(LA32And64, InstrAnalysisTest,
testing::Values("loongarch32", "loongarch64"));

0 comments on commit f7d7847

Please sign in to comment.