Skip to content
This repository has been archived by the owner on Jun 20, 2019. It is now read-only.

Commit

Permalink
Merge pull request #141 from ibuclaw/valist
Browse files Browse the repository at this point in the history
Silently convert va_list[1] to be passed around as a pointer in the backend
  • Loading branch information
jpf91 committed Aug 25, 2015
2 parents 58e4a29 + 10f6c8a commit cff73bc
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 84 deletions.
13 changes: 13 additions & 0 deletions gcc/d/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2015-08-25 Iain Buclaw <ibuclaw@gdcproject.org>

* d-builtins.cc(maybe_set_builtin_1): Remove va_list handling.
(d_init_builtins): Don't represent static array va_list as reference.
* d-codegen.cc(convert_for_argument): Handle va_list as a static array.
(declaration_type): Likewise.
(type_passed_as): Likewise.
(decl_reference_p): Renamed to declaration_type_kind, update to return
how type is represented internally, updated all callers.
(arg_reference_p): Renamed to argument_type_kind, update to return how
type is represented internally, updated all callers.
* d-codegen.h(type_kind): Declare.

2015-08-22 Iain Buclaw <ibuclaw@gdcproject.org>

* toir.cc(IRVisitor::visit(TryCatchStatement)): Always emit call to
Expand Down
22 changes: 3 additions & 19 deletions gcc/d/d-builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -497,21 +497,6 @@ maybe_set_builtin_1(Dsymbol *m)
if (fd->ident != Lexer::idPool(name))
continue;

// As per C ABI, in gcc.builtins module va_list is passed by reference.
TypeFunction *tf = (TypeFunction *) fd->type;
for (size_t i = 0; i < tf->parameters->dim; i++)
{
Type *type = (*tf->parameters)[i]->type;
if (type->ty == Tsarray)
(*tf->parameters)[i]->storageClass |= STCref;
else if (type->ty == Tident && Type::tvalist->ty == Tsarray)
{
Identifier *ident = ((TypeIdentifier *) type)->ident;
if (ident == Lexer::idPool("va_list"))
(*tf->parameters)[i]->storageClass |= STCref;
}
}

fd->csym = new Symbol;
fd->csym->Sident = name;
fd->csym->Stree = decl;
Expand Down Expand Up @@ -765,10 +750,9 @@ d_init_builtins()

if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
// It might seem natural to make the reference type a pointer,
// but this will not work in D. There is no implicit casting
// from an array to a pointer.
va_list_arg_type_node = build_reference_type(va_list_type_node);
// It might seem natural to make the argument type a pointer, but there
// is no implicit casting from arrays to pointers in D.
va_list_arg_type_node = va_list_type_node;
va_list_ref_type_node = va_list_arg_type_node;
}
else
Expand Down
165 changes: 114 additions & 51 deletions gcc/d/d-codegen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -821,19 +821,32 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
// Return a TREE representation of EXPR converted to represent parameter type ARG.

tree
convert_for_argument (tree exp_tree, Expression *expr, Parameter *arg)
convert_for_argument(tree exp_tree, Expression *expr, Parameter *arg)
{
if (arg_reference_p (arg))
switch (argument_type_kind(arg))
{
// Front-end already sometimes automatically takes the address
case type_reference:
// Front-end sometimes automatically takes the address.
if (expr->op != TOKaddress && expr->op != TOKsymoff && expr->op != TOKadd)
exp_tree = build_address (exp_tree);
exp_tree = build_address(exp_tree);

return convert (type_passed_as (arg), exp_tree);
}
return convert(type_passed_as(arg), exp_tree);

case type_va_pointer:
// Do nothing if the va_list has already been decayed to a pointer.
if (POINTER_TYPE_P (TREE_TYPE (exp_tree)))
return exp_tree;
else
return build_address(exp_tree);

// Lazy arguments: expr should already be a delegate
return exp_tree;
case type_lazy:
case type_normal:
// Lazy arguments: expr should already be a delegate
return exp_tree;

default:
gcc_unreachable();
}
}

// Perform default promotions for data used in expressions.
Expand Down Expand Up @@ -927,81 +940,131 @@ d_array_convert (Expression *exp)
gcc_unreachable();
}

// Return TRUE if declaration DECL is a reference type.
// Return the kind of type the declaration DECL should be stored as.

bool
decl_reference_p (Declaration *decl)
type_kind
declaration_type_kind(Declaration *decl)
{
Type *base_type = decl->type->toBasetype();
Type *tb = decl->type->toBasetype();

if (base_type->ty == Treference)
return true;
// Compatibility with C ABI, if the va_list is passed as a pointer.
// However for ever other case, static arrays are passed around by value.
if (decl->isParameter() && Type::tvalist->ty == Tsarray
&& d_types_same(tb, Type::tvalist))
return type_va_pointer;

if (decl->storage_class & (STCout | STCref))
return true;
// Declaration is a reference type.
if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
return type_reference;

return false;
// Declaration is a lazy parameter.
if (decl->storage_class & STClazy)
return type_lazy;

return type_normal;
}

// Returns the real type for declaration DECL.
// Reference decls are converted to reference-to-types.
// Lazy decls are converted into delegates.

tree
declaration_type (Declaration *decl)
declaration_type(Declaration *decl)
{
tree decl_type = build_ctype(decl->type);

if (decl_reference_p (decl))
decl_type = build_reference_type (decl_type);
else if (decl->storage_class & STClazy)
switch (declaration_type_kind(decl))
{
TypeFunction *tf = new TypeFunction (NULL, decl->type, false, LINKd);
TypeDelegate *t = new TypeDelegate (tf);
decl_type = build_ctype(t->merge());
}
else if (decl->isThisDeclaration())
decl_type = insert_type_modifiers (decl_type, MODconst);
case type_reference:
{
tree decl_type = build_ctype(decl->type);
return build_reference_type(decl_type);
}

case type_lazy:
{
TypeFunction *tf = new TypeFunction(NULL, decl->type, false, LINKd);
TypeDelegate *t = new TypeDelegate(tf);
return build_ctype(t->merge());
}

case type_va_pointer:
{
Type *valist = decl->type->nextOf()->pointerTo();
valist = valist->castMod(decl->type->mod);
return build_ctype(valist);
}

case type_normal:
{
tree decl_type = build_ctype(decl->type);
if (decl->isThisDeclaration())
decl_type = insert_type_modifiers(decl_type, MODconst);

return decl_type;
return decl_type;
}

default:
gcc_unreachable();
}
}

// These should match the Declaration versions above
// Return TRUE if parameter ARG is a reference type.
// Return the kind of type the parameter ARG should be passed as.

bool
arg_reference_p (Parameter *arg)
type_kind
argument_type_kind(Parameter *arg)
{
Type *base_type = arg->type->toBasetype();
Type *tb = arg->type->toBasetype();

if (base_type->ty == Treference)
return true;
// Compatibility with C ABI, if the va_list is passed as a pointer.
// However for ever other case, static arrays are passed around by value.
if (Type::tvalist->ty == Tsarray && d_types_same(tb, Type::tvalist))
return type_va_pointer;

if (arg->storageClass & (STCout | STCref))
return true;
// Parameter is a reference type.
if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
return type_reference;

return false;
// Parameter is a lazy parameter.
if (arg->storageClass & STClazy)
return type_lazy;

return type_normal;
}

// Returns the real type for parameter ARG.
// Reference parameters are converted to reference-to-types.
// Lazy parameters are converted into delegates.

tree
type_passed_as (Parameter *arg)
type_passed_as(Parameter *arg)
{
tree arg_type = build_ctype(arg->type);

if (arg_reference_p (arg))
arg_type = build_reference_type (arg_type);
else if (arg->storageClass & STClazy)
switch (argument_type_kind(arg))
{
TypeFunction *tf = new TypeFunction (NULL, arg->type, false, LINKd);
TypeDelegate *t = new TypeDelegate (tf);
arg_type = build_ctype(t->merge());
}
case type_reference:
{
tree arg_type = build_ctype(arg->type);
return build_reference_type(arg_type);
}

case type_lazy:
{
TypeFunction *tf = new TypeFunction(NULL, arg->type, false, LINKd);
TypeDelegate *t = new TypeDelegate(tf);
return build_ctype(t->merge());
}

case type_va_pointer:
{
Type *valist = arg->type->nextOf()->pointerTo();
valist = valist->castMod(arg->type->mod);
return build_ctype(valist);
}

case type_normal:
return build_ctype(arg->type);

return arg_type;
default:
gcc_unreachable();
}
}

// Returns an array of type D_TYPE which has SIZE number of elements.
Expand Down
14 changes: 12 additions & 2 deletions gcc/d/d-codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ enum LibCall
LIBCALL_count
};

// If a type is internally represented as something else.

enum type_kind
{
type_normal,
type_reference, // Passed by reference.
type_va_pointer, // VA list that is passed as a pointer.
type_lazy, // Converted into a delegate.
};

struct FuncFrameInfo
{
bool creates_frame; // Function creates nested frame.
Expand Down Expand Up @@ -75,9 +85,9 @@ extern tree build_address (tree exp);
extern tree build_struct_memcmp (tree_code code, StructDeclaration *sd, tree arg0, tree arg1);

// Routines to handle variables that are references.
extern bool decl_reference_p (Declaration *decl);
extern type_kind declaration_type_kind(Declaration *decl);
extern tree declaration_type (Declaration *decl);
extern bool arg_reference_p (Parameter *arg);
extern type_kind argument_type_kind(Parameter *arg);
extern tree type_passed_as (Parameter *arg);

extern tree d_array_type (Type *d_type, uinteger_t size);
Expand Down
2 changes: 1 addition & 1 deletion gcc/d/d-decls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ VarDeclaration::toSymbol()
// Can't set TREE_STATIC, etc. until we get to toObjFile as this could be
// called from a variable in an imported module.
if ((isConst() || isImmutable()) && (storage_class & STCinit)
&& !decl_reference_p (this))
&& declaration_type_kind(this) != type_reference)
{
if (!TREE_STATIC (decl))
TREE_READONLY (decl) = 1;
Expand Down
16 changes: 8 additions & 8 deletions gcc/d/d-elem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1441,10 +1441,10 @@ PtrExp::toElem (IRState *)
else if (e1->op == TOKsymoff)
{
SymOffExp *sym_exp = (SymOffExp *) e1;
if (!decl_reference_p (sym_exp->var))
if (declaration_type_kind(sym_exp->var) != type_reference)
{
rec_type = sym_exp->var->type->toBasetype();
rec_tree = get_decl_tree (sym_exp->var);
rec_tree = get_decl_tree(sym_exp->var);
the_offset = sym_exp->offset;
}
}
Expand Down Expand Up @@ -1919,13 +1919,13 @@ SymbolExp::toElem (IRState *)

// For variables that are references (currently only out/inout arguments;
// objects don't count), evaluating the variable means we want what it refers to.
if (decl_reference_p (var))
exp = indirect_ref (build_ctype(var->type), exp);
if (declaration_type_kind(var) == type_reference)
exp = indirect_ref(build_ctype(var->type), exp);

// The frontend sometimes emits different types for the expression and var.
// Convert to the expressions type, but don't convert FuncDeclaration as
// type->ctype sometimes isn't the correct type for functions!
if (!var->type->equals (type) && !var->isFuncDeclaration())
if (!d_types_same(var->type, type) && !var->isFuncDeclaration())
exp = build1 (VIEW_CONVERT_EXPR, build_ctype(type), exp);

return exp;
Expand All @@ -1937,10 +1937,10 @@ SymbolExp::toElem (IRState *)
exp = get_decl_tree (var);
TREE_USED (exp) = 1;

if (decl_reference_p (var))
gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp)));
if (declaration_type_kind(var) == type_reference)
gcc_assert(POINTER_TYPE_P (TREE_TYPE (exp)));
else
exp = build_address (exp);
exp = build_address(exp);

if (!offset)
return d_convert (build_ctype(type), exp);
Expand Down
13 changes: 10 additions & 3 deletions gcc/d/dfrontend/cppmangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,18 @@ class CppMangleVisitor : public Visitor
td = new TypeDelegate(td);
t = t->merge();
}
if (t->ty == Tsarray)
#ifdef IN_GCC
if (t->ty == Tsarray && Type::tvalist->ty == Tsarray)
{
// Mangle static arrays as pointers
t = t->nextOf()->pointerTo();
// Could be a va_list, which we mangle as a pointer.
Type *tb = t->toBasetype()->mutableOf();
if (tb == Type::tvalist)
{
tb = t->nextOf()->pointerTo();
t = tb->castMod(t->mod);
}
}
#endif

/* If it is a basic, enum or struct type,
* then don't mark it const
Expand Down

0 comments on commit cff73bc

Please sign in to comment.