"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/druntime/src/core/internal/vararg/aarch64.d" (20 Nov 2020, 5813 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * Varargs implementation for the AArch64 Procedure Call Standard (not followed by Apple).
    3  * Used by core.stdc.stdarg and core.vararg.
    4  *
    5  * Reference: https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#appendix-variable-argument-lists
    6  *
    7  * Copyright: Copyright Digital Mars 2020 - 2020.
    8  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
    9  * Authors:   Martin Kinkelin
   10  * Source: $(DRUNTIMESRC core/internal/vararg/aarch64.d)
   11  */
   12 
   13 module core.internal.vararg.aarch64;
   14 
   15 version (AArch64):
   16 
   17 // Darwin uses a simpler varargs implementation
   18 version (OSX) {}
   19 else version (iOS) {}
   20 else version (TVOS) {}
   21 else version (WatchOS) {}
   22 else:
   23 
   24 import core.stdc.stdarg : alignUp;
   25 
   26 @system:
   27 //@nogc:    // Not yet, need to make TypeInfo's member functions @nogc first
   28 nothrow:
   29 
   30 extern (C++, std) struct __va_list
   31 {
   32     void* __stack;
   33     void* __gr_top;
   34     void* __vr_top;
   35     int __gr_offs;
   36     int __vr_offs;
   37 }
   38 
   39 ///
   40 alias va_list = __va_list;
   41 
   42 ///
   43 T va_arg(T)(ref va_list ap)
   44 {
   45     static if (is(T ArgTypes == __argTypes))
   46     {
   47         T onStack()
   48         {
   49             void* arg = ap.__stack;
   50             static if (T.alignof > 8)
   51                 arg = arg.alignUp!16;
   52             ap.__stack = alignUp(arg + T.sizeof);
   53             version (BigEndian)
   54                 static if (T.sizeof < 8)
   55                     arg += 8 - T.sizeof;
   56             return *cast(T*) arg;
   57         }
   58 
   59         static if (ArgTypes.length == 0)
   60         {
   61             // indirectly by value; get pointer and copy
   62             T* ptr = va_arg!(T*)(ap);
   63             return *ptr;
   64         }
   65 
   66         static assert(ArgTypes.length == 1);
   67 
   68         static if (is(ArgTypes[0] E : E[N], int N))
   69             alias FundamentalType = E; // static array element type
   70         else
   71             alias FundamentalType = ArgTypes[0];
   72 
   73         static if (__traits(isFloating, FundamentalType) || is(FundamentalType == __vector))
   74         {
   75             import core.stdc.string : memcpy;
   76 
   77             // SIMD register(s)
   78             int offs = ap.__vr_offs;
   79             if (offs >= 0)
   80                 return onStack();           // reg save area empty
   81             enum int usedRegSize = FundamentalType.sizeof;
   82             static assert(T.sizeof % usedRegSize == 0);
   83             enum int nreg = T.sizeof / usedRegSize;
   84             ap.__vr_offs = offs + (nreg * 16);
   85             if (ap.__vr_offs > 0)
   86                 return onStack();           // overflowed reg save area
   87             version (BigEndian)
   88                 static if (usedRegSize < 16)
   89                     offs += 16 - usedRegSize;
   90 
   91             T result = void;
   92             static foreach (i; 0 .. nreg)
   93                 memcpy((cast(void*) &result) + i * usedRegSize, ap.__vr_top + (offs + i * 16), usedRegSize);
   94             return result;
   95         }
   96         else
   97         {
   98             // GP register(s)
   99             int offs = ap.__gr_offs;
  100             if (offs >= 0)
  101                 return onStack();           // reg save area empty
  102             static if (T.alignof > 8)
  103                 offs = offs.alignUp!16;
  104             enum int nreg = (T.sizeof + 7) / 8;
  105             ap.__gr_offs = offs + (nreg * 8);
  106             if (ap.__gr_offs > 0)
  107                 return onStack();           // overflowed reg save area
  108             version (BigEndian)
  109                 static if (T.sizeof < 8)
  110                     offs += 8 - T.sizeof;
  111             return *cast(T*) (ap.__gr_top + offs);
  112         }
  113     }
  114     else
  115     {
  116         static assert(false, "not a valid argument type for va_arg");
  117     }
  118 }
  119 
  120 ///
  121 void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
  122 {
  123     import core.stdc.string : memcpy;
  124 
  125     const size = ti.tsize;
  126     const alignment = ti.talign;
  127 
  128     if (auto ti_struct = cast(TypeInfo_Struct) ti)
  129     {
  130         TypeInfo arg1, arg2;
  131         ti.argTypes(arg1, arg2);
  132 
  133         if (!arg1)
  134         {
  135             // indirectly by value; get pointer and move
  136             void* ptr = va_arg!(void*)(ap);
  137             memcpy(parmn, ptr, size);
  138             return;
  139         }
  140 
  141         assert(!arg2);
  142         ti = arg1;
  143     }
  144 
  145     void onStack()
  146     {
  147         void* arg = ap.__stack;
  148         if (alignment > 8)
  149             arg = arg.alignUp!16;
  150         ap.__stack = alignUp(arg + size);
  151         version (BigEndian)
  152             if (size < 8)
  153                 arg += 8 - size;
  154         memcpy(parmn, arg, size);
  155     }
  156 
  157     // HFVA structs have already been lowered to static arrays;
  158     // lower `ti` further to the fundamental type, including HFVA
  159     // static arrays.
  160     // TODO: complex numbers
  161     if (auto ti_sarray = cast(TypeInfo_StaticArray) ti)
  162         ti = ti_sarray.value;
  163 
  164     if (ti.flags() & 2)
  165     {
  166         // SIMD register(s)
  167         int offs = ap.__vr_offs;
  168         if (offs >= 0)
  169             return onStack();           // reg save area empty
  170         const usedRegSize = cast(int) ti.tsize;
  171         assert(size % usedRegSize == 0);
  172         const nreg = cast(int) (size / usedRegSize);
  173         ap.__vr_offs = offs + (nreg * 16);
  174         if (ap.__vr_offs > 0)
  175             return onStack();           // overflowed reg save area
  176         version (BigEndian)
  177             if (usedRegSize < 16)
  178                 offs += 16 - usedRegSize;
  179         foreach (i; 0 .. nreg)
  180             memcpy(parmn + i * usedRegSize, ap.__vr_top + (offs + i * 16), usedRegSize);
  181 
  182         return;
  183     }
  184 
  185     // GP register(s)
  186     int offs = ap.__gr_offs;
  187     if (offs >= 0)
  188         return onStack();           // reg save area empty
  189     if (alignment > 8)
  190         offs = offs.alignUp!16;
  191     const nreg = cast(int) ((size + 7) / 8);
  192     ap.__gr_offs = offs + (nreg * 8);
  193     if (ap.__gr_offs > 0)
  194         return onStack();           // overflowed reg save area
  195     version (BigEndian)
  196         if (size < 8)
  197             offs += 8 - size;
  198     memcpy(parmn, ap.__gr_top + offs, size);
  199 }