d: Merge update dmd 799066f49
Removes the implementation of __traits(argTypes), which only supported x86_64 targets. The only use of this trait is an unused va_arg() function, this has been removed as well. Reviewed-on: https://github.com/dlang/dmd/pull/11022 gcc/d/ChangeLog: 2020-04-13 Iain Buclaw <ibuclaw@gdcproject.org> * Make-lang.in (D_FRONTEND_OBJS): Remove d/argtypes.o. * d-target.cc (Target::toArgTypes): New function. libphobos/ChangeLog: 2020-04-13 Iain Buclaw <ibuclaw@gdcproject.org> * libdruntime/core/stdc/stdarg.d: Remove run-time va_list template.
This commit is contained in:
parent
af4c92573d
commit
a1ccbae63c
11 changed files with 28 additions and 764 deletions
|
@ -1,3 +1,8 @@
|
|||
2020-04-13 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
|
||||
* Make-lang.in (D_FRONTEND_OBJS): Remove d/argtypes.o.
|
||||
* d-target.cc (Target::toArgTypes): New function.
|
||||
|
||||
2020-04-10 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
|
||||
* d-spec.cc (LIBDRUNTIME): Remove.
|
||||
|
|
|
@ -59,7 +59,6 @@ D_FRONTEND_OBJS = \
|
|||
d/access.o \
|
||||
d/aliasthis.o \
|
||||
d/apply.o \
|
||||
d/argtypes.o \
|
||||
d/arrayop.o \
|
||||
d/attrib.o \
|
||||
d/blockexit.o \
|
||||
|
|
|
@ -410,3 +410,15 @@ Target::systemLinkage (void)
|
|||
{
|
||||
return LINKc;
|
||||
}
|
||||
|
||||
/* Generate a TypeTuple of the equivalent types used to determine if a
|
||||
function argument of the given type can be passed in registers.
|
||||
The results of this are highly platform dependent, and intended
|
||||
primarly for use in implementing va_arg() with RTTI. */
|
||||
|
||||
TypeTuple *
|
||||
Target::toArgTypes (Type *)
|
||||
{
|
||||
/* Not implemented, however this is not currently used anywhere. */
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
3e10e2dd29e583f1d94d84de5e4bd858e0303669
|
||||
799066f498aebcfa420df284cac1f204b1f953a8
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -1,484 +0,0 @@
|
|||
|
||||
/* Compiler implementation of the D programming language
|
||||
* Copyright (C) 2010-2019 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/D-Programming-Language/dmd/blob/master/src/argtypes.c
|
||||
*/
|
||||
|
||||
#include "root/dsystem.h"
|
||||
#include "root/checkedint.h"
|
||||
|
||||
#include "mars.h"
|
||||
#include "dsymbol.h"
|
||||
#include "mtype.h"
|
||||
#include "scope.h"
|
||||
#include "init.h"
|
||||
#include "expression.h"
|
||||
#include "attrib.h"
|
||||
#include "declaration.h"
|
||||
#include "template.h"
|
||||
#include "id.h"
|
||||
#include "enum.h"
|
||||
#include "import.h"
|
||||
#include "aggregate.h"
|
||||
#include "hdrgen.h"
|
||||
|
||||
/****************************************************
|
||||
* This breaks a type down into 'simpler' types that can be passed to a function
|
||||
* in registers, and returned in registers.
|
||||
* It's highly platform dependent.
|
||||
* Params:
|
||||
* t = type to break down
|
||||
* Returns:
|
||||
* tuple of types, each element can be passed in a register.
|
||||
* A tuple of zero length means the type cannot be passed/returned in registers.
|
||||
*/
|
||||
|
||||
TypeTuple *toArgTypes(Type *t)
|
||||
{
|
||||
class ToArgTypes : public Visitor
|
||||
{
|
||||
public:
|
||||
TypeTuple *result;
|
||||
|
||||
ToArgTypes()
|
||||
{
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
void visit(Type *)
|
||||
{
|
||||
// not valid for a parameter
|
||||
}
|
||||
|
||||
void visit(TypeError *)
|
||||
{
|
||||
result = new TypeTuple(Type::terror);
|
||||
}
|
||||
|
||||
void visit(TypeBasic *t)
|
||||
{
|
||||
Type *t1 = NULL;
|
||||
Type *t2 = NULL;
|
||||
switch (t->ty)
|
||||
{
|
||||
case Tvoid:
|
||||
return;
|
||||
|
||||
case Tbool:
|
||||
case Tint8:
|
||||
case Tuns8:
|
||||
case Tint16:
|
||||
case Tuns16:
|
||||
case Tint32:
|
||||
case Tuns32:
|
||||
case Tfloat32:
|
||||
case Tint64:
|
||||
case Tuns64:
|
||||
case Tint128:
|
||||
case Tuns128:
|
||||
case Tfloat64:
|
||||
case Tfloat80:
|
||||
t1 = t;
|
||||
break;
|
||||
|
||||
case Timaginary32:
|
||||
t1 = Type::tfloat32;
|
||||
break;
|
||||
|
||||
case Timaginary64:
|
||||
t1 = Type::tfloat64;
|
||||
break;
|
||||
|
||||
case Timaginary80:
|
||||
t1 = Type::tfloat80;
|
||||
break;
|
||||
|
||||
case Tcomplex32:
|
||||
if (global.params.is64bit)
|
||||
t1 = Type::tfloat64;
|
||||
else
|
||||
{
|
||||
t1 = Type::tfloat64;
|
||||
t2 = Type::tfloat64;
|
||||
}
|
||||
break;
|
||||
|
||||
case Tcomplex64:
|
||||
t1 = Type::tfloat64;
|
||||
t2 = Type::tfloat64;
|
||||
break;
|
||||
|
||||
case Tcomplex80:
|
||||
t1 = Type::tfloat80;
|
||||
t2 = Type::tfloat80;
|
||||
break;
|
||||
|
||||
case Tchar:
|
||||
t1 = Type::tuns8;
|
||||
break;
|
||||
|
||||
case Twchar:
|
||||
t1 = Type::tuns16;
|
||||
break;
|
||||
|
||||
case Tdchar:
|
||||
t1 = Type::tuns32;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (t1)
|
||||
{
|
||||
if (t2)
|
||||
result = new TypeTuple(t1, t2);
|
||||
else
|
||||
result = new TypeTuple(t1);
|
||||
}
|
||||
else
|
||||
result = new TypeTuple();
|
||||
}
|
||||
|
||||
void visit(TypeVector *t)
|
||||
{
|
||||
result = new TypeTuple(t);
|
||||
}
|
||||
|
||||
void visit(TypeSArray *t)
|
||||
{
|
||||
if (t->dim)
|
||||
{
|
||||
/* Should really be done as if it were a struct with dim members
|
||||
* of the array's elements.
|
||||
* I.e. int[2] should be done like struct S { int a; int b; }
|
||||
*/
|
||||
dinteger_t sz = t->dim->toInteger();
|
||||
// T[1] should be passed like T
|
||||
if (sz == 1)
|
||||
{
|
||||
t->next->accept(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = new TypeTuple(); // pass on the stack for efficiency
|
||||
}
|
||||
|
||||
void visit(TypeAArray *)
|
||||
{
|
||||
result = new TypeTuple(Type::tvoidptr);
|
||||
}
|
||||
|
||||
void visit(TypePointer *)
|
||||
{
|
||||
result = new TypeTuple(Type::tvoidptr);
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Convert a floating point type into the equivalent integral type.
|
||||
*/
|
||||
|
||||
static Type *mergeFloatToInt(Type *t)
|
||||
{
|
||||
switch (t->ty)
|
||||
{
|
||||
case Tfloat32:
|
||||
case Timaginary32:
|
||||
t = Type::tint32;
|
||||
break;
|
||||
case Tfloat64:
|
||||
case Timaginary64:
|
||||
case Tcomplex32:
|
||||
t = Type::tint64;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* This merges two types into an 8byte type.
|
||||
* Params:
|
||||
* t1 = first type (can be null)
|
||||
* t2 = second type (can be null)
|
||||
* offset2 = offset of t2 from start of t1
|
||||
* Returns:
|
||||
* type that encompasses both t1 and t2, null if cannot be done
|
||||
*/
|
||||
|
||||
static Type *argtypemerge(Type *t1, Type *t2, unsigned offset2)
|
||||
{
|
||||
//printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2);
|
||||
if (!t1)
|
||||
{ assert(!t2 || offset2 == 0);
|
||||
return t2;
|
||||
}
|
||||
if (!t2)
|
||||
return t1;
|
||||
|
||||
const d_uns64 sz1 = t1->size(Loc());
|
||||
const d_uns64 sz2 = t2->size(Loc());
|
||||
assert(sz1 != SIZE_INVALID && sz2 != SIZE_INVALID);
|
||||
|
||||
if (t1->ty != t2->ty &&
|
||||
(t1->ty == Tfloat80 || t2->ty == Tfloat80))
|
||||
return NULL;
|
||||
|
||||
// [float,float] => [cfloat]
|
||||
if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4)
|
||||
return Type::tfloat64;
|
||||
|
||||
// Merging floating and non-floating types produces the non-floating type
|
||||
if (t1->isfloating())
|
||||
{
|
||||
if (!t2->isfloating())
|
||||
t1 = mergeFloatToInt(t1);
|
||||
}
|
||||
else if (t2->isfloating())
|
||||
t2 = mergeFloatToInt(t2);
|
||||
|
||||
Type *t;
|
||||
|
||||
// Pick type with larger size
|
||||
if (sz1 < sz2)
|
||||
t = t2;
|
||||
else
|
||||
t = t1;
|
||||
|
||||
// If t2 does not lie within t1, need to increase the size of t to enclose both
|
||||
assert(sz2 < UINT64_MAX - UINT32_MAX);
|
||||
if (offset2 && sz1 < offset2 + sz2)
|
||||
{
|
||||
switch (offset2 + sz2)
|
||||
{
|
||||
case 2:
|
||||
t = Type::tint16;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
t = Type::tint32;
|
||||
break;
|
||||
default:
|
||||
t = Type::tint64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void visit(TypeDArray *)
|
||||
{
|
||||
/* Should be done as if it were:
|
||||
* struct S { size_t length; void* ptr; }
|
||||
*/
|
||||
if (global.params.is64bit && !global.params.isLP64)
|
||||
{
|
||||
// For AMD64 ILP32 ABI, D arrays fit into a single integer register.
|
||||
unsigned offset = (unsigned)Type::tsize_t->size(Loc());
|
||||
Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
|
||||
if (t)
|
||||
{
|
||||
result = new TypeTuple(t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = new TypeTuple(Type::tsize_t, Type::tvoidptr);
|
||||
}
|
||||
|
||||
void visit(TypeDelegate *)
|
||||
{
|
||||
/* Should be done as if it were:
|
||||
* struct S { size_t length; void* ptr; }
|
||||
*/
|
||||
if (global.params.is64bit && !global.params.isLP64)
|
||||
{
|
||||
// For AMD64 ILP32 ABI, delegates fit into a single integer register.
|
||||
unsigned offset = (unsigned)Type::tsize_t->size(Loc());
|
||||
Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
|
||||
if (t)
|
||||
{
|
||||
result = new TypeTuple(t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = new TypeTuple(Type::tvoidptr, Type::tvoidptr);
|
||||
}
|
||||
|
||||
void visit(TypeStruct *t)
|
||||
{
|
||||
//printf("TypeStruct::toArgTypes() %s\n", t->toChars());
|
||||
if (!t->sym->isPOD() || t->sym->fields.dim == 0)
|
||||
{
|
||||
Lmemory:
|
||||
//printf("\ttoArgTypes() %s => [ ]\n", t->toChars());
|
||||
result = new TypeTuple(); // pass on the stack
|
||||
return;
|
||||
}
|
||||
Type *t1 = NULL;
|
||||
Type *t2 = NULL;
|
||||
const d_uns64 sz = t->size(Loc());
|
||||
assert(sz < 0xFFFFFFFF);
|
||||
switch ((unsigned)sz)
|
||||
{
|
||||
case 1:
|
||||
t1 = Type::tint8;
|
||||
break;
|
||||
case 2:
|
||||
t1 = Type::tint16;
|
||||
break;
|
||||
case 3:
|
||||
if (!global.params.is64bit)
|
||||
goto Lmemory;
|
||||
/* fall through */
|
||||
case 4:
|
||||
t1 = Type::tint32;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
if (!global.params.is64bit)
|
||||
goto Lmemory;
|
||||
/* fall through */
|
||||
case 8:
|
||||
t1 = Type::tint64;
|
||||
break;
|
||||
case 16:
|
||||
t1 = NULL; // could be a TypeVector
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
if (!global.params.is64bit)
|
||||
goto Lmemory;
|
||||
t1 = NULL;
|
||||
break;
|
||||
default:
|
||||
goto Lmemory;
|
||||
}
|
||||
if (global.params.is64bit && t->sym->fields.dim)
|
||||
{
|
||||
t1 = NULL;
|
||||
for (size_t i = 0; i < t->sym->fields.dim; i++)
|
||||
{
|
||||
VarDeclaration *f = t->sym->fields[i];
|
||||
//printf(" [%d] %s f->type = %s\n", (int)i, f->toChars(), f->type->toChars());
|
||||
|
||||
TypeTuple *tup = toArgTypes(f->type);
|
||||
if (!tup)
|
||||
goto Lmemory;
|
||||
size_t dim = tup->arguments->dim;
|
||||
Type *ft1 = NULL;
|
||||
Type *ft2 = NULL;
|
||||
switch (dim)
|
||||
{
|
||||
case 2:
|
||||
ft1 = (*tup->arguments)[0]->type;
|
||||
ft2 = (*tup->arguments)[1]->type;
|
||||
break;
|
||||
case 1:
|
||||
if (f->offset < 8)
|
||||
ft1 = (*tup->arguments)[0]->type;
|
||||
else
|
||||
ft2 = (*tup->arguments)[0]->type;
|
||||
break;
|
||||
default:
|
||||
goto Lmemory;
|
||||
}
|
||||
|
||||
if (f->offset & 7)
|
||||
{
|
||||
// Misaligned fields goto Lmemory
|
||||
unsigned alignsz = f->type->alignsize();
|
||||
if (f->offset & (alignsz - 1))
|
||||
goto Lmemory;
|
||||
|
||||
// Fields that overlap the 8byte boundary goto Lmemory
|
||||
const d_uns64 fieldsz = f->type->size(Loc());
|
||||
assert(fieldsz != SIZE_INVALID && fieldsz < UINT64_MAX - UINT32_MAX);
|
||||
if (f->offset < 8 && (f->offset + fieldsz) > 8)
|
||||
goto Lmemory;
|
||||
}
|
||||
|
||||
// First field in 8byte must be at start of 8byte
|
||||
assert(t1 || f->offset == 0);
|
||||
//printf("ft1 = %s\n", ft1 ? ft1->toChars() : "null");
|
||||
//printf("ft2 = %s\n", ft2 ? ft2->toChars() : "null");
|
||||
if (ft1)
|
||||
{
|
||||
t1 = argtypemerge(t1, ft1, f->offset);
|
||||
if (!t1)
|
||||
goto Lmemory;
|
||||
}
|
||||
|
||||
if (ft2)
|
||||
{
|
||||
unsigned off2 = f->offset;
|
||||
if (ft1)
|
||||
off2 = 8;
|
||||
if (!t2 && off2 != 8)
|
||||
goto Lmemory;
|
||||
assert(t2 || off2 == 8);
|
||||
t2 = argtypemerge(t2, ft2, off2 - 8);
|
||||
if (!t2)
|
||||
goto Lmemory;
|
||||
}
|
||||
}
|
||||
|
||||
if (t2)
|
||||
{
|
||||
if (t1->isfloating() && t2->isfloating())
|
||||
{
|
||||
if ((t1->ty == Tfloat32 || t1->ty == Tfloat64) &&
|
||||
(t2->ty == Tfloat32 || t2->ty == Tfloat64))
|
||||
;
|
||||
else
|
||||
goto Lmemory;
|
||||
}
|
||||
else if (t1->isfloating())
|
||||
goto Lmemory;
|
||||
else if (t2->isfloating())
|
||||
goto Lmemory;
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("\ttoArgTypes() %s => [%s,%s]\n", t->toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : "");
|
||||
|
||||
if (t1)
|
||||
{
|
||||
//if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars());
|
||||
if (t2)
|
||||
result = new TypeTuple(t1, t2);
|
||||
else
|
||||
result = new TypeTuple(t1);
|
||||
}
|
||||
else
|
||||
goto Lmemory;
|
||||
}
|
||||
|
||||
void visit(TypeEnum *t)
|
||||
{
|
||||
t->toBasetype()->accept(this);
|
||||
}
|
||||
|
||||
void visit(TypeClass *)
|
||||
{
|
||||
result = new TypeTuple(Type::tvoidptr);
|
||||
}
|
||||
};
|
||||
|
||||
ToArgTypes v;
|
||||
t->accept(&v);
|
||||
return v.result;
|
||||
}
|
|
@ -22,9 +22,9 @@
|
|||
#include "statement.h"
|
||||
#include "template.h"
|
||||
#include "tokens.h"
|
||||
#include "target.h"
|
||||
|
||||
Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
|
||||
TypeTuple *toArgTypes(Type *t);
|
||||
void unSpeculative(Scope *sc, RootObject *o);
|
||||
bool MODimplicitConv(MOD modfrom, MOD modto);
|
||||
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
|
||||
|
@ -1303,8 +1303,8 @@ void StructDeclaration::finalizeSize()
|
|||
}
|
||||
}
|
||||
|
||||
TypeTuple *tt = toArgTypes(type);
|
||||
size_t dim = tt->arguments->dim;
|
||||
TypeTuple *tt = Target::toArgTypes(type);
|
||||
size_t dim = tt ? tt->arguments->dim : 0;
|
||||
if (dim >= 1)
|
||||
{
|
||||
assert(dim <= 2);
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2);
|
||||
bool isArrayOpValid(Expression *e);
|
||||
Expression *expandVar(int result, VarDeclaration *v);
|
||||
TypeTuple *toArgTypes(Type *t);
|
||||
bool checkAssignEscape(Scope *sc, Expression *e, bool gag);
|
||||
bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
|
||||
bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
|
||||
|
@ -2074,7 +2073,7 @@ public:
|
|||
* The results of this are highly platform dependent, and intended
|
||||
* primarly for use in implementing va_arg().
|
||||
*/
|
||||
tded = toArgTypes(e->targ);
|
||||
tded = Target::toArgTypes(e->targ);
|
||||
if (!tded)
|
||||
goto Lno; // not valid for a parameter
|
||||
break;
|
||||
|
|
|
@ -21,6 +21,7 @@ class Dsymbol;
|
|||
class Expression;
|
||||
class Parameter;
|
||||
class Type;
|
||||
class TypeTuple;
|
||||
struct OutBuffer;
|
||||
|
||||
struct Target
|
||||
|
@ -73,4 +74,5 @@ struct Target
|
|||
static Type *cppParameterType(Parameter *p);
|
||||
static bool cppFundamentalType(const Type *t, bool& isFundamental);
|
||||
static LINK systemLinkage();
|
||||
static TypeTuple *toArgTypes(Type *t);
|
||||
};
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
|
||||
void chkArgTypes(S, V...)()
|
||||
{
|
||||
pragma(msg, S);
|
||||
static if (is(S U == __argTypes))
|
||||
{
|
||||
foreach (T; U) { pragma(msg, T); }
|
||||
static assert(U.length == V.length);
|
||||
foreach (i, T; U)
|
||||
static assert(is(V[i] == T));
|
||||
}
|
||||
else
|
||||
static assert(0);
|
||||
}
|
||||
|
||||
void chkSingle(T,U)()
|
||||
{
|
||||
struct S { T a; }
|
||||
chkArgTypes!(S, U)();
|
||||
}
|
||||
|
||||
void chkIdentity(T)()
|
||||
{
|
||||
chkSingle!(T,T)();
|
||||
}
|
||||
|
||||
void chkPair(T,U,V)()
|
||||
{
|
||||
struct S { T a; U b; }
|
||||
chkArgTypes!(S, V)();
|
||||
}
|
||||
|
||||
version (X86_64)
|
||||
{
|
||||
int main()
|
||||
{
|
||||
chkIdentity!byte();
|
||||
chkIdentity!ubyte();
|
||||
chkIdentity!short();
|
||||
chkIdentity!ushort();
|
||||
chkIdentity!int();
|
||||
chkIdentity!uint();
|
||||
chkIdentity!long();
|
||||
chkIdentity!ulong();
|
||||
chkSingle!(char,ubyte)();
|
||||
chkSingle!(wchar,ushort)();
|
||||
chkSingle!(dchar,uint)();
|
||||
|
||||
chkIdentity!float();
|
||||
chkIdentity!double();
|
||||
chkIdentity!real();
|
||||
|
||||
chkIdentity!(void*)();
|
||||
|
||||
chkIdentity!(__vector(byte[16]))();
|
||||
chkIdentity!(__vector(ubyte[16]))();
|
||||
chkIdentity!(__vector(short[8]))();
|
||||
chkIdentity!(__vector(ushort[8]))();
|
||||
chkIdentity!(__vector(int[4]))();
|
||||
chkIdentity!(__vector(uint[4]))();
|
||||
chkIdentity!(__vector(long[2]))();
|
||||
chkIdentity!(__vector(ulong[2]))();
|
||||
|
||||
chkIdentity!(__vector(float[4]))();
|
||||
chkIdentity!(__vector(double[2]))();
|
||||
|
||||
chkPair!(byte,byte,short);
|
||||
chkPair!(ubyte,ubyte,short);
|
||||
chkPair!(short,short,int);
|
||||
chkPair!(int,int,long);
|
||||
|
||||
chkPair!(byte,short,int);
|
||||
chkPair!(short,byte,int);
|
||||
|
||||
chkPair!(int,float,long);
|
||||
chkPair!(float,int,long);
|
||||
chkPair!(byte,float,long);
|
||||
chkPair!(float,short,long);
|
||||
|
||||
//struct S1 { long a; long b; }
|
||||
//chkArgTypes!(S1, long, long)();
|
||||
|
||||
struct S2 { union { long a; double d; }}
|
||||
chkArgTypes!(S2, long)();
|
||||
|
||||
struct S3 { union { double d; long a; }}
|
||||
chkArgTypes!(S3, long)();
|
||||
|
||||
struct S4 { int a,b,c,d,e; }
|
||||
chkArgTypes!(S4)();
|
||||
|
||||
struct S5 { align(1): char a; int b; }
|
||||
chkArgTypes!(S5)();
|
||||
|
||||
struct S6 { align(1): int a; void* b; }
|
||||
chkArgTypes!(S5)();
|
||||
|
||||
struct S7 { union { void* p; real r; }}
|
||||
chkArgTypes!(S7)();
|
||||
|
||||
struct S8 { union { real r; void* p; }}
|
||||
chkArgTypes!(S8)();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
2020-04-13 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
|
||||
* libdruntime/core/stdc/stdarg.d: Remove run-time va_list template.
|
||||
|
||||
2020-04-10 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
|
||||
* d_rules.am (libdgruntime_la_LINK): Move to libdruntime/Makefile.am.
|
||||
|
|
|
@ -50,166 +50,6 @@ version (GNU)
|
|||
void va_arg(T)(ref va_list ap, ref T parmn);
|
||||
|
||||
|
||||
/*************
|
||||
* Retrieve and store through parmn the next value that is of TypeInfo ti.
|
||||
* Used when the static type is not known.
|
||||
*/
|
||||
version (X86)
|
||||
{
|
||||
///
|
||||
void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
|
||||
{
|
||||
auto p = ap;
|
||||
auto tsize = ti.tsize;
|
||||
ap = cast(va_list)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
|
||||
parmn[0..tsize] = p[0..tsize];
|
||||
}
|
||||
}
|
||||
else version (X86_64)
|
||||
{
|
||||
/// Layout of this struct must match __builtin_va_list for C ABI compatibility
|
||||
struct __va_list
|
||||
{
|
||||
uint offset_regs = 6 * 8; // no regs
|
||||
uint offset_fpregs = 6 * 8 + 8 * 16; // no fp regs
|
||||
void* stack_args;
|
||||
void* reg_args;
|
||||
}
|
||||
|
||||
///
|
||||
void va_arg()(ref va_list apx, TypeInfo ti, void* parmn)
|
||||
{
|
||||
__va_list* ap = cast(__va_list*)apx;
|
||||
TypeInfo arg1, arg2;
|
||||
if (!ti.argTypes(arg1, arg2))
|
||||
{
|
||||
bool inXMMregister(TypeInfo arg) pure nothrow @safe
|
||||
{
|
||||
return (arg.flags & 2) != 0;
|
||||
}
|
||||
|
||||
TypeInfo_Vector v1 = arg1 ? cast(TypeInfo_Vector)arg1 : null;
|
||||
if (arg1 && (arg1.tsize() <= 8 || v1))
|
||||
{ // Arg is passed in one register
|
||||
auto tsize = arg1.tsize();
|
||||
void* p;
|
||||
bool stack = false;
|
||||
auto offset_fpregs_save = ap.offset_fpregs;
|
||||
auto offset_regs_save = ap.offset_regs;
|
||||
L1:
|
||||
if (inXMMregister(arg1) || v1)
|
||||
{ // Passed in XMM register
|
||||
if (ap.offset_fpregs < (6 * 8 + 16 * 8) && !stack)
|
||||
{
|
||||
p = ap.reg_args + ap.offset_fpregs;
|
||||
ap.offset_fpregs += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = ap.stack_args;
|
||||
ap.stack_args += (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
|
||||
stack = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Passed in regular register
|
||||
if (ap.offset_regs < 6 * 8 && !stack)
|
||||
{
|
||||
p = ap.reg_args + ap.offset_regs;
|
||||
ap.offset_regs += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = ap.stack_args;
|
||||
ap.stack_args += 8;
|
||||
stack = true;
|
||||
}
|
||||
}
|
||||
parmn[0..tsize] = p[0..tsize];
|
||||
|
||||
if (arg2)
|
||||
{
|
||||
if (inXMMregister(arg2))
|
||||
{ // Passed in XMM register
|
||||
if (ap.offset_fpregs < (6 * 8 + 16 * 8) && !stack)
|
||||
{
|
||||
p = ap.reg_args + ap.offset_fpregs;
|
||||
ap.offset_fpregs += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!stack)
|
||||
{ // arg1 is really on the stack, so rewind and redo
|
||||
ap.offset_fpregs = offset_fpregs_save;
|
||||
ap.offset_regs = offset_regs_save;
|
||||
stack = true;
|
||||
goto L1;
|
||||
}
|
||||
p = ap.stack_args;
|
||||
ap.stack_args += (arg2.tsize() + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Passed in regular register
|
||||
if (ap.offset_regs < 6 * 8 && !stack)
|
||||
{
|
||||
p = ap.reg_args + ap.offset_regs;
|
||||
ap.offset_regs += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!stack)
|
||||
{ // arg1 is really on the stack, so rewind and redo
|
||||
ap.offset_fpregs = offset_fpregs_save;
|
||||
ap.offset_regs = offset_regs_save;
|
||||
stack = true;
|
||||
goto L1;
|
||||
}
|
||||
p = ap.stack_args;
|
||||
ap.stack_args += 8;
|
||||
}
|
||||
}
|
||||
auto sz = ti.tsize() - 8;
|
||||
(parmn + 8)[0..sz] = p[0..sz];
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Always passed in memory
|
||||
// The arg may have more strict alignment than the stack
|
||||
auto talign = ti.talign();
|
||||
auto tsize = ti.tsize();
|
||||
auto p = cast(void*)((cast(size_t)ap.stack_args + talign - 1) & ~(talign - 1));
|
||||
ap.stack_args = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
|
||||
parmn[0..tsize] = p[0..tsize];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "not a valid argument type for va_arg");
|
||||
}
|
||||
}
|
||||
}
|
||||
else version (ARM)
|
||||
{
|
||||
///
|
||||
void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
|
||||
{
|
||||
auto p = *cast(void**) ≈
|
||||
auto tsize = ti.tsize();
|
||||
*cast(void**) &ap += ( tsize + size_t.sizeof - 1 ) & ~( size_t.sizeof - 1 );
|
||||
parmn[0..tsize] = p[0..tsize];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
///
|
||||
void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
|
||||
{
|
||||
static assert(false, "Unsupported platform");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
* End use of ap.
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue