1 //==--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 #include "llvm/Support/TypeSize.h" 19 20 namespace llvm { 21 22 /// StackOffset is a wrapper around scalable and non-scalable offsets and is 23 /// used in several functions such as 'isAArch64FrameOffsetLegal' and 24 /// 'emitFrameOffset()'. StackOffsets are described by MVTs, e.g. 25 // 26 /// StackOffset(1, MVT::nxv16i8) 27 // 28 /// would describe an offset as being the size of a single SVE vector. 29 /// 30 /// The class also implements simple arithmetic (addition/subtraction) on these 31 /// offsets, e.g. 32 // 33 /// StackOffset(1, MVT::nxv16i8) + StackOffset(1, MVT::i64) 34 // 35 /// describes an offset that spans the combined storage required for an SVE 36 /// vector and a 64bit GPR. 37 class StackOffset { 38 int64_t Bytes; 39 int64_t ScalableBytes; 40 41 explicit operator int() const; 42 43 public: 44 using Part = std::pair<int64_t, MVT>; 45 StackOffset()46 StackOffset() : Bytes(0), ScalableBytes(0) {} 47 StackOffset(int64_t Offset,MVT::SimpleValueType T)48 StackOffset(int64_t Offset, MVT::SimpleValueType T) : StackOffset() { 49 assert(MVT(T).isByteSized() && "Offset type is not a multiple of bytes"); 50 *this += Part(Offset, T); 51 } 52 StackOffset(const StackOffset & Other)53 StackOffset(const StackOffset &Other) 54 : Bytes(Other.Bytes), ScalableBytes(Other.ScalableBytes) {} 55 56 StackOffset &operator=(const StackOffset &) = default; 57 58 StackOffset &operator+=(const StackOffset::Part &Other) { 59 const TypeSize Size = Other.second.getSizeInBits(); 60 if (Size.isScalable()) 61 ScalableBytes += Other.first * ((int64_t)Size.getKnownMinSize() / 8); 62 else 63 Bytes += Other.first * ((int64_t)Size.getFixedSize() / 8); 64 return *this; 65 } 66 67 StackOffset &operator+=(const StackOffset &Other) { 68 Bytes += Other.Bytes; 69 ScalableBytes += Other.ScalableBytes; 70 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; 81 ScalableBytes -= Other.ScalableBytes; 82 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 98 /// Returns the scalable part of the offset in bytes. getScalableBytes()99 int64_t getScalableBytes() const { return ScalableBytes; } 100 101 /// Returns the non-scalable part of the offset in bytes. getBytes()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. getForFrameOffset(int64_t & NumBytes,int64_t & NumPredicateVectors,int64_t & NumDataVectors)107 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 } 124 125 /// Returns whether the offset is known zero. 126 explicit operator bool() const { return Bytes || ScalableBytes; } 127 isValid()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 } 134 }; 135 136 } // end namespace llvm 137 138 #endif 139