
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
188 lines
7.7 KiB
C++
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);
|
|
}
|