1//===- EnableArmStreaming.cpp - Enable Armv9 Streaming SVE mode -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass enables the Armv9 Scalable Matrix Extension (SME) Streaming SVE
10// (SSVE) mode [1][2] by adding either of the following attributes to
11// 'func.func' ops:
12//
13// * 'arm_streaming' (default)
14// * 'arm_locally_streaming'
15//
16// It can also optionally enable the ZA storage array.
17//
18// Streaming-mode is part of the interface (ABI) for functions with the
19// first attribute and it's the responsibility of the caller to manage
20// PSTATE.SM on entry/exit to functions with this attribute [3]. The LLVM
21// backend will emit 'smstart sm' / 'smstop sm' [4] around calls to
22// streaming functions.
23//
24// In locally streaming functions PSTATE.SM is kept internal and managed by
25// the callee on entry/exit. The LLVM backend will emit 'smstart sm' /
26// 'smstop sm' in the prologue / epilogue for functions with this
27// attribute.
28//
29// [1] https://developer.arm.com/documentation/ddi0616/aa
30// [2] https://llvm.org/docs/AArch64SME.html
31// [3] https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#671pstatesm-interfaces
32// [4] https://developer.arm.com/documentation/ddi0602/2023-03/Base-Instructions/SMSTART--Enables-access-to-Streaming-SVE-mode-and-SME-architectural-state--an-alias-of-MSR--immediate--
33//
34//===----------------------------------------------------------------------===//
35
36#include "mlir/Dialect/ArmSME/IR/ArmSME.h"
37#include "mlir/Dialect/ArmSME/Transforms/Passes.h"
38#include "mlir/Dialect/ArmSME/Transforms/PassesEnums.cpp.inc"
39
40#include "mlir/Dialect/Func/IR/FuncOps.h"
41
42#define DEBUG_TYPE "enable-arm-streaming"
43
44namespace mlir {
45namespace arm_sme {
46#define GEN_PASS_DEF_ENABLEARMSTREAMING
47#include "mlir/Dialect/ArmSME/Transforms/Passes.h.inc"
48} // namespace arm_sme
49} // namespace mlir
50
51using namespace mlir;
52using namespace mlir::arm_sme;
53namespace {
54
55constexpr StringLiteral
56 kEnableArmStreamingIgnoreAttr("enable_arm_streaming_ignore");
57
58struct EnableArmStreamingPass
59 : public arm_sme::impl::EnableArmStreamingBase<EnableArmStreamingPass> {
60 EnableArmStreamingPass(ArmStreamingMode streamingMode, ArmZaMode zaMode,
61 bool onlyIfRequiredByOps) {
62 this->streamingMode = streamingMode;
63 this->zaMode = zaMode;
64 this->onlyIfRequiredByOps = onlyIfRequiredByOps;
65 }
66 void runOnOperation() override {
67 auto op = getOperation();
68
69 if (onlyIfRequiredByOps) {
70 bool foundTileOp = false;
71 op.walk([&](Operation *op) {
72 if (llvm::isa<ArmSMETileOpInterface>(op)) {
73 foundTileOp = true;
74 return WalkResult::interrupt();
75 }
76 return WalkResult::advance();
77 });
78 if (!foundTileOp)
79 return;
80 }
81
82 if (op->getAttr(kEnableArmStreamingIgnoreAttr) ||
83 streamingMode == ArmStreamingMode::Disabled)
84 return;
85
86 auto unitAttr = UnitAttr::get(&getContext());
87
88 op->setAttr(stringifyArmStreamingMode(streamingMode), unitAttr);
89
90 // The pass currently only supports enabling ZA when in streaming-mode, but
91 // ZA can be accessed by the SME LDR, STR and ZERO instructions when not in
92 // streaming-mode (see section B1.1.1, IDGNQM of spec [1]). It may be worth
93 // supporting this later.
94 if (zaMode != ArmZaMode::Disabled)
95 op->setAttr(stringifyArmZaMode(zaMode), unitAttr);
96 }
97};
98} // namespace
99
100std::unique_ptr<Pass> mlir::arm_sme::createEnableArmStreamingPass(
101 const ArmStreamingMode streamingMode, const ArmZaMode zaMode,
102 bool onlyIfRequiredByOps) {
103 return std::make_unique<EnableArmStreamingPass>(streamingMode, zaMode,
104 onlyIfRequiredByOps);
105}
106

source code of mlir/lib/Dialect/ArmSME/Transforms/EnableArmStreaming.cpp