AArch64StackOffset.h revision 360784
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 20namespace 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. 37class StackOffset { 38 int64_t Bytes; 39 int64_t ScalableBytes; 40 41 explicit operator int() const; 42 43public: 44 using Part = std::pair<int64_t, MVT>; 45 46 StackOffset() : Bytes(0), ScalableBytes(0) {} 47 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 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. 99 int64_t getScalableBytes() const { return ScalableBytes; } 100 101 /// 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. 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 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