+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.
d/access.o \
d/aliasthis.o \
d/apply.o \
- d/argtypes.o \
d/arrayop.o \
d/attrib.o \
d/blockexit.o \
{
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;
+}
-3e10e2dd29e583f1d94d84de5e4bd858e0303669
+799066f498aebcfa420df284cac1f204b1f953a8
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
+++ /dev/null
-
-/* 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;
-}
#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);
}
}
- 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);
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);
* 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;
class Expression;
class Parameter;
class Type;
+class TypeTuple;
struct OutBuffer;
struct Target
static Type *cppParameterType(Parameter *p);
static bool cppFundamentalType(const Type *t, bool& isFundamental);
static LINK systemLinkage();
+ static TypeTuple *toArgTypes(Type *t);
};
+++ /dev/null
-
-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;
- }
-}
+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.
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.
*/