blob: 13f12a6c9c30a488de40ba78254a6d1f50cacbf6 [file] [log] [blame]
Sander de Smalen612b0382019-08-06 13:06:40 +00001//==--AArch64StackOffset.h ---------------------------------------*- C++ -*-==//
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 file contains the declaration of the StackOffset class, which is used to
10// describe scalable and non-scalable offsets during frame lowering.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64STACKOFFSET_H
15#define LLVM_LIB_TARGET_AARCH64_AARCH64STACKOFFSET_H
16
17#include "llvm/Support/MachineValueType.h"
18
19namespace llvm {
20
21/// StackOffset is a wrapper around scalable and non-scalable offsets and is
22/// used in several functions such as 'isAArch64FrameOffsetLegal' and
23/// 'emitFrameOffset()'. StackOffsets are described by MVTs, e.g.
24//
25/// StackOffset(1, MVT::nxv16i8)
26//
27/// would describe an offset as being the size of a single SVE vector.
28///
29/// The class also implements simple arithmetic (addition/subtraction) on these
30/// offsets, e.g.
31//
32/// StackOffset(1, MVT::nxv16i8) + StackOffset(1, MVT::i64)
33//
34/// describes an offset that spans the combined storage required for an SVE
35/// vector and a 64bit GPR.
36class StackOffset {
37 int64_t Bytes;
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000038 int64_t ScalableBytes;
Sander de Smalen612b0382019-08-06 13:06:40 +000039
40 explicit operator int() const;
41
42public:
43 using Part = std::pair<int64_t, MVT>;
44
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000045 StackOffset() : Bytes(0), ScalableBytes(0) {}
Sander de Smalen612b0382019-08-06 13:06:40 +000046
47 StackOffset(int64_t Offset, MVT::SimpleValueType T) : StackOffset() {
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000048 assert(MVT(T).getSizeInBits() % 8 == 0 &&
49 "Offset type is not a multiple of bytes");
Sander de Smalen612b0382019-08-06 13:06:40 +000050 *this += Part(Offset, T);
51 }
52
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000053 StackOffset(const StackOffset &Other)
54 : Bytes(Other.Bytes), ScalableBytes(Other.ScalableBytes) {}
Sander de Smalen612b0382019-08-06 13:06:40 +000055
56 StackOffset &operator=(const StackOffset &) = default;
57
58 StackOffset &operator+=(const StackOffset::Part &Other) {
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000059 int64_t OffsetInBytes = Other.first * (Other.second.getSizeInBits() / 8);
60 if (Other.second.isScalableVector())
61 ScalableBytes += OffsetInBytes;
62 else
63 Bytes += OffsetInBytes;
Sander de Smalen612b0382019-08-06 13:06:40 +000064 return *this;
65 }
66
67 StackOffset &operator+=(const StackOffset &Other) {
68 Bytes += Other.Bytes;
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000069 ScalableBytes += Other.ScalableBytes;
Sander de Smalen612b0382019-08-06 13:06:40 +000070 return *this;
71 }
72
73 StackOffset operator+(const StackOffset &Other) const {
74 StackOffset Res(*this);
75 Res += Other;
76 return Res;
77 }
78
79 StackOffset &operator-=(const StackOffset &Other) {
80 Bytes -= Other.Bytes;
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000081 ScalableBytes -= Other.ScalableBytes;
Sander de Smalen612b0382019-08-06 13:06:40 +000082 return *this;
83 }
84
85 StackOffset operator-(const StackOffset &Other) const {
86 StackOffset Res(*this);
87 Res -= Other;
88 return Res;
89 }
90
91 StackOffset operator-() const {
92 StackOffset Res = {};
93 const StackOffset Other(*this);
94 Res -= Other;
95 return Res;
96 }
97
Sander de Smalen4f99b6f2019-10-03 11:33:50 +000098 /// Returns the scalable part of the offset in bytes.
99 int64_t getScalableBytes() const { return ScalableBytes; }
100
Sander de Smalen612b0382019-08-06 13:06:40 +0000101 /// Returns the non-scalable part of the offset in bytes.
102 int64_t getBytes() const { return Bytes; }
103
104 /// Returns the offset in parts to which this frame offset can be
105 /// decomposed for the purpose of describing a frame offset.
106 /// For non-scalable offsets this is simply its byte size.
Sander de Smalen4f99b6f2019-10-03 11:33:50 +0000107 void getForFrameOffset(int64_t &NumBytes, int64_t &NumPredicateVectors,
108 int64_t &NumDataVectors) const {
109 assert(isValid() && "Invalid frame offset");
110
111 NumBytes = Bytes;
112 NumDataVectors = 0;
113 NumPredicateVectors = ScalableBytes / 2;
114 // This method is used to get the offsets to adjust the frame offset.
115 // If the function requires ADDPL to be used and needs more than two ADDPL
116 // instructions, part of the offset is folded into NumDataVectors so that it
117 // uses ADDVL for part of it, reducing the number of ADDPL instructions.
118 if (NumPredicateVectors % 8 == 0 || NumPredicateVectors < -64 ||
119 NumPredicateVectors > 62) {
120 NumDataVectors = NumPredicateVectors / 8;
121 NumPredicateVectors -= NumDataVectors * 8;
122 }
123 }
Sander de Smalen612b0382019-08-06 13:06:40 +0000124
125 /// Returns whether the offset is known zero.
Sander de Smalen4f99b6f2019-10-03 11:33:50 +0000126 explicit operator bool() const { return Bytes || ScalableBytes; }
127
128 bool isValid() const {
129 // The smallest scalable element supported by scaled SVE addressing
130 // modes are predicates, which are 2 scalable bytes in size. So the scalable
131 // byte offset must always be a multiple of 2.
132 return ScalableBytes % 2 == 0;
133 }
Sander de Smalen612b0382019-08-06 13:06:40 +0000134};
135
136} // end namespace llvm
137
138#endif