gem5  v20.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/intregs.hh"
37 #include "arch/arm/utility.hh"
38 #include "base/intmath.hh"
39 #include "cpu/thread_context.hh"
40 #include "sim/guest_abi.hh"
41 #include "sim/proxy_ptr.hh"
42 
43 class ThreadContext;
44 
45 struct Aapcs64
46 {
47  struct State
48  {
49  int ngrn=0; // Next general purpose register number.
50  int nsrn=0; // Next SIMD and floating point register number.
51  Addr nsaa; // Next stacked argument address.
52 
53  // The maximum allowed general purpose register number.
54  static const int MAX_GRN = 7;
55  // The maximum allowed SIMD and floating point register number.
56  static const int MAX_SRN = 7;
57 
58  explicit State(const ThreadContext *tc) :
59  nsaa(tc->readIntReg(ArmISA::INTREG_SPX))
60  {}
61  };
62 };
63 
64 namespace GuestABI
65 {
66 
67 /*
68  * Short Vectors
69  */
70 
71 // A short vector is a machine type that is composed of repeated instances of
72 // one fundamental integral or floating- point type. It may be 8 or 16 bytes
73 // in total size.
74 
75 template <typename T, typename Enabled=void>
76 struct IsAapcs64ShortVector : public std::false_type {};
77 
78 template <typename E, size_t N>
80  typename std::enable_if<
81  (std::is_integral<E>::value || std::is_floating_point<E>::value) &&
82  (sizeof(E) * N == 8 || sizeof(E) * N == 16)>::type> :
83  public std::true_type
84 {};
85 
86 /*
87  * Composite Types
88  */
89 
90 template <typename T, typename Enabled=void>
91 struct IsAapcs64Composite : public std::false_type {};
92 
93 template <typename T>
94 struct IsAapcs64Composite<T, typename std::enable_if<
95  (std::is_array<T>::value ||
96  std::is_class<T>::value ||
97  std::is_union<T>::value) &&
98  // VarArgs is technically a composite type, but it's not a normal argument.
99  !IsVarArgs<T>::value &&
100  // Short vectors are also composite types, but don't treat them as one.
101  !IsAapcs64ShortVector<T>::value
102  >::type> : public std::true_type
103 {};
104 
105 // Homogeneous Aggregates
106 // These *should* be any aggregate type which has only one type of member, but
107 // we can't actually detect that or manipulate that with templates. Instead,
108 // we approximate that by detecting only arrays with that property.
109 
110 // An Homogeneous Floating-Point Aggregate (HFA) is an Homogeneous Aggregate
111 // with a Fundemental Data Type that is a Floating-Point type and at most four
112 // uniquely addressable members.
113 
114 template <typename T, typename Enabled=void>
115 struct IsAapcs64Hfa : public std::false_type {};
116 
117 template <typename E, size_t N>
118 struct IsAapcs64Hfa<E[N],
119  typename std::enable_if<std::is_floating_point<E>::value &&
120  N <= 4>::type> : public std::true_type
121 {};
122 
123 // An Homogeneous Short-Vector Aggregate (HVA) is an Homogeneous Aggregate with
124 // a Fundamental Data Type that is a Short-Vector type and at most four
125 // uniquely addressable members.
126 
127 template <typename T, typename Enabled=void>
128 struct IsAapcs64Hva : public std::false_type {};
129 
130 template <typename E, size_t N>
131 struct IsAapcs64Hva<E[N],
132  typename std::enable_if<IsAapcs64ShortVector<E>::value &&
133  N <= 4>::type> : public std::true_type
134 {};
135 
136 // A shorthand to test if a type is an HVA or an HFA.
137 template <typename T, typename Enabled=void>
138 struct IsAapcs64Hxa : public std::false_type {};
139 
140 template <typename T>
141 struct IsAapcs64Hxa<T, typename std::enable_if<
142  IsAapcs64Hfa<T>::value || IsAapcs64Hva<T>::value>::type> :
143  public std::true_type
144 {};
145 
146 struct Aapcs64ArgumentBase
147 {
148  template <typename T>
149  static T
150  loadFromStack(ThreadContext *tc, Aapcs64::State &state)
151  {
152  // The alignment is the larger of 8 or the natural alignment of T.
153  size_t align = std::max<size_t>(8, alignof(T));
154  // Increase the size to the next multiple of 8.
155  size_t size = roundUp(sizeof(T), 8);
156 
157  // Align the stack.
158  state.nsaa = roundUp(state.nsaa, align);
159 
160  // Extract the value from it.
161  ConstVPtr<T> val(state.nsaa, tc);
162 
163  // Move the nsaa past this argument.
164  state.nsaa += size;
165 
166  // Return the value we extracted.
167  return gtoh(*val, ArmISA::byteOrder(tc));
168  }
169 };
170 
171 
172 /*
173  * Floating point and Short-Vector arguments and return values.
174  */
175 
176 template <typename Float>
177 struct Argument<Aapcs64, Float, typename std::enable_if<
178  std::is_floating_point<Float>::value ||
179  IsAapcs64ShortVector<Float>::value>::type> :
180  public Aapcs64ArgumentBase
181 {
182  static Float
183  get(ThreadContext *tc, Aapcs64::State &state)
184  {
185  if (state.nsrn <= state.MAX_SRN) {
186  RegId id(VecRegClass, state.nsrn++);
187  return tc->readVecReg(id).laneView<Float, 0>();
188  }
189 
190  return loadFromStack<Float>(tc, state);
191  }
192 };
193 
194 template <typename Float>
195 struct Result<Aapcs64, Float, typename std::enable_if<
196  std::is_floating_point<Float>::value ||
197  IsAapcs64ShortVector<Float>::value>::type>
198 {
199  static void
200  store(ThreadContext *tc, const Float &f)
201  {
202  RegId id(VecRegClass, 0);
203  auto reg = tc->readVecReg(id);
204  reg.laneView<Float, 0>() = f;
205  tc->setVecReg(id, reg);
206  }
207 };
208 
209 
210 /*
211  * Integer arguments and return values.
212  */
213 
214 // This will pick up Addr as well, which should be used for guest pointers.
215 template <typename Integer>
216 struct Argument<Aapcs64, Integer, typename std::enable_if<
217  std::is_integral<Integer>::value && (sizeof(Integer) <= 8)
218  >::type> : public Aapcs64ArgumentBase
219 {
220  static Integer
222  {
223  if (state.ngrn <= state.MAX_GRN)
224  return tc->readIntReg(state.ngrn++);
225 
226  // Max out ngrn since we've effectively saturated it.
227  state.ngrn = state.MAX_GRN + 1;
228 
229  return loadFromStack<Integer>(tc, state);
230  }
231 };
232 
233 template <typename Integer>
234 struct Argument<Aapcs64, Integer, typename std::enable_if<
235  std::is_integral<Integer>::value && (sizeof(Integer) > 8)
236  >::type> : public Aapcs64ArgumentBase
237 {
238  static Integer
240  {
241  if (alignof(Integer) == 16 && (state.ngrn % 2))
242  state.ngrn++;
243 
244  if (sizeof(Integer) == 16 && state.ngrn + 1 <= state.MAX_GRN) {
245  Integer low = tc->readIntReg(state.ngrn++);
246  Integer high = tc->readIntReg(state.ngrn++);
247  high = high << 64;
248  return high | low;
249  }
250 
251  // Max out ngrn since we've effectively saturated it.
252  state.ngrn = state.MAX_GRN + 1;
253 
254  return loadFromStack<Integer>(tc, state);
255  }
256 };
257 
258 template <typename Integer>
259 struct Result<Aapcs64, Integer, typename std::enable_if<
260  std::is_integral<Integer>::value && (sizeof(Integer) <= 8)
261  >::type>
262 {
263  static void
264  store(ThreadContext *tc, const Integer &i)
265  {
266  tc->setIntReg(0, i);
267  }
268 };
269 
270 template <typename Integer>
271 struct Result<Aapcs64, Integer, typename std::enable_if<
272  std::is_integral<Integer>::value && (sizeof(Integer) > 8)
273  >::type>
274 {
275  static void
276  store(ThreadContext *tc, const Integer &i)
277  {
278  tc->setIntReg(0, (uint64_t)i);
279  tc->setIntReg(1, (uint64_t)(i >> 64));
280  }
281 };
282 
283 
284 /*
285  * Homogeneous Floating-Point and Short-Vector Aggregates (HFAs and HVAs)
286  * argument and return values.
287  */
288 
289 template <typename T>
290 struct Aapcs64ArrayType { using Type = void; };
291 
292 template <typename E, size_t N>
293 struct Aapcs64ArrayType<E[N]> { using Type = E; };
294 
295 template <typename HA>
296 struct Argument<Aapcs64, HA, typename std::enable_if<
297  IsAapcs64Hxa<HA>::value>::type> : public Aapcs64ArgumentBase
298 {
299  static HA
301  {
302  using Elem = typename Aapcs64ArrayType<HA>::Type;
303  constexpr size_t Count = sizeof(HA) / sizeof(Elem);
304 
305  if (state.nsrn + Count - 1 <= state.MAX_SRN) {
306  HA ha;
307  for (int i = 0; i < Count; i++)
308  ha[i] = Argument<Aapcs64, Elem>::get(tc, state);
309  return ha;
310  }
311 
312  // Max out the nsrn since we effectively exhausted it.
313  state.nsrn = state.MAX_SRN + 1;
314 
315  return loadFromStack<HA>(tc, state);
316  }
317 };
318 
319 template <typename HA>
320 struct Result<Aapcs64, HA,
321  typename std::enable_if<IsAapcs64Hxa<HA>::value>::type>
322 {
323  static HA
324  store(ThreadContext *tc, const HA &ha)
325  {
326  using Elem = typename Aapcs64ArrayType<HA>::Type;
327  constexpr size_t Count = sizeof(HA) / sizeof(Elem);
328 
329  for (int i = 0; i < Count; i++)
331  }
332 };
333 
334 
335 /*
336  * Composite arguments and return values which are not HVAs or HFAs.
337  */
338 
339 template <typename Composite>
340 struct Argument<Aapcs64, Composite, typename std::enable_if<
341  IsAapcs64Composite<Composite>::value && !IsAapcs64Hxa<Composite>::value
342  >::type> : public Aapcs64ArgumentBase
343 {
344  static Composite
346  {
347  if (sizeof(Composite) > 16) {
348  // Composite values larger than 16 which aren't HFAs or HVAs are
349  // kept in a buffer, and the argument is actually a pointer to that
350  // buffer.
352  ConstVPtr<Composite> composite(addr, tc);
353  return gtoh(*composite, ArmISA::byteOrder(tc));
354  }
355 
356  // The size of Composite must be 16 bytes or less after this point.
357 
358  size_t bytes = sizeof(Composite);
359  using Chunk = uint64_t;
360 
361  const int chunk_size = sizeof(Chunk);
362  const int regs = (bytes + chunk_size - 1) / chunk_size;
363 
364  // Can it fit in GPRs?
365  if (state.ngrn + regs - 1 <= state.MAX_GRN) {
366  alignas(alignof(Composite)) uint8_t buf[bytes];
367  for (int i = 0; i < regs; i++) {
368  Chunk val = tc->readIntReg(state.ngrn++);
369  val = htog(val, ArmISA::byteOrder(tc));
370  size_t to_copy = std::min<size_t>(bytes, chunk_size);
371  memcpy(buf + i * chunk_size, &val, to_copy);
372  bytes -= to_copy;
373  }
374  return gtoh(*(Composite *)buf, ArmISA::byteOrder(tc));
375  }
376 
377  // Max out the ngrn since we effectively exhausted it.
378  state.ngrn = state.MAX_GRN;
379 
380  return loadFromStack<Composite>(tc, state);
381  }
382 };
383 
384 template <typename Composite>
385 struct Result<Aapcs64, Composite, typename std::enable_if<
386  IsAapcs64Composite<Composite>::value && !IsAapcs64Hxa<Composite>::value
387  >::type>
388 {
389  static void
390  store(ThreadContext *tc, const Composite &c)
391  {
392  if (sizeof(Composite) > 16) {
394  VPtr<Composite> composite(addr, tc);
395  *composite = htog(c, ArmISA::byteOrder(tc));
396  return;
397  }
398 
399  // The size of Composite must be 16 bytes or less after this point.
400 
401  size_t bytes = sizeof(Composite);
402  using Chunk = uint64_t;
403 
404  const int chunk_size = sizeof(Chunk);
405  const int regs = (bytes + chunk_size - 1) / chunk_size;
406 
407  Composite cp = htog(c, ArmISA::byteOrder(tc));
408  uint8_t *buf = (uint8_t *)&cp;
409  for (int i = 0; i < regs; i++) {
410  size_t to_copy = std::min<size_t>(bytes, chunk_size);
411 
412  Chunk val;
413  memcpy(&val, buf, to_copy);
414  val = gtoh(val, ArmISA::byteOrder(tc));
415 
416  tc->setIntReg(i, val);
417 
418  bytes -= to_copy;
419  buf += to_copy;
420  }
421  }
422 };
423 
424 } // namespace GuestABI
425 
426 #endif // __ARCH_ARM_AAPCS64_HH__
GuestABI::Result< Aapcs64, HA, typename std::enable_if< IsAapcs64Hxa< HA >::value >::type >::store
static HA store(ThreadContext *tc, const HA &ha)
Definition: aapcs64.hh:324
GuestABI::IsAapcs64Composite
Definition: aapcs64.hh:91
ArmISA::byteOrder
ByteOrder byteOrder(const ThreadContext *tc)
Definition: utility.hh:449
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
ConstProxyPtr
Definition: proxy_ptr.hh:106
GuestABI::Argument< Aapcs64, HA, typename std::enable_if< IsAapcs64Hxa< HA >::value >::type >::get
static HA get(ThreadContext *tc, Aapcs64::State &state)
Definition: aapcs64.hh:300
ProxyPtr
Definition: proxy_ptr.hh:236
ThreadContext::setVecReg
virtual void setVecReg(const RegId &reg, const VecRegContainer &val)=0
type
uint8_t type
Definition: inet.hh:421
ThreadContext::setIntReg
virtual void setIntReg(RegIndex reg_idx, RegVal val)=0
GuestABI::Argument::type >::get
static Integer get(ThreadContext *tc, Aapcs64::State &state)
Definition: aapcs64.hh:239
GuestABI::enable_if< std::is_integral< Integer >::value &&(sizeof(Integer)<=8) >::type >::get
static Integer get(ThreadContext *tc, Aapcs64::State &state)
Definition: aapcs64.hh:221
X86ISA::E
Bitfield< 31, 0 > E
Definition: int.hh:51
GuestABI::enable_if< std::is_integral< Integer >::value &&(sizeof(Integer)<=8) >::type >::store
static void store(ThreadContext *tc, const Integer &i)
Definition: aapcs64.hh:264
GuestABI::Aapcs64ArrayType
Definition: aapcs64.hh:290
proxy_ptr.hh
GuestABI::Aapcs64ArrayType::Type
void Type
Definition: aapcs64.hh:290
ArmISA
Definition: ccregs.hh:41
X86ISA::reg
Bitfield< 5, 3 > reg
Definition: types.hh:87
GuestABI::IsAapcs64ShortVector
Definition: aapcs64.hh:76
sc_dt::align
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:2083
RegId
Register ID: describe an architectural register with its class and index.
Definition: reg_class.hh:75
VecRegContainer::laneView
VecLaneT< VecElem, false > laneView()
View as the Nth lane of type VecElem.
Definition: vec_reg.hh:596
ArmISA::INTREG_SPX
@ INTREG_SPX
Definition: intregs.hh:160
cp
Definition: cprintf.cc:40
GuestABI::Result< Aapcs64, Composite, typename std::enable_if< IsAapcs64Composite< Composite >::value &&!IsAapcs64Hxa< Composite >::value >::type >::store
static void store(ThreadContext *tc, const Composite &c)
Definition: aapcs64.hh:390
ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:88
GuestABI::Argument< Aapcs64, Composite, typename std::enable_if< IsAapcs64Composite< Composite >::value &&!IsAapcs64Hxa< Composite >::value >::type >::get
static Composite get(ThreadContext *tc, Aapcs64::State &state)
Definition: aapcs64.hh:345
GuestABI
Definition: aapcs32.hh:66
Aapcs64
Definition: aapcs64.hh:45
htog
T htog(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:155
GuestABI::Argument
Definition: definition.hh:93
ThreadContext::readVecReg
virtual const VecRegContainer & readVecReg(const RegId &reg) const =0
intregs.hh
Aapcs64::State::nsrn
int nsrn
Definition: aapcs64.hh:50
X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:769
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
Aapcs64::State::State
State(const ThreadContext *tc)
Definition: aapcs64.hh:58
Aapcs64::State::MAX_SRN
static const int MAX_SRN
Definition: aapcs64.hh:56
utility.hh
GuestABI::Result::type >::store
static void store(ThreadContext *tc, const Integer &i)
Definition: aapcs64.hh:276
Stats::Result
double Result
All results are doubles.
Definition: types.hh:50
Aapcs64::State::ngrn
int ngrn
Definition: aapcs64.hh:49
VecRegClass
@ VecRegClass
Vector Register.
Definition: reg_class.hh:56
ArmISA::ha
Bitfield< 39 > ha
Definition: miscregs_types.hh:538
GuestABI::Result
Definition: definition.hh:58
Aapcs64::State::nsaa
Addr nsaa
Definition: aapcs64.hh:51
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
roundUp
T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition: intmath.hh:131
guest_abi.hh
addr
ip6_addr_t addr
Definition: inet.hh:423
ArmISA::INTREG_X8
@ INTREG_X8
Definition: intregs.hh:135
Aapcs64::State::MAX_GRN
static const int MAX_GRN
Definition: aapcs64.hh:54
ArmISA::c
Bitfield< 29 > c
Definition: miscregs_types.hh:50
gtoh
T gtoh(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:162
Aapcs64::State
Definition: aapcs64.hh:47
intmath.hh
ThreadContext::readIntReg
virtual RegVal readIntReg(RegIndex reg_idx) const =0
GuestABI::IsAapcs64Hfa
Definition: aapcs64.hh:115
thread_context.hh
GuestABI::Aapcs64ArrayType< E[N]>::Type
E Type
Definition: aapcs64.hh:293
ArmISA::id
Bitfield< 33 > id
Definition: miscregs_types.hh:247
ArmISA::f
Bitfield< 6 > f
Definition: miscregs_types.hh:64

Generated on Wed Sep 30 2020 14:01:58 for gem5 by doxygen 1.8.17