gem5  v22.1.0.0
aapcs64.hh
Go to the documentation of this file.
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef __ARCH_ARM_AAPCS64_HH__
29 #define __ARCH_ARM_AAPCS64_HH__
30 
31 #include <algorithm>
32 #include <array>
33 #include <type_traits>
34 #include <utility>
35 
36 #include "arch/arm/regs/int.hh"
37 #include "arch/arm/regs/vec.hh"
38 #include "arch/arm/utility.hh"
39 #include "base/intmath.hh"
40 #include "cpu/thread_context.hh"
41 #include "sim/guest_abi.hh"
42 #include "sim/proxy_ptr.hh"
43 
44 namespace gem5
45 {
46 
47 class ThreadContext;
48 
49 struct Aapcs64
50 {
51  using UintPtr = uint64_t;
52 
53  struct State
54  {
55  int ngrn=0; // Next general purpose register number.
56  int nsrn=0; // Next SIMD and floating point register number.
57  Addr nsaa; // Next stacked argument address.
58 
59  // The maximum allowed general purpose register number.
60  static const int MAX_GRN = 7;
61  // The maximum allowed SIMD and floating point register number.
62  static const int MAX_SRN = 7;
63 
64  explicit State(const ThreadContext *tc) :
65  nsaa(tc->getReg(ArmISA::int_reg::Spx))
66  {}
67  };
68 };
69 
70 GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi);
71 namespace guest_abi
72 {
73 
74 /*
75  * Short Vectors
76  */
77 
78 // A short vector is a machine type that is composed of repeated instances of
79 // one fundamental integral or floating- point type. It may be 8 or 16 bytes
80 // in total size.
81 
82 template <typename T, typename Enabled=void>
83 struct IsAapcs64ShortVector : public std::false_type {};
84 
85 template <typename E, size_t N>
87  typename std::enable_if_t<
88  (std::is_integral_v<E> || std::is_floating_point_v<E>) &&
89  (sizeof(E) * N == 8 || sizeof(E) * N == 16)>> :
90  public std::true_type
91 {};
92 
93 template <typename T>
95 
96 /*
97  * Composite Types
98  */
99 
100 template <typename T, typename Enabled=void>
101 struct IsAapcs64Composite : public std::false_type {};
102 
103 template <typename T>
104 struct IsAapcs64Composite<T, typename std::enable_if_t<
105  (std::is_array_v<T> || std::is_class_v<T> || std::is_union_v<T>) &&
106  // VarArgs is technically a composite type, but it's not a normal argument.
107  !IsVarArgsV<T> &&
108  // Short vectors are also composite types, but don't treat them as one.
109  !IsAapcs64ShortVectorV<T>
110  >> : public std::true_type
111 {};
112 
113 template <typename T>
115 
116 // Homogeneous Aggregates
117 // These *should* be any aggregate type which has only one type of member, but
118 // we can't actually detect that or manipulate that with templates. Instead,
119 // we approximate that by detecting only arrays with that property.
120 
121 // An Homogeneous Floating-Point Aggregate (HFA) is an Homogeneous Aggregate
122 // with a Fundemental Data Type that is a Floating-Point type and at most four
123 // uniquely addressable members.
124 
125 template <typename T, typename Enabled=void>
126 struct IsAapcs64Hfa : public std::false_type {};
127 
128 template <typename E, size_t N>
129 struct IsAapcs64Hfa<E[N],
130  typename std::enable_if_t<std::is_floating_point_v<E> && N <= 4>> :
131  public std::true_type
132 {};
133 
134 template <typename T>
135 constexpr bool IsAapcs64HfaV = IsAapcs64Hfa<T>::value;
136 
137 // An Homogeneous Short-Vector Aggregate (HVA) is an Homogeneous Aggregate with
138 // a Fundamental Data Type that is a Short-Vector type and at most four
139 // uniquely addressable members.
140 
141 template <typename T, typename Enabled=void>
142 struct IsAapcs64Hva : public std::false_type {};
143 
144 template <typename E, size_t N>
145 struct IsAapcs64Hva<E[N],
146  typename std::enable_if_t<IsAapcs64ShortVectorV<E> && N <= 4>> :
147  public std::true_type
148 {};
149 
150 template <typename T>
151 constexpr bool IsAapcs64HvaV = IsAapcs64Hva<T>::value;
152 
153 // A shorthand to test if a type is an HVA or an HFA.
154 template <typename T, typename Enabled=void>
155 struct IsAapcs64Hxa : public std::false_type {};
156 
157 template <typename T>
158 struct IsAapcs64Hxa<T, typename std::enable_if_t<
159  IsAapcs64HfaV<T> || IsAapcs64HvaV<T>>> :
160  public std::true_type
161 {};
162 
163 template <typename T>
164 constexpr bool IsAapcs64HxaV = IsAapcs64Hxa<T>::value;
165 
166 struct Aapcs64ArgumentBase
167 {
168  template <typename T>
169  static T
170  loadFromStack(ThreadContext *tc, Aapcs64::State &state)
171  {
172  // The alignment is the larger of 8 or the natural alignment of T.
173  size_t align = std::max<size_t>(8, alignof(T));
174  // Increase the size to the next multiple of 8.
175  size_t size = roundUp(sizeof(T), 8);
176 
177  // Align the stack.
178  state.nsaa = roundUp(state.nsaa, align);
179 
180  // Extract the value from it.
181  ConstVPtr<T> val(state.nsaa, tc);
182 
183  // Move the nsaa past this argument.
184  state.nsaa += size;
185 
186  // Return the value we extracted.
187  return gtoh(*val, ArmISA::byteOrder(tc));
188  }
189 };
190 
191 
192 /*
193  * Floating point and Short-Vector arguments and return values.
194  */
195 
196 template <typename Float>
197 struct Argument<Aapcs64, Float, typename std::enable_if_t<
198  std::is_floating_point_v<Float> || IsAapcs64ShortVectorV<Float>>> :
199  public Aapcs64ArgumentBase
200 {
201  static Float
202  get(ThreadContext *tc, Aapcs64::State &state)
203  {
204  if (state.nsrn <= state.MAX_SRN) {
205  RegId id = ArmISA::vecRegClass[state.nsrn++];
207  tc->getReg(id, &vc);
208  return vc.as<Float>()[0];
209  }
210 
211  return loadFromStack<Float>(tc, state);
212  }
213 };
214 
215 template <typename Float>
216 struct Result<Aapcs64, Float, typename std::enable_if_t<
217  std::is_floating_point_v<Float> || IsAapcs64ShortVectorV<Float>>>
218 {
219  static void
220  store(ThreadContext *tc, const Float &f)
221  {
222  RegId id = ArmISA::vecRegClass[0];
224  tc->getReg(id, &reg);
225  reg.as<Float>()[0] = f;
226  tc->setReg(id, &reg);
227  }
228 };
229 
230 
231 /*
232  * Integer arguments and return values.
233  */
234 
235 // This will pick up Addr as well, which should be used for guest pointers.
236 template <typename Integer>
237 struct Argument<Aapcs64, Integer, typename std::enable_if_t<
238  std::is_integral_v<Integer> && (sizeof(Integer) <= 8)>> :
239  public Aapcs64ArgumentBase
240 {
241  static Integer
243  {
244  if (state.ngrn <= state.MAX_GRN)
245  return tc->getReg(ArmISA::intRegClass[state.ngrn++]);
246 
247  // Max out ngrn since we've effectively saturated it.
248  state.ngrn = state.MAX_GRN + 1;
249 
250  return loadFromStack<Integer>(tc, state);
251  }
252 };
253 
254 template <typename Integer>
255 struct Argument<Aapcs64, Integer, typename std::enable_if_t<
256  std::is_integral_v<Integer> && (sizeof(Integer) > 8)>> :
257  public Aapcs64ArgumentBase
258 {
259  static Integer
261  {
262  if (alignof(Integer) == 16 && (state.ngrn % 2))
263  state.ngrn++;
264 
265  if (sizeof(Integer) == 16 && state.ngrn + 1 <= state.MAX_GRN) {
266  Integer low = tc->getReg(ArmISA::intRegClass[state.ngrn++]);
267  Integer high = tc->getReg(ArmISA::intRegClass[state.ngrn++]);
268  high = high << 64;
269  return high | low;
270  }
271 
272  // Max out ngrn since we've effectively saturated it.
273  state.ngrn = state.MAX_GRN + 1;
274 
275  return loadFromStack<Integer>(tc, state);
276  }
277 };
278 
279 template <typename Integer>
280 struct Result<Aapcs64, Integer, typename std::enable_if_t<
281  std::is_integral_v<Integer> && (sizeof(Integer) <= 8)>>
282 {
283  static void
284  store(ThreadContext *tc, const Integer &i)
285  {
287  }
288 };
289 
290 template <typename Integer>
291 struct Result<Aapcs64, Integer, typename std::enable_if_t<
292  std::is_integral_v<Integer> && (sizeof(Integer) > 8)>>
293 {
294  static void
295  store(ThreadContext *tc, const Integer &i)
296  {
297  tc->setReg(ArmISA::int_reg::X0, (uint64_t)i);
298  tc->setReg(ArmISA::int_reg::X1, (uint64_t)(i >> 64));
299  }
300 };
301 
302 
303 /*
304  * Homogeneous Floating-Point and Short-Vector Aggregates (HFAs and HVAs)
305  * argument and return values.
306  */
307 
308 template <typename T>
309 struct Aapcs64ArrayType { using Type = void; };
310 
311 template <typename E, size_t N>
312 struct Aapcs64ArrayType<E[N]> { using Type = E; };
313 
314 template <typename HA>
315 struct Argument<Aapcs64, HA, typename std::enable_if_t<
316  IsAapcs64HxaV<HA>>> : public Aapcs64ArgumentBase
317 {
318  static HA
320  {
321  using Elem = typename Aapcs64ArrayType<HA>::Type;
322  constexpr size_t Count = sizeof(HA) / sizeof(Elem);
323 
324  if (state.nsrn + Count - 1 <= state.MAX_SRN) {
325  HA ha;
326  for (int i = 0; i < Count; i++)
328  return ha;
329  }
330 
331  // Max out the nsrn since we effectively exhausted it.
332  state.nsrn = state.MAX_SRN + 1;
333 
334  return loadFromStack<HA>(tc, state);
335  }
336 };
337 
338 template <typename HA>
339 struct Result<Aapcs64, HA, typename std::enable_if_t<IsAapcs64HxaV<HA>>>
340 {
341  static HA
342  store(ThreadContext *tc, const HA &ha)
343  {
344  using Elem = typename Aapcs64ArrayType<HA>::Type;
345  constexpr size_t Count = sizeof(HA) / sizeof(Elem);
346 
347  for (int i = 0; i < Count; i++)
349  }
350 };
351 
352 
353 /*
354  * Composite arguments and return values which are not HVAs or HFAs.
355  */
356 
357 template <typename Composite>
358 struct Argument<Aapcs64, Composite, typename std::enable_if_t<
359  IsAapcs64CompositeV<Composite> && !IsAapcs64HxaV<Composite>>> :
360  public Aapcs64ArgumentBase
361 {
362  static Composite
364  {
365  if (sizeof(Composite) > 16) {
366  // Composite values larger than 16 which aren't HFAs or HVAs are
367  // kept in a buffer, and the argument is actually a pointer to that
368  // buffer.
370  ConstVPtr<Composite> composite(addr, tc);
371  return gtoh(*composite, ArmISA::byteOrder(tc));
372  }
373 
374  // The size of Composite must be 16 bytes or less after this point.
375 
376  size_t bytes = sizeof(Composite);
377  using Chunk = uint64_t;
378 
379  const int chunk_size = sizeof(Chunk);
380  const int regs = (bytes + chunk_size - 1) / chunk_size;
381 
382  // Can it fit in GPRs?
383  if (state.ngrn + regs - 1 <= state.MAX_GRN) {
384  alignas(alignof(Composite)) uint8_t buf[bytes];
385  for (int i = 0; i < regs; i++) {
386  Chunk val = tc->getReg(ArmISA::intRegClass[state.ngrn++]);
387  val = htog(val, ArmISA::byteOrder(tc));
388  size_t to_copy = std::min<size_t>(bytes, chunk_size);
389  memcpy(buf + i * chunk_size, &val, to_copy);
390  bytes -= to_copy;
391  }
392  return gtoh(*(Composite *)buf, ArmISA::byteOrder(tc));
393  }
394 
395  // Max out the ngrn since we effectively exhausted it.
396  state.ngrn = state.MAX_GRN;
397 
398  return loadFromStack<Composite>(tc, state);
399  }
400 };
401 
402 template <typename Composite>
403 struct Result<Aapcs64, Composite, typename std::enable_if_t<
404  IsAapcs64CompositeV<Composite> && !IsAapcs64HxaV<Composite>>>
405 {
406  static void
407  store(ThreadContext *tc, const Composite &c)
408  {
409  if (sizeof(Composite) > 16) {
411  VPtr<Composite> composite(addr, tc);
412  *composite = htog(c, ArmISA::byteOrder(tc));
413  return;
414  }
415 
416  // The size of Composite must be 16 bytes or less after this point.
417 
418  size_t bytes = sizeof(Composite);
419  using Chunk = uint64_t;
420 
421  const int chunk_size = sizeof(Chunk);
422  const int regs = (bytes + chunk_size - 1) / chunk_size;
423 
424  Composite cp = htog(c, ArmISA::byteOrder(tc));
425  uint8_t *buf = (uint8_t *)&cp;
426  for (int i = 0; i < regs; i++) {
427  size_t to_copy = std::min<size_t>(bytes, chunk_size);
428 
429  Chunk val;
430  memcpy(&val, buf, to_copy);
431  val = gtoh(val, ArmISA::byteOrder(tc));
432 
434 
435  bytes -= to_copy;
436  buf += to_copy;
437  }
438  }
439 };
440 
441 } // namespace guest_abi
442 } // namespace gem5
443 
444 #endif // __ARCH_ARM_AAPCS64_HH__
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal getReg(const RegId &reg) const
virtual void setReg(const RegId &reg, RegVal val)
static constexpr T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition: intmath.hh:260
atomic_var_t state
Definition: helpers.cc:188
constexpr RegId X0
Definition: int.hh:240
constexpr RegId X1
Definition: int.hh:241
static RegId x(unsigned index)
Definition: int.hh:445
constexpr RegId Spx
Definition: int.hh:238
constexpr RegId X8
Definition: int.hh:248
ByteOrder byteOrder(const ThreadContext *tc)
Definition: utility.hh:357
Bitfield< 7 > i
Definition: misc_types.hh:67
gem5::VecRegContainer< NumVecElemPerVecReg *sizeof(VecElem)> VecRegContainer
Definition: vec.hh:65
constexpr RegClass intRegClass
Definition: int.hh:173
Bitfield< 39 > ha
Definition: misc_types.hh:550
constexpr RegClass vecRegClass
Definition: vec.hh:101
Bitfield< 2 > c
Definition: pagetable.hh:63
Bitfield< 56 > f
Definition: pagetable.hh:53
Bitfield< 5, 3 > reg
Definition: types.hh:92
Bitfield< 31, 0 > E
Definition: int.hh:56
Bitfield< 63 > val
Definition: misc.hh:776
Bitfield< 3 > addr
Definition: types.hh:84
struct IsAapcs64Hfa< E[N], typename std::enable_if_t< std::is_floating_point_v< E > &&N<=4 > > :public std::true_type{};template< typename T >constexpr bool IsAapcs64HfaV=IsAapcs64Hfa< T >::value;template< typename T, typename Enabled=void >struct IsAapcs64Hva :public std::false_type {};template< typename E, size_t N >struct IsAapcs64Hva< E[N], typename std::enable_if_t< IsAapcs64ShortVectorV< E > &&N<=4 > > :public std::true_type{};template< typename T >constexpr bool IsAapcs64HvaV=IsAapcs64Hva< T >::value;template< typename T, typename Enabled=void >struct IsAapcs64Hxa :public std::false_type {};template< typename T >struct IsAapcs64Hxa< T, typename std::enable_if_t< IsAapcs64HfaV< T >||IsAapcs64HvaV< T > > > :public std::true_type{};template< typename T >constexpr bool IsAapcs64HxaV=IsAapcs64Hxa< T >::value;struct Aapcs64ArgumentBase{ template< typename T > static T loadFromStack(ThreadContext *tc, Aapcs64::State &state) { size_t align=std::max< size_t >(8, alignof(T));size_t size=roundUp(sizeof(T), 8);state.nsaa=roundUp(state.nsaa, align);ConstVPtr< T > val(state.nsaa, tc);state.nsaa+=size;return gtoh(*val, ArmISA::byteOrder(tc));}};template< typename Float >struct Argument< Aapcs64, Float, typename std::enable_if_t< std::is_floating_point_v< Float >||IsAapcs64ShortVectorV< Float > > > :public Aapcs64ArgumentBase{ static Float get(ThreadContext *tc, Aapcs64::State &state) { if(state.nsrn<=state.MAX_SRN) { RegId id=ArmISA::vecRegClass[state.nsrn++];ArmISA::VecRegContainer vc;tc->getReg(id, &vc);return vc.as< Float >()[0];} return loadFromStack< Float >(tc, state);}};template< typename Float >struct Result< Aapcs64, Float, typename std::enable_if_t< std::is_floating_point_v< Float >||IsAapcs64ShortVectorV< Float > > >{ static void store(ThreadContext *tc, const Float &f) { RegId id=ArmISA::vecRegClass[0];ArmISA::VecRegContainer reg;tc-> getReg(id, &reg)
constexpr bool IsAapcs64CompositeV
Definition: aapcs64.hh:114
constexpr bool IsAapcs64ShortVectorV
Definition: aapcs64.hh:94
double Result
All results are doubles.
Definition: types.hh:56
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
high
Definition: intmath.hh:176
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
T gtoh(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:194
T htog(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:187
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
void align(const scfx_rep &lhs, const scfx_rep &rhs, int &new_wp, int &len_mant, scfx_mant_ref &lhs_mant, scfx_mant_ref &rhs_mant)
Definition: scfx_rep.cc:2051
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2826
static const int MAX_GRN
Definition: aapcs64.hh:60
static const int MAX_SRN
Definition: aapcs64.hh:62
State(const ThreadContext *tc)
Definition: aapcs64.hh:64
uint64_t UintPtr
Definition: aapcs64.hh:51

Generated on Wed Dec 21 2022 10:22:24 for gem5 by doxygen 1.9.1