Skip to content

[LoongArch][MC] Refine MCInstrAnalysis based on registers used #71276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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"));