llvm-project/llvm/unittests/Target/AArch64/SMEAttributesTest.cpp
Sander de Smalen cf72dddaef [AArch64][SME] Add utility class for handling SME attributes.
This patch adds a utility class that will be used in subsequent patches
for parsing the function/callsite attributes and determining whether
changes to PSTATE.SM are needed, or whether a lazy-save mechanism is
required.

It also implements some of the restrictions on the SME attributes
in the IR Verifier pass.

More details about the SME attributes and design can be found
in D131562.

Reviewed By: david-arm, aemerson

Differential Revision: https://reviews.llvm.org/D131570
2022-09-12 12:41:30 +00:00

188 lines
7.7 KiB
C++

#include "Utils/AArch64SMEAttributes.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;
using SA = SMEAttrs;
std::unique_ptr<Module> parseIR(const char *IR) {
static LLVMContext C;
SMDiagnostic Err;
return parseAssemblyString(IR, Err, C);
}
TEST(SMEAttributes, Constructors) {
LLVMContext Context;
ASSERT_TRUE(SA(*parseIR("declare void @foo()")->getFunction("foo"))
.hasNonStreamingInterfaceAndBody());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_sm_body\"")
->getFunction("foo"))
.hasNonStreamingInterface());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_sm_enabled\"")
->getFunction("foo"))
.hasStreamingInterface());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_sm_body\"")
->getFunction("foo"))
.hasStreamingBody());
ASSERT_TRUE(
SA(*parseIR("declare void @foo() \"aarch64_pstate_sm_compatible\"")
->getFunction("foo"))
.hasStreamingCompatibleInterface());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_za_shared\"")
->getFunction("foo"))
.hasSharedZAInterface());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_za_new\"")
->getFunction("foo"))
.hasNewZAInterface());
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_za_preserved\"")
->getFunction("foo"))
.preservesZA());
// Invalid combinations.
EXPECT_DEBUG_DEATH(SA(SA::SM_Enabled | SA::SM_Compatible),
"SM_Enabled and SM_Compatible are mutually exclusive");
EXPECT_DEBUG_DEATH(SA(SA::ZA_New | SA::ZA_Shared),
"ZA_New and ZA_Shared are mutually exclusive");
EXPECT_DEBUG_DEATH(SA(SA::ZA_New | SA::ZA_Preserved),
"ZA_New and ZA_Preserved are mutually exclusive");
// Test that the set() methods equally check validity.
EXPECT_DEBUG_DEATH(SA(SA::SM_Enabled).set(SA::SM_Compatible),
"SM_Enabled and SM_Compatible are mutually exclusive");
EXPECT_DEBUG_DEATH(SA(SA::SM_Compatible).set(SA::SM_Enabled),
"SM_Enabled and SM_Compatible are mutually exclusive");
}
TEST(SMEAttributes, Basics) {
// Test PSTATE.SM interfaces.
ASSERT_TRUE(SA(SA::Normal).hasNonStreamingInterfaceAndBody());
ASSERT_TRUE(SA(SA::SM_Enabled).hasStreamingInterface());
ASSERT_TRUE(SA(SA::SM_Body).hasStreamingBody());
ASSERT_TRUE(SA(SA::SM_Body).hasNonStreamingInterface());
ASSERT_FALSE(SA(SA::SM_Body).hasNonStreamingInterfaceAndBody());
ASSERT_FALSE(SA(SA::SM_Body).hasStreamingInterface());
ASSERT_TRUE(SA(SA::SM_Compatible).hasStreamingCompatibleInterface());
ASSERT_TRUE(
SA(SA::SM_Compatible | SA::SM_Body).hasStreamingCompatibleInterface());
ASSERT_TRUE(SA(SA::SM_Compatible | SA::SM_Body).hasStreamingBody());
ASSERT_FALSE(SA(SA::SM_Compatible | SA::SM_Body).hasNonStreamingInterface());
// Test PSTATE.ZA interfaces.
ASSERT_FALSE(SA(SA::ZA_Shared).hasPrivateZAInterface());
ASSERT_TRUE(SA(SA::ZA_Shared).hasSharedZAInterface());
ASSERT_TRUE(SA(SA::ZA_Shared).hasZAState());
ASSERT_FALSE(SA(SA::ZA_Shared).preservesZA());
ASSERT_TRUE(SA(SA::ZA_Shared | SA::ZA_Preserved).preservesZA());
ASSERT_TRUE(SA(SA::ZA_New).hasPrivateZAInterface());
ASSERT_TRUE(SA(SA::ZA_New).hasNewZAInterface());
ASSERT_TRUE(SA(SA::ZA_New).hasZAState());
ASSERT_FALSE(SA(SA::ZA_New).preservesZA());
ASSERT_TRUE(SA(SA::Normal).hasPrivateZAInterface());
ASSERT_FALSE(SA(SA::Normal).hasNewZAInterface());
ASSERT_FALSE(SA(SA::Normal).hasZAState());
ASSERT_FALSE(SA(SA::Normal).preservesZA());
}
TEST(SMEAttributes, Transitions) {
// Normal -> Normal
ASSERT_FALSE(SA(SA::Normal).requiresSMChange(SA(SA::Normal)));
// Normal -> Normal + LocallyStreaming
ASSERT_FALSE(SA(SA::Normal).requiresSMChange(SA(SA::Normal | SA::SM_Body)));
ASSERT_EQ(*SA(SA::Normal)
.requiresSMChange(SA(SA::Normal | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
// Normal -> Streaming
ASSERT_EQ(*SA(SA::Normal).requiresSMChange(SA(SA::SM_Enabled)), true);
// Normal -> Streaming + LocallyStreaming
ASSERT_EQ(*SA(SA::Normal).requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body)),
true);
ASSERT_EQ(*SA(SA::Normal)
.requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
// Normal -> Streaming-compatible
ASSERT_FALSE(SA(SA::Normal).requiresSMChange(SA(SA::SM_Compatible)));
// Normal -> Streaming-compatible + LocallyStreaming
ASSERT_FALSE(
SA(SA::Normal).requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body)));
ASSERT_EQ(*SA(SA::Normal)
.requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
// Streaming -> Normal
ASSERT_EQ(*SA(SA::SM_Enabled).requiresSMChange(SA(SA::Normal)), false);
// Streaming -> Normal + LocallyStreaming
ASSERT_EQ(*SA(SA::SM_Enabled).requiresSMChange(SA(SA::Normal | SA::SM_Body)),
false);
ASSERT_FALSE(SA(SA::SM_Enabled)
.requiresSMChange(SA(SA::Normal | SA::SM_Body),
/*BodyOverridesInterface=*/true));
// Streaming -> Streaming
ASSERT_FALSE(SA(SA::SM_Enabled).requiresSMChange(SA(SA::SM_Enabled)));
// Streaming -> Streaming + LocallyStreaming
ASSERT_FALSE(
SA(SA::SM_Enabled).requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body)));
ASSERT_FALSE(SA(SA::SM_Enabled)
.requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body),
/*BodyOverridesInterface=*/true));
// Streaming -> Streaming-compatible
ASSERT_FALSE(SA(SA::SM_Enabled).requiresSMChange(SA(SA::SM_Compatible)));
// Streaming -> Streaming-compatible + LocallyStreaming
ASSERT_FALSE(
SA(SA::SM_Enabled).requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body)));
ASSERT_FALSE(SA(SA::SM_Enabled)
.requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body),
/*BodyOverridesInterface=*/true));
// Streaming-compatible -> Normal
ASSERT_EQ(*SA(SA::SM_Compatible).requiresSMChange(SA(SA::Normal)), false);
ASSERT_EQ(
*SA(SA::SM_Compatible).requiresSMChange(SA(SA::Normal | SA::SM_Body)),
false);
ASSERT_EQ(*SA(SA::SM_Compatible)
.requiresSMChange(SA(SA::Normal | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
// Streaming-compatible -> Streaming
ASSERT_EQ(*SA(SA::SM_Compatible).requiresSMChange(SA(SA::SM_Enabled)), true);
// Streaming-compatible -> Streaming + LocallyStreaming
ASSERT_EQ(
*SA(SA::SM_Compatible).requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body)),
true);
ASSERT_EQ(*SA(SA::SM_Compatible)
.requiresSMChange(SA(SA::SM_Enabled | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
// Streaming-compatible -> Streaming-compatible
ASSERT_FALSE(SA(SA::SM_Compatible).requiresSMChange(SA(SA::SM_Compatible)));
// Streaming-compatible -> Streaming-compatible + LocallyStreaming
ASSERT_FALSE(SA(SA::SM_Compatible)
.requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body)));
ASSERT_EQ(*SA(SA::SM_Compatible)
.requiresSMChange(SA(SA::SM_Compatible | SA::SM_Body),
/*BodyOverridesInterface=*/true),
true);
}