From 71ddde8ba52af7277b8f3a8dffa570963a3069f2 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 7 Jan 2025 07:14:41 -0800 Subject: [PATCH] [RISCV][llvm-exegesis] Add unittests. NFC (#121862) This is largely based on Mips and PowerPC. --- .../tools/llvm-exegesis/CMakeLists.txt | 3 + .../tools/llvm-exegesis/RISCV/CMakeLists.txt | 21 +++ .../RISCV/SnippetGeneratorTest.cpp | 122 ++++++++++++++++++ .../tools/llvm-exegesis/RISCV/TargetTest.cpp | 47 +++++++ .../tools/llvm-exegesis/RISCV/TestBase.h | 44 +++++++ 5 files changed, 237 insertions(+) create mode 100644 llvm/unittests/tools/llvm-exegesis/RISCV/CMakeLists.txt create mode 100644 llvm/unittests/tools/llvm-exegesis/RISCV/SnippetGeneratorTest.cpp create mode 100644 llvm/unittests/tools/llvm-exegesis/RISCV/TargetTest.cpp create mode 100644 llvm/unittests/tools/llvm-exegesis/RISCV/TestBase.h diff --git a/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt index 3ee3a0dc6b5d04..735f17ab03e612 100644 --- a/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt +++ b/llvm/unittests/tools/llvm-exegesis/CMakeLists.txt @@ -53,6 +53,9 @@ endif() if(LLVM_TARGETS_TO_BUILD MATCHES "Mips") include(Mips/CMakeLists.txt) endif() +if(LLVM_TARGETS_TO_BUILD MATCHES "RISCV") + include(RISCV/CMakeLists.txt) +endif() include_directories(${exegesis_includes}) diff --git a/llvm/unittests/tools/llvm-exegesis/RISCV/CMakeLists.txt b/llvm/unittests/tools/llvm-exegesis/RISCV/CMakeLists.txt new file mode 100644 index 00000000000000..1984819be7738b --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/RISCV/CMakeLists.txt @@ -0,0 +1,21 @@ +add_llvm_exegesis_unittest_includes( + ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV + ${LLVM_BINARY_DIR}/lib/Target/RISCV + ${LLVM_MAIN_SRC_DIR}/tools/llvm-exegesis/lib + ) + +add_llvm_exegesis_unittest_link_components( + MC + MCParser + Object + Support + Symbolize + RISCV + ) + +add_llvm_exegesis_unittest_sources( + SnippetGeneratorTest.cpp + TargetTest.cpp + ) +add_llvm_exegesis_unittest_link_libraries( + LLVMExegesisRISCV) diff --git a/llvm/unittests/tools/llvm-exegesis/RISCV/SnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/RISCV/SnippetGeneratorTest.cpp new file mode 100644 index 00000000000000..5920b79da9d3e8 --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/RISCV/SnippetGeneratorTest.cpp @@ -0,0 +1,122 @@ +//===-- SnippetGeneratorTest.cpp --------------------------------*- C++ -*-===// +// +// 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 "../Common/AssemblerUtils.h" +#include "LlvmState.h" +#include "MCInstrDescView.h" +#include "ParallelSnippetGenerator.h" +#include "RISCVInstrInfo.h" +#include "RegisterAliasing.h" +#include "SerialSnippetGenerator.h" +#include "TestBase.h" + +namespace llvm { +namespace exegesis { +namespace { + +using testing::AnyOf; +using testing::ElementsAre; +using testing::HasSubstr; +using testing::SizeIs; + +MATCHER(IsInvalid, "") { return !arg.isValid(); } +MATCHER(IsReg, "") { return arg.isReg(); } + +template +class RISCVSnippetGeneratorTest : public RISCVTestBase { +protected: + RISCVSnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()) {} + + std::vector checkAndGetCodeTemplates(unsigned Opcode) { + randomGenerator().seed(0); // Initialize seed. + const Instruction &Instr = State.getIC().getInstr(Opcode); + auto CodeTemplateOrError = Generator.generateCodeTemplates( + &Instr, State.getRATC().emptyRegisters()); + EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration. + return std::move(CodeTemplateOrError.get()); + } + + SnippetGeneratorT Generator; +}; + +using RISCVSerialSnippetGeneratorTest = + RISCVSnippetGeneratorTest; + +using RISCVParallelSnippetGeneratorTest = + RISCVSnippetGeneratorTest; + +TEST_F(RISCVSerialSnippetGeneratorTest, + ImplicitSelfDependencyThroughExplicitRegs) { + // - ADD + // - Op0 Explicit Def RegClass(GPR) + // - Op1 Explicit Use RegClass(GPR) + // - Op2 Explicit Use RegClass(GPR) + // - Var0 [Op0] + // - Var1 [Op1] + // - Var2 [Op2] + // - hasAliasingRegisters + const unsigned Opcode = RISCV::ADD; + const auto CodeTemplates = checkAndGetCodeTemplates(Opcode); + ASSERT_THAT(CodeTemplates, SizeIs(1)); + const auto &CT = CodeTemplates[0]; + EXPECT_THAT(CT.Execution, ExecutionMode::SERIAL_VIA_EXPLICIT_REGS); + ASSERT_THAT(CT.Instructions, SizeIs(1)); + const InstructionTemplate &IT = CT.Instructions[0]; + EXPECT_THAT(IT.getOpcode(), Opcode); + ASSERT_THAT(IT.getVariableValues(), SizeIs(3)); + EXPECT_THAT(IT.getVariableValues(), + AnyOf(ElementsAre(IsReg(), IsInvalid(), IsReg()), + ElementsAre(IsReg(), IsReg(), IsInvalid()))) + << "Op0 is either set to Op1 or to Op2"; +} + +TEST_F(RISCVSerialSnippetGeneratorTest, + ImplicitSelfDependencyThroughExplicitRegsForbidAll) { + // - XOR + // - Op0 Explicit Def RegClass(GPR) + // - Op1 Explicit Use RegClass(GPR) + // - Op2 Explicit Use RegClass(GPR) + // - Var0 [Op0] + // - Var1 [Op1] + // - Var2 [Op2] + // - hasAliasingRegisters + randomGenerator().seed(0); // Initialize seed. + const Instruction &Instr = State.getIC().getInstr(RISCV::XOR); + auto AllRegisters = State.getRATC().emptyRegisters(); + AllRegisters.flip(); + EXPECT_TRUE(errorToBool( + Generator.generateCodeTemplates(&Instr, AllRegisters).takeError())); +} + +TEST_F(RISCVParallelSnippetGeneratorTest, MemoryUse) { + // LB reads from memory. + // - LB + // - Op0 Explicit Def RegClass(GPR) + // - Op1 Explicit Use Memory RegClass(GPR) + // - Op2 Explicit Use Memory + // - Var0 [Op0] + // - Var1 [Op1] + // - Var2 [Op2] + // - hasMemoryOperands + const unsigned Opcode = RISCV::LB; + const auto CodeTemplates = checkAndGetCodeTemplates(Opcode); + ASSERT_THAT(CodeTemplates, SizeIs(1)); + const auto &CT = CodeTemplates[0]; + EXPECT_THAT(CT.Info, HasSubstr("instruction has no tied variables")); + EXPECT_THAT(CT.Execution, ExecutionMode::UNKNOWN); + ASSERT_THAT(CT.Instructions, + SizeIs(ParallelSnippetGenerator::kMinNumDifferentAddresses)); + const InstructionTemplate &IT = CT.Instructions[0]; + EXPECT_THAT(IT.getOpcode(), Opcode); + ASSERT_THAT(IT.getVariableValues(), SizeIs(3)); + EXPECT_EQ(IT.getVariableValues()[1].getReg(), RISCV::X10); +} + +} // namespace +} // namespace exegesis +} // namespace llvm diff --git a/llvm/unittests/tools/llvm-exegesis/RISCV/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/RISCV/TargetTest.cpp new file mode 100644 index 00000000000000..745a6c68c9a0e1 --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/RISCV/TargetTest.cpp @@ -0,0 +1,47 @@ +//===-- TargetTest.cpp ---------------------------------------*- C++ -*-===// +// +// 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 "Target.h" + +#include +#include + +#include "MCTargetDesc/RISCVMCTargetDesc.h" +#include "TestBase.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace exegesis { + +void InitializeRISCVExegesisTarget(); + +namespace { + +using testing::IsEmpty; +using testing::Not; +using testing::NotNull; + +class RISCVTargetTest : public RISCVTestBase { +protected: + std::vector setRegTo(unsigned Reg, const APInt &Value) { + return State.getExegesisTarget().setRegTo(State.getSubtargetInfo(), Reg, + Value); + } +}; + +TEST_F(RISCVTargetTest, SetRegToConstant) { + const auto Insts = setRegTo(RISCV::X10, APInt()); + EXPECT_THAT(Insts, Not(IsEmpty())); +} + +} // namespace +} // namespace exegesis +} // namespace llvm diff --git a/llvm/unittests/tools/llvm-exegesis/RISCV/TestBase.h b/llvm/unittests/tools/llvm-exegesis/RISCV/TestBase.h new file mode 100644 index 00000000000000..66748fb9a2ce1b --- /dev/null +++ b/llvm/unittests/tools/llvm-exegesis/RISCV/TestBase.h @@ -0,0 +1,44 @@ +//===-- TestBase.h ----------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Test fixture common to all RISC-V tests. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_RISCV_TESTBASE_H +#define LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_RISCV_TESTBASE_H + +#include "LlvmState.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace exegesis { + +void InitializeRISCVExegesisTarget(); + +class RISCVTestBase : public ::testing::Test { +protected: + RISCVTestBase() + : State(cantFail( + LLVMState::Create("riscv64-unknown-linux", "generic-rv64"))) {} + + static void SetUpTestCase() { + LLVMInitializeRISCVTargetInfo(); + LLVMInitializeRISCVTargetMC(); + LLVMInitializeRISCVTarget(); + InitializeRISCVExegesisTarget(); + } + + const LLVMState State; +}; + +} // namespace exegesis +} // namespace llvm + +#endif