gem5 v24.0.0.0
Loading...
Searching...
No Matches
aapcs32.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_AAPCS32_HH__
29#define __ARCH_ARM_AAPCS32_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 "mem/port_proxy.hh"
44#include "sim/full_system.hh"
45#include "sim/guest_abi.hh"
46#include "sim/proxy_ptr.hh"
47
48namespace gem5
49{
50
51class ThreadContext;
52
53struct Aapcs32
54{
55 struct State
56 {
57 bool stackUsed=false; // Whether anything has been put on the stack.
58
59 int ncrn=0; // Next general purpose register number.
60 Addr nsaa; // Next stacked argument address.
61
62 // The maximum allowed general purpose register number.
63 static const int MAX_CRN = 3;
64
66
67 explicit State(const ThreadContext *tc) :
68 nsaa(tc->getReg(ArmISA::int_reg::Spx))
69 {}
70 };
71};
72
73namespace guest_abi
74{
75
76/*
77 * Composite Types
78 */
79
80template <typename T, typename Enabled=void>
81struct IsAapcs32Composite : public std::false_type {};
82
83template <typename T>
84struct IsAapcs32Composite<T, typename std::enable_if_t<
85 (std::is_array_v<T> || std::is_class_v<T> || std::is_union_v<T>) &&
86 // VarArgs is technically a composite type, but it's not a normal argument.
87 !IsVarArgsV<T>
88 >> : public std::true_type
89{};
90
91template <typename T>
93
94// Homogeneous Aggregates
95// These *should* be any aggregate type which has only one type of member, but
96// we can't actually detect that or manipulate that with templates. Instead,
97// we approximate that by detecting only arrays with that property.
98
99template <typename T, std::size_t count, typename Enabled=void>
101
102template <typename T>
103struct IsAapcs32HomogeneousAggregate : public std::false_type {};
104
105template <typename E, size_t N>
106struct IsAapcs32HomogeneousAggregate<E[N]> : public std::true_type {};
107
108template <typename T>
111
113{
114 template <typename T>
115 static T
117 {
118 state.stackUsed = true;
119
120 // The alignment is the larger of 4 or the natural alignment of T.
121 size_t align = std::max<size_t>(4, alignof(T));
122 // Increase the size to the next multiple of 4.
123 size_t size = roundUp(sizeof(T), 4);
124
125 // Align the stack.
126 state.nsaa = roundUp(state.nsaa, align);
127
128 // Extract the value from it.
129 ConstVPtr<T> val(state.nsaa, tc);
130
131 // Move the nsaa past this argument.
132 state.nsaa += size;
133
134 // Return the value we extracted.
135 return gtoh(*val, ArmISA::byteOrder(tc));
136 }
137};
138
139
140/*
141 * Integer arguments and return values.
142 */
143
144template <typename Integer>
145struct Result<Aapcs32, Integer, typename std::enable_if_t<
146 std::is_integral_v<Integer> && (sizeof(Integer) < sizeof(uint32_t))>>
147{
148 static void
149 store(ThreadContext *tc, const Integer &i)
150 {
151 uint32_t val = std::is_signed_v<Integer> ?
154 }
155};
156
157template <typename Integer>
158struct Result<Aapcs32, Integer, typename std::enable_if_t<
159 std::is_integral_v<Integer> && (sizeof(Integer) == sizeof(uint32_t))>>
160{
161 static void
162 store(ThreadContext *tc, const Integer &i)
163 {
164 tc->setReg(ArmISA::int_reg::R0, (uint32_t)i);
165 }
166};
167
168template <typename Integer>
169struct Result<Aapcs32, Integer, typename std::enable_if_t<
170 std::is_integral_v<Integer> && (sizeof(Integer) == sizeof(uint64_t))>>
171{
172 static void
173 store(ThreadContext *tc, const Integer &i)
174 {
175 if (ArmISA::byteOrder(tc) == ByteOrder::little) {
176 tc->setReg(ArmISA::int_reg::R0, (uint32_t)(i >> 0));
177 tc->setReg(ArmISA::int_reg::R1, (uint32_t)(i >> 32));
178 } else {
179 tc->setReg(ArmISA::int_reg::R0, (uint32_t)(i >> 32));
180 tc->setReg(ArmISA::int_reg::R1, (uint32_t)(i >> 0));
181 }
182 }
183};
184
185template <typename Integer>
186struct Argument<Aapcs32, Integer, typename std::enable_if_t<
187 std::is_integral_v<Integer> && (sizeof(Integer) <= sizeof(uint32_t))
188 >> : public Aapcs32ArgumentBase
189{
190 static Integer
192 {
193 if (state.ncrn <= state.MAX_CRN) {
194 return tc->getReg(ArmISA::intRegClass[state.ncrn++]);
195 }
196
197 // Max out the ncrn since we effectively exhausted it.
198 state.ncrn = state.MAX_CRN + 1;
199
200 return loadFromStack<Integer>(tc, state);
201 }
202};
203
204template <typename Integer>
205struct Argument<Aapcs32, Integer, typename std::enable_if_t<
206 std::is_integral_v<Integer> && (sizeof(Integer) > sizeof(uint32_t))
207 >> : public Aapcs32ArgumentBase
208{
209 static Integer
211 {
212 if (alignof(Integer) == 8 && (state.ncrn % 2))
213 state.ncrn++;
214
215 if (sizeof(Integer) == sizeof(uint64_t) &&
216 state.ncrn + 1 <= state.MAX_CRN) {
217 Integer low, high;
218 if (ArmISA::byteOrder(tc) == ByteOrder::little) {
219 low = tc->getReg(ArmISA::intRegClass[state.ncrn++]) & mask(32);
220 high = tc->getReg(ArmISA::intRegClass[state.ncrn++]) &
221 mask(32);
222 } else {
223 high = tc->getReg(ArmISA::intRegClass[state.ncrn++]) &
224 mask(32);
225 low = tc->getReg(ArmISA::intRegClass[state.ncrn++]) & mask(32);
226 }
227 return low | (high << 32);
228 }
229
230 // Max out the ncrn since we effectively exhausted it.
231 state.ncrn = state.MAX_CRN + 1;
232
233 return loadFromStack<Integer>(tc, state);
234 }
235};
236
237
238/*
239 * Floating point and Short-Vector arguments and return values.
240 */
241
242template <typename Float>
243struct Result<Aapcs32, Float, typename std::enable_if_t<
244 std::is_floating_point_v<Float>>>
245{
246 static void
248 {
249 auto i = floatToBits(f);
251 };
252};
253
254template <typename Float>
255struct Argument<Aapcs32, Float, typename std::enable_if_t<
256 std::is_floating_point_v<Float>>> : public Aapcs32ArgumentBase
257{
258 static Float
260 {
261 if (sizeof(Float) == sizeof(uint32_t)) {
262 return bitsToFloat32(
264 } else {
265 return bitsToFloat64(
267 }
268 }
269};
270
271
272/*
273 * Composite arguments and return values.
274 */
275
276template <typename Composite>
277struct Result<Aapcs32, Composite, typename std::enable_if_t<
278 IsAapcs32CompositeV<Composite>>>
279{
280 static void
281 store(ThreadContext *tc, const Composite &composite,
283 {
284 if (sizeof(Composite) <= sizeof(uint32_t)) {
285 Composite cp = htog(composite, ArmISA::byteOrder(tc));
286 uint32_t val;
287 memcpy((void *)&val, (void *)&cp, sizeof(Composite));
290 } else {
291 VPtr<Composite> cp(state.retAddr, tc);
292 *cp = htog(composite, ArmISA::byteOrder(tc));
293 }
294 }
295
296 static void
298 {
299 if (sizeof(Composite) > sizeof(uint32_t))
300 state.retAddr = tc->getReg(ArmISA::intRegClass[state.ncrn++]);
301 }
302};
303
304template <typename Composite>
305struct Argument<Aapcs32, Composite, typename std::enable_if_t<
306 IsAapcs32CompositeV<Composite>>> :
308{
309 static Composite
311 {
312 size_t bytes = sizeof(Composite);
313 using Chunk = uint32_t;
314
315 const int chunk_size = sizeof(Chunk);
316 const int regs = (bytes + chunk_size - 1) / chunk_size;
317
318 if (bytes <= chunk_size) {
319 if (state.ncrn++ <= state.MAX_CRN) {
320 alignas(alignof(Composite)) uint32_t val =
321 tc->getReg(ArmISA::intRegClass[state.ncrn++]);
323 return gtoh(*(Composite *)&val, ArmISA::byteOrder(tc));
324 }
325 }
326
327 if (alignof(Composite) == 8 && (state.ncrn % 2))
328 state.ncrn++;
329
330 if (state.ncrn + regs - 1 <= state.MAX_CRN) {
331 alignas(alignof(Composite)) uint8_t buf[bytes];
332 for (int i = 0; i < regs; i++) {
333 Chunk val = tc->getReg(ArmISA::intRegClass[state.ncrn++]);
335 size_t to_copy = std::min<size_t>(bytes, chunk_size);
336 memcpy(buf + i * chunk_size, &val, to_copy);
337 bytes -= to_copy;
338 }
339 return gtoh(*(Composite *)buf, ArmISA::byteOrder(tc));
340 }
341
342 if (!state.stackUsed && state.ncrn <= state.MAX_CRN) {
343 alignas(alignof(Composite)) uint8_t buf[bytes];
344
345 int offset = 0;
346 while (state.ncrn <= state.MAX_CRN) {
347 Chunk val = tc->getReg(ArmISA::intRegClass[state.ncrn++]);
349 size_t to_copy = std::min<size_t>(bytes, chunk_size);
350 memcpy(buf + offset, &val, to_copy);
351 offset += to_copy;
352 bytes -= to_copy;
353 }
354
355 if (bytes) {
356 TranslatingPortProxy fs_proxy(tc);
357 SETranslatingPortProxy se_proxy(tc);
358 PortProxy &virt_proxy = FullSystem ? fs_proxy : se_proxy;
359
360 virt_proxy.readBlob(
361 state.nsaa, buf, bytes);
362
363 state.stackUsed = true;
364 state.nsaa += roundUp(bytes, 4);
365 state.ncrn = state.MAX_CRN + 1;
366 }
367
368 return gtoh(*(Composite *)buf, ArmISA::byteOrder(tc));
369 }
370
371 state.ncrn = state.MAX_CRN + 1;
372
373 return loadFromStack<Composite>(tc, state);
374 }
375};
376
377} // namespace guest_abi
378
379
380/*
381 * VFP ABI variant.
382 */
383
384struct Aapcs32Vfp : public Aapcs32
385{
386 struct State : public Aapcs32::State
387 {
388 bool variadic=false; // Whether this function is variadic.
389
390 // Whether the various single and double precision registers have
391 // been allocated.
392 std::array<bool, 16> s;
393 std::array<bool, 8> d;
394
395 explicit State(const ThreadContext *tc) : Aapcs32::State(tc)
396 {
397 s.fill(false);
398 d.fill(false);
399 }
400
401 int
402 allocate(float, int count)
403 {
404 int last = 0;
405 for (int i = 0; i <= s.size() - count; i++) {
406 if (s[i]) {
407 last = i + 1;
408 continue;
409 }
410 if (i - last + 1 == count) {
411 for (int j = 0; j < count; j++) {
412 s[last + j] = true;
413 d[(last + j) / 2] = true;
414 }
415 return last;
416 }
417 }
418 s.fill(true);
419 d.fill(true);
420 return -1;
421 }
422
423 int
424 allocate(double, int count)
425 {
426 int last = 0;
427 for (int i = 0; i <= d.size() - count; i++) {
428 if (d[i]) {
429 last = i + 1;
430 continue;
431 }
432 if (i - last + 1 == count) {
433 for (int j = 0; j < count; j++) {
434 d[last + j] = true;
435 s[(last + j) * 2] = true;
436 s[(last + j) * 2 + 1] = true;
437 }
438 return last;
439 }
440 }
441 s.fill(true);
442 d.fill(true);
443 return -1;
444 }
445 };
446};
447
448namespace guest_abi
449{
450
451/*
452 * Integer arguments and return values.
453 */
454
455template <typename Integer>
456struct Result<Aapcs32Vfp, Integer, typename std::enable_if_t<
457 std::is_integral_v<Integer>>> : public Result<Aapcs32, Integer>
458{};
459
460template <typename Integer>
461struct Argument<Aapcs32Vfp, Integer, typename std::enable_if_t<
462 std::is_integral_v<Integer>>> : public Argument<Aapcs32, Integer>
463{};
464
465
466/*
467 * Floating point arguments and return values.
468 */
469
470template <typename Float>
471struct Result<Aapcs32Vfp, Float, typename std::enable_if_t<
472 std::is_floating_point_v<Float>>>
473{
474 static void
476 {
477 if (state.variadic) {
479 return;
480 }
481
482 auto bytes = floatToBits(f);
483 auto *vec_elems = static_cast<ArmISA::VecElem *>(&bytes);
484 constexpr int chunks = sizeof(Float) / sizeof(ArmISA::VecElem);
485 for (int chunk = 0; chunk < chunks; chunk++)
486 tc->setReg(ArmISA::vecElemClass[chunk], vec_elems[chunk]);
487 };
488};
489
490template <typename Float>
491struct Argument<Aapcs32Vfp, Float, typename std::enable_if_t<
492 std::is_floating_point_v<Float>>> : public Aapcs32ArgumentBase
493{
494 static Float
496 {
497 if (state.variadic)
499
500 const int index = state.allocate(Float{}, 1);
501
502 if (index < 0)
503 return loadFromStack<Float>(tc, state);
504
505 decltype(floatToBits(Float{})) result;
506 auto *vec_elems = static_cast<ArmISA::VecElem *>(&result);
507
508 constexpr int chunks = sizeof(Float) / sizeof(ArmISA::VecElem);
509 for (int chunk = 0; chunk < chunks; chunk++)
510 vec_elems[chunk] = tc->getReg(ArmISA::vecElemClass[chunk]);
511
512 return bitsToFloat(result);
513 }
514};
515
516
517/*
518 * Composite arguments and return values which are not Homogeneous Aggregates.
519 */
520
521template <typename Composite>
522struct Result<Aapcs32Vfp, Composite, typename std::enable_if_t<
523 IsAapcs32CompositeV<Composite> &&
524 !IsAapcs32HomogeneousAggregateV<Composite>>> :
525 public Result<Aapcs32, Composite>
526{};
527
528template <typename Composite>
529struct Argument<Aapcs32Vfp, Composite, typename std::enable_if_t<
530 IsAapcs32CompositeV<Composite> &&
531 !IsAapcs32HomogeneousAggregateV<Composite>>> :
532 public Argument<Aapcs32, Composite>
533{};
534
535
536/*
537 * Homogeneous Aggregate argument and return values.
538 */
539
540template <typename T>
541struct Aapcs32ArrayType { using Type = void; };
542
543template <typename E, size_t N>
544struct Aapcs32ArrayType<E[N]> { using Type = E; };
545
546template <typename HA>
547struct Argument<Aapcs32Vfp, HA, typename std::enable_if_t<
548 IsAapcs32HomogeneousAggregateV<HA>>> :
550{
551 static bool
553 {
554 using Elem = typename Aapcs32ArrayType<HA>::Type;
555 constexpr size_t Count = sizeof(HA) / sizeof(Elem);
556 return state.variadic || !std::is_floating_point_v<Elem> ||
557 Count > 4;
558 }
559
560 static HA
562 {
563 using Elem = typename Aapcs32ArrayType<HA>::Type;
564 constexpr size_t Count = sizeof(HA) / sizeof(Elem);
565
566 if (useBaseABI(state))
568
569 const int base = state.allocate(Elem{}, Count);
570 if (base >= 0) {
571 constexpr int lane_per_reg = 16 / sizeof(Elem);
572 HA ha;
573 for (int i = 0; i < Count; i++) {
574 const int index = base + i;
575 const int reg = index / lane_per_reg;
576 const int lane = index % lane_per_reg;
577
580 tc->getReg(id, &val);
581 ha[i] = val.as<Elem>()[lane];
582 }
583 return ha;
584 }
585
586 return loadFromStack<HA>(tc, state);
587 }
588
589 static void
591 {
592 if (useBaseABI(state))
594 }
595};
596
597template <typename HA>
599 typename std::enable_if_t<IsAapcs32HomogeneousAggregateV<HA>>>
600{
601 static bool
603 {
604 using Elem = typename Aapcs32ArrayType<HA>::Type;
605 constexpr size_t Count = sizeof(HA) / sizeof(Elem);
606 return state.variadic || !std::is_floating_point_v<Elem> ||
607 Count > 4;
608 }
609
610 static HA
612 {
613 using Elem = typename Aapcs32ArrayType<HA>::Type;
614 constexpr size_t Count = sizeof(HA) / sizeof(Elem);
615
616 if (useBaseABI(state)) {
618 return;
619 }
620
621 constexpr int lane_per_reg = 16 / sizeof(Elem);
622 for (int i = 0; i < Count; i++) {
623 const int reg = i / lane_per_reg;
624 const int lane = i % lane_per_reg;
625
628 tc->getReg(id, &val);
629 val.as<Elem>()[lane] = ha[i];
630 tc->setReg(id, &val);
631 }
632 }
633
634 static void
636 {
637 if (useBaseABI(state))
639 }
640};
641
642
643/*
644 * Varargs
645 */
646
647template <typename ...Types>
648struct Argument<Aapcs32Vfp, VarArgs<Types...>>
649{
650 static VarArgs<Types...>
652 {
653 state.variadic = true;
654 return getArgument<Aapcs32, VarArgs<Types...>>(tc, state);
655 }
656};
657
658} // namespace guest_abi
659} // namespace gem5
660
661#endif // __ARCH_ARM_AAPCS32_HH__
This object is a proxy for a port or other object which implements the functional response protocol,...
Definition port_proxy.hh:87
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
Register ID: describe an architectural register with its class and index.
Definition reg_class.hh:94
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)
This proxy attempts to translate virtual addresses using the TLBs.
Vector Register Abstraction This generic class is the model in a particularization of MVC,...
Definition vec_reg.hh:126
static constexpr T roundUp(const T &val, const U &align)
This function is used to align addresses in memory.
Definition intmath.hh:260
constexpr uint64_t sext(uint64_t val)
Sign-extend an N-bit value to 64 bits.
Definition bitfield.hh:129
atomic_var_t state
Definition helpers.cc:211
constexpr RegId R1
Definition int.hh:187
constexpr RegId R0
Definition int.hh:186
ByteOrder byteOrder(const ThreadContext *tc)
Definition utility.hh:359
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
constexpr RegClass vecElemClass
Definition vec.hh:105
constexpr RegClass intRegClass
Definition int.hh:173
Bitfield< 6 > f
Definition misc_types.hh:68
Bitfield< 39 > ha
uint32_t VecElem
Definition vec.hh:63
constexpr RegClass vecRegClass
Definition vec.hh:101
Bitfield< 30, 0 > index
Bitfield< 5, 3 > reg
Definition types.hh:92
Bitfield< 31, 0 > E
Definition int.hh:56
Bitfield< 51, 12 > base
Definition pagetable.hh:141
Bitfield< 63 > val
Definition misc.hh:804
constexpr bool IsAapcs32CompositeV
Definition aapcs32.hh:92
constexpr bool IsAapcs32HomogeneousAggregateV
Definition aapcs32.hh:109
static void storeResult(ThreadContext *tc, const Ret &ret, typename ABI::State &state)
Definition layout.hh:163
T[count] Aapcs32HomogeneousAggregate
Definition aapcs32.hh:100
static Arg getArgument(ThreadContext *tc, typename ABI::State &state)
Definition layout.hh:170
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
static uint64_t floatToBits(double val)
Definition types.hh:202
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
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition root.cc:220
static double bitsToFloat(uint64_t val)
Definition types.hh:229
T htog(T value, ByteOrder guest_byte_order)
Definition byteswap.hh:187
static double bitsToFloat64(uint64_t val)
Definition types.hh:218
static float bitsToFloat32(uint32_t val)
Definition types.hh:206
Overload hash function for BasicBlockRange type.
Definition binary32.hh:81
PortProxy Object Declaration.
std::array< bool, 16 > s
Definition aapcs32.hh:392
State(const ThreadContext *tc)
Definition aapcs32.hh:395
int allocate(double, int count)
Definition aapcs32.hh:424
int allocate(float, int count)
Definition aapcs32.hh:402
std::array< bool, 8 > d
Definition aapcs32.hh:393
static const int MAX_CRN
Definition aapcs32.hh:63
State(const ThreadContext *tc)
Definition aapcs32.hh:67
static T loadFromStack(ThreadContext *tc, Aapcs32::State &state)
Definition aapcs32.hh:116
static VarArgs< Types... > get(ThreadContext *tc, typename Aapcs32Vfp::State &state)
Definition aapcs32.hh:651
static void store(ThreadContext *tc, const Float &f, Aapcs32Vfp::State &state)
Definition aapcs32.hh:475
static void store(ThreadContext *tc, const Composite &composite, Aapcs32::State &state)
Definition aapcs32.hh:281
static void store(ThreadContext *tc, const Float &f, Aapcs32::State &state)
Definition aapcs32.hh:247

Generated on Tue Jun 18 2024 16:23:55 for gem5 by doxygen 1.11.0