484 changes: 421 additions & 63 deletions gcc/d/d-codegen.cc

Large diffs are not rendered by default.

29 changes: 21 additions & 8 deletions gcc/d/d-codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,20 @@ struct FuncFrameInfo
};

// Visitor routines for barrier between frontend and glue.
void build_ir(Statement *s, IRState *irs);
void build_ir(FuncDeclaration *fd);
tree build_ctype(Type *t);

// Code generation routines.
extern void push_binding_level(level_kind kind);
extern tree pop_binding_level();

extern void push_stmt_list();
extern tree pop_stmt_list();
extern void add_stmt(tree t);

extern void start_function(FuncDeclaration *decl);
extern void end_function();

extern tree d_decl_context (Dsymbol *dsym);

extern tree d_mark_addressable (tree exp);
Expand Down Expand Up @@ -88,7 +98,11 @@ extern tree maybe_compound_expr (tree arg0, tree arg1);
extern tree maybe_vcompound_expr (tree arg0, tree arg1);

extern tree bind_expr (tree var_chain, tree body);
extern tree d_build_label (Loc loc, Identifier *ident);

extern tree define_label(Statement *s, Identifier *ident = NULL);
extern tree lookup_label(Statement *s, Identifier *ident = NULL);
extern tree lookup_bc_label(Statement *s, bc_kind);
extern void check_goto(Statement *from, Statement *to);

// Type conversion.
// 'd_convert' just to give it a different name from the extern "C" convert.
Expand Down Expand Up @@ -136,24 +150,24 @@ extern tree d_assert_call (Loc loc, LibCall libcall, tree msg = NULL_TREE);

// Closures and frame generation.
extern tree build_frame_type(FuncDeclaration *func);
extern void build_closure(FuncDeclaration *fd, IRState *irs);
extern void build_closure(FuncDeclaration *fd);
extern FuncFrameInfo *get_frameinfo(FuncDeclaration *fd);
extern tree get_framedecl(FuncDeclaration *inner, FuncDeclaration *outer);

extern tree build_vthis(AggregateDeclaration *decl, FuncDeclaration *fd);
extern tree build_vthis(AggregateDeclaration *decl);
extern tree build_vthis_type(tree basetype, tree type);

// Static chain for nested functions
extern tree get_frame_for_symbol(FuncDeclaration *func, Dsymbol *sym);
extern tree get_frame_for_symbol(Dsymbol *sym);

// Local variables
extern void build_local_var(VarDeclaration *vd, FuncDeclaration *fd);
extern void build_local_var(VarDeclaration *vd);
extern tree build_local_temp(tree type);
extern tree create_temporary_var(tree type);
extern tree maybe_temporary_var(tree exp, tree *out_var);
extern void expand_decl(tree decl);

extern tree get_decl_tree(Declaration *decl, FuncDeclaration *func);
extern tree get_decl_tree(Declaration *decl);

// Temporaries (currently just SAVE_EXPRs)
extern tree make_temp (tree t);
Expand Down Expand Up @@ -265,7 +279,6 @@ extern bool call_by_alias_p (FuncDeclaration *caller, FuncDeclaration *callee);

// Globals.
extern Module *current_module_decl;
#define current_irstate (cfun->language->irs)

#endif

Expand Down
245 changes: 123 additions & 122 deletions gcc/d/d-convert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,128 +27,7 @@
#include "convert.h"
#include "stor-layout.h"

#include "d-lang.h"

// Creates an expression whose value is that of EXPR, converted to type TYPE.
// This function implements all reasonable scalar conversions.

tree
convert(tree type, tree expr)
{
tree e = expr;
tree_code code = TREE_CODE(type);

if (type == error_mark_node
|| expr == error_mark_node
|| TREE_TYPE(expr) == error_mark_node)
return error_mark_node;

const char *invalid_conv_diag
= targetm.invalid_conversion(TREE_TYPE(expr), type);

if (invalid_conv_diag)
{
error("%s", invalid_conv_diag);
return error_mark_node;
}

if (type == TREE_TYPE(expr))
return expr;

if (TREE_CODE(type) == ARRAY_TYPE
&& TREE_CODE(TREE_TYPE(expr)) == ARRAY_TYPE
&& TYPE_DOMAIN(type) == TYPE_DOMAIN(TREE_TYPE(expr)))
return expr;

tree ret = targetm.convert_to_type(type, expr);
if (ret)
return ret;

STRIP_TYPE_NOPS(e);
tree etype = TREE_TYPE(e);

if (TYPE_MAIN_VARIANT(type) == TYPE_MAIN_VARIANT(TREE_TYPE(expr)))
return fold_convert(type, expr);
if (TREE_CODE(TREE_TYPE(expr)) == ERROR_MARK)
return error_mark_node;
if (TREE_CODE(TREE_TYPE(expr)) == VOID_TYPE)
{
error("void value not ignored as it ought to be");
return error_mark_node;
}

switch (code)
{
case VOID_TYPE:
return fold_convert(type, e);

case INTEGER_TYPE:
case ENUMERAL_TYPE:
if (TREE_CODE(etype) == POINTER_TYPE
|| TREE_CODE(etype) == REFERENCE_TYPE)
{
if (integer_zerop(e))
return build_int_cst(type, 0);

// Convert to an unsigned integer of the correct width first, and
// from there widen/truncate to the required type.
tree utype = lang_hooks.types.type_for_size(TYPE_PRECISION(etype), 1);
ret = fold_build1(CONVERT_EXPR, utype, e);
return fold_convert(type, ret);
}

ret = convert_to_integer(type, e);
goto maybe_fold;

case BOOLEAN_TYPE:
return fold_convert(type, d_truthvalue_conversion(expr));

case POINTER_TYPE:
case REFERENCE_TYPE:
ret = convert_to_pointer(type, e);
goto maybe_fold;

case REAL_TYPE:
if (TREE_CODE (etype) == COMPLEX_TYPE && D_TYPE_IMAGINARY_FLOAT (type))
e = build1(IMAGPART_EXPR, TREE_TYPE (etype), e);

ret = convert_to_real(type, e);
goto maybe_fold;

case COMPLEX_TYPE:
if (TREE_CODE (etype) == REAL_TYPE && D_TYPE_IMAGINARY_FLOAT (etype))
ret = build2(COMPLEX_EXPR, type,
build_zero_cst(TREE_TYPE (type)),
convert(TREE_TYPE (type), expr));
else
ret = convert_to_complex(type, e);
goto maybe_fold;

case VECTOR_TYPE:
ret = convert_to_vector(type, e);
goto maybe_fold;

case RECORD_TYPE:
case UNION_TYPE:
if (lang_hooks.types_compatible_p(type, TREE_TYPE(expr)))
{
ret = build1(VIEW_CONVERT_EXPR, type, expr);
goto maybe_fold;
}
break;

default:
break;

maybe_fold:
if (!TREE_CONSTANT(ret))
ret = fold(ret);
return ret;
}

error("conversion to non-scalar type requested");
return error_mark_node;
}
#include "d-tree.h"


// Build CODE expression with operands OP0 and OP1.
Expand Down Expand Up @@ -380,3 +259,125 @@ d_truthvalue_conversion (tree expr)
}
}


// Creates an expression whose value is that of EXPR, converted to type TYPE.
// This function implements all reasonable scalar conversions.

tree
convert(tree type, tree expr)
{
tree e = expr;
tree_code code = TREE_CODE(type);

if (type == error_mark_node
|| expr == error_mark_node
|| TREE_TYPE(expr) == error_mark_node)
return error_mark_node;

const char *invalid_conv_diag
= targetm.invalid_conversion(TREE_TYPE(expr), type);

if (invalid_conv_diag)
{
error("%s", invalid_conv_diag);
return error_mark_node;
}

if (type == TREE_TYPE(expr))
return expr;

if (TREE_CODE(type) == ARRAY_TYPE
&& TREE_CODE(TREE_TYPE(expr)) == ARRAY_TYPE
&& TYPE_DOMAIN(type) == TYPE_DOMAIN(TREE_TYPE(expr)))
return expr;

tree ret = targetm.convert_to_type(type, expr);
if (ret)
return ret;

STRIP_TYPE_NOPS(e);
tree etype = TREE_TYPE(e);

if (TYPE_MAIN_VARIANT(type) == TYPE_MAIN_VARIANT(TREE_TYPE(expr)))
return fold_convert(type, expr);
if (TREE_CODE(TREE_TYPE(expr)) == ERROR_MARK)
return error_mark_node;
if (TREE_CODE(TREE_TYPE(expr)) == VOID_TYPE)
{
error("void value not ignored as it ought to be");
return error_mark_node;
}

switch (code)
{
case VOID_TYPE:
return fold_convert(type, e);

case INTEGER_TYPE:
case ENUMERAL_TYPE:
if (TREE_CODE(etype) == POINTER_TYPE
|| TREE_CODE(etype) == REFERENCE_TYPE)
{
if (integer_zerop(e))
return build_int_cst(type, 0);

// Convert to an unsigned integer of the correct width first, and
// from there widen/truncate to the required type.
tree utype = lang_hooks.types.type_for_size(TYPE_PRECISION(etype), 1);
ret = fold_build1(CONVERT_EXPR, utype, e);
return fold_convert(type, ret);
}

ret = convert_to_integer(type, e);
goto maybe_fold;

case BOOLEAN_TYPE:
return fold_convert(type, d_truthvalue_conversion(expr));

case POINTER_TYPE:
case REFERENCE_TYPE:
ret = convert_to_pointer(type, e);
goto maybe_fold;

case REAL_TYPE:
if (TREE_CODE (etype) == COMPLEX_TYPE && D_TYPE_IMAGINARY_FLOAT (type))
e = build1(IMAGPART_EXPR, TREE_TYPE (etype), e);

ret = convert_to_real(type, e);
goto maybe_fold;

case COMPLEX_TYPE:
if (TREE_CODE (etype) == REAL_TYPE && D_TYPE_IMAGINARY_FLOAT (etype))
ret = build2(COMPLEX_EXPR, type,
build_zero_cst(TREE_TYPE (type)),
convert(TREE_TYPE (type), expr));
else
ret = convert_to_complex(type, e);
goto maybe_fold;

case VECTOR_TYPE:
ret = convert_to_vector(type, e);
goto maybe_fold;

case RECORD_TYPE:
case UNION_TYPE:
if (lang_hooks.types_compatible_p(type, TREE_TYPE(expr)))
{
ret = build1(VIEW_CONVERT_EXPR, type, expr);
goto maybe_fold;
}
break;

default:
break;

maybe_fold:
if (!TREE_CONSTANT(ret))
ret = fold(ret);
return ret;
}

error("conversion to non-scalar type requested");
return error_mark_node;
}

1 change: 1 addition & 0 deletions gcc/d/d-decls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "stringpool.h"
#include "stor-layout.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-codegen.h"
#include "d-objfile.h"
Expand Down
410 changes: 205 additions & 205 deletions gcc/d/d-elem.cc

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions gcc/d/d-glue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "fold-const.h"
#include "diagnostic.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-objfile.h"
#include "d-codegen.h"
Expand Down
1 change: 1 addition & 0 deletions gcc/d/d-incpath.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "options.h"
#include "cppdefault.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-codegen.h"

Expand Down
679 changes: 0 additions & 679 deletions gcc/d/d-irstate.cc

This file was deleted.

203 changes: 0 additions & 203 deletions gcc/d/d-irstate.h

This file was deleted.

78 changes: 8 additions & 70 deletions gcc/d/d-lang.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@
#include "gimple-expr.h"
#include "gimplify.h"
#include "debug.h"
#include "hash-set.h"
#include "function.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-codegen.h"
#include "d-objfile.h"
#include "d-irstate.h"
#include "d-dmd-gcc.h"
#include "id.h"

Expand Down Expand Up @@ -142,6 +141,10 @@ static Module *rootmodule = NULL;
/* Zero disables all standard directories for headers. */
static bool std_inc = true;

/* The current and global binding level in effect. */
struct binding_level *current_binding_level;
struct binding_level *global_binding_level;

/* Common initialization before calling option handlers. */
static void
d_init_options(unsigned int, cl_decoded_option *decoded_options)
Expand Down Expand Up @@ -245,7 +248,8 @@ d_init()
initTraitsStringTable();

// Backend init.
init_global_binding_level();
global_binding_level = ggc_cleared_alloc<binding_level>();
current_binding_level = global_binding_level;

// This allows the code in d-builtins.c to not have to worry about
// converting (C signed char *) to (D char *) for string arguments of
Expand Down Expand Up @@ -1340,56 +1344,6 @@ d_type_promotes_to(tree type)
}


struct binding_level *current_binding_level;
struct binding_level *global_binding_level;

static binding_level *
alloc_binding_level()
{
return ggc_cleared_alloc<binding_level>();
}

/* The D front-end does not use the 'binding level' system for a symbol table,
It is only needed to get debugging information for local variables and
otherwise support the backend. */

void
push_binding_level()
{
binding_level *new_level = alloc_binding_level();
new_level->level_chain = current_binding_level;
current_binding_level = new_level;
}

tree
pop_binding_level(bool functionbody)
{
binding_level *level = current_binding_level;
current_binding_level = level->level_chain;

tree block = make_node(BLOCK);
BLOCK_VARS (block) = level->names;
BLOCK_SUBBLOCKS (block) = level->blocks;

// In each subblock, record that this is its superior.
for (tree t = level->blocks; t; t = BLOCK_CHAIN (t))
BLOCK_SUPERCONTEXT (t) = block;

// Dispose of the block that we just made inside some higher level.
if (functionbody)
{
DECL_INITIAL (current_function_decl) = block;
BLOCK_SUPERCONTEXT (block) = current_function_decl;
}
else
current_binding_level->blocks
= block_chainon(current_binding_level->blocks, block);

TREE_USED (block) = 1;
return block;
}


// This is called by the backend before parsing. Need to make this do
// something or lang_hooks.clear_binding_stack (lhd_clear_binding_stack)
// loops forever.
Expand All @@ -1403,13 +1357,6 @@ d_global_bindings_p()
return !global_binding_level;
}

void
init_global_binding_level()
{
global_binding_level = alloc_binding_level();
current_binding_level = global_binding_level;
}

tree
d_pushdecl (tree decl)
{
Expand All @@ -1425,16 +1372,7 @@ d_pushdecl (tree decl)
return decl;
}

void
set_decl_binding_chain (tree decl_chain)
{
gcc_assert (current_binding_level);
current_binding_level->names = decl_chain;
}


// Return the list of declarations of the current level.
// Supports dbx and stabs.

static tree
d_getdecls()
Expand Down Expand Up @@ -1560,7 +1498,7 @@ d_keep (tree t)
d_keep_list = tree_cons (NULL_TREE, t, d_keep_list);
}

tree d_eh_personality_decl;
static GTY(()) tree d_eh_personality_decl;

/* Return the GDC personality function decl. */
static tree
Expand Down
154 changes: 10 additions & 144 deletions gcc/d/d-lang.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,165 +22,32 @@

// Forward type declarations to avoid including unnecessary headers.
class Declaration;
class Expression;
class Module;
class Type;
struct IRState;

/* Nothing is added to tree_identifier; */
struct GTY(()) lang_identifier
{
struct tree_identifier common;
};

/* Global state pertinent to the current function. */
struct GTY(()) language_function
{
IRState * GTY((skip)) irs;
};

/* The D front end types have not been integrated into the GCC garbage
collection system. Handle this by using the "skip" attribute. */
struct GTY(()) lang_decl
{
Declaration * GTY((skip)) d_decl;
};

/* The lang_type field is not set for every GCC type. */
struct GTY(()) lang_type
{
Type * GTY((skip)) d_type;
};

/* Another required, but unused declaration. This could be simplified, since
there is no special lang_identifier */
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON)"
" ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
lang_tree_node
{
union tree_node GTY((tag ("0"),
desc ("tree_node_structure (&%h)"))) generic;
lang_identifier GTY((tag ("1"))) identifier;
};

extern GTY(()) tree d_eh_personality_decl;

/* True if the Tdelegate typed expression is not really a variable,
but a literal function / method reference. */
#define D_METHOD_CALL_EXPR(NODE) (TREE_LANG_FLAG_0 (NODE))

/* True if the type is an imaginary float type. */
#define D_TYPE_IMAGINARY_FLOAT(NODE) (TYPE_LANG_FLAG_1 (TREE_CHECK ((NODE), REAL_TYPE)))

/* True if the symbol should be made "link one only". This is used to
defer calling make_decl_one_only() before the decl has been prepared. */
#define D_DECL_ONE_ONLY(NODE) (DECL_LANG_FLAG_0 (NODE))

/* True if the symbol is a template member. Need to distinguish
between templates and other shared static data so that the latter
is not affected by -femit-templates. */
#define D_DECL_IS_TEMPLATE(NODE) (DECL_LANG_FLAG_1 (NODE))

/* The D front-end does not use the 'binding level' system for a symbol table,
It is only needed to get debugging information for local variables and
otherwise support the backend. */
struct GTY(()) binding_level
{
/* A chain of declarations. These are in the reverse of the order supplied. */
tree names;

/* For each level (except the global one), a chain of BLOCK nodes for
all the levels that were entered and exited one level down. */
tree blocks;

/* The binding level this one is contained in. */
binding_level *level_chain;
};

extern GTY(()) binding_level *current_binding_level;
extern GTY(()) binding_level *global_binding_level;

enum d_tree_index
{
DTI_VTBL_PTR_TYPE,

DTI_BOOL_TYPE,
DTI_CHAR_TYPE,
DTI_WCHAR_TYPE,
DTI_DCHAR_TYPE,

DTI_BYTE_TYPE,
DTI_UBYTE_TYPE,
DTI_SHORT_TYPE,
DTI_USHORT_TYPE,
DTI_INT_TYPE,
DTI_UINT_TYPE,
DTI_LONG_TYPE,
DTI_ULONG_TYPE,
DTI_CENT_TYPE,
DTI_UCENT_TYPE,

DTI_IFLOAT_TYPE,
DTI_IDOUBLE_TYPE,
DTI_IREAL_TYPE,

DTI_UNKNOWN_TYPE,

DTI_MAX
};

extern GTY(()) tree d_global_trees[DTI_MAX];

#define vtbl_ptr_type_node d_global_trees[DTI_VTBL_PTR_TYPE]
#define bool_type_node d_global_trees[DTI_BOOL_TYPE]
#define char8_type_node d_global_trees[DTI_CHAR_TYPE]
#define char16_type_node d_global_trees[DTI_DCHAR_TYPE]
#define char32_type_node d_global_trees[DTI_WCHAR_TYPE]
#define byte_type_node d_global_trees[DTI_BYTE_TYPE]
#define ubyte_type_node d_global_trees[DTI_UBYTE_TYPE]
#define short_type_node d_global_trees[DTI_SHORT_TYPE]
#define ushort_type_node d_global_trees[DTI_USHORT_TYPE]
#define int_type_node d_global_trees[DTI_INT_TYPE]
#define uint_type_node d_global_trees[DTI_UINT_TYPE]
#define long_type_node d_global_trees[DTI_LONG_TYPE]
#define ulong_type_node d_global_trees[DTI_ULONG_TYPE]
#define cent_type_node d_global_trees[DTI_CENT_TYPE]
#define ucent_type_node d_global_trees[DTI_UCENT_TYPE]
#define ifloat_type_node d_global_trees[DTI_IFLOAT_TYPE]
#define idouble_type_node d_global_trees[DTI_IDOUBLE_TYPE]
#define ireal_type_node d_global_trees[DTI_IREAL_TYPE]
#define d_unknown_type_node d_global_trees[DTI_UNKNOWN_TYPE]


/* In d-lang.cc. */

// In d-convert.cc.
tree d_truthvalue_conversion (tree);

// In d-incpath.cc.
extern void add_import_paths(const char *iprefix, const char *imultilib, bool stdinc);

// In d-lang.cc.
void d_add_global_declaration (tree);

class Module;
Module *d_gcc_get_output_module();

struct lang_type *build_d_type_lang_specific (Type *t);
struct lang_decl *build_d_decl_lang_specific (Declaration *d);

/* In d-incpath.cc */
extern void add_import_paths(const char *iprefix, const char *imultilib, bool stdinc);

/* In d-lang.cc */
extern tree d_pushdecl (tree);
extern void push_binding_level();
extern tree pop_binding_level(bool functionbody);

extern void init_global_binding_level();
extern void set_decl_binding_chain (tree decl_chain);

extern tree d_unsigned_type (tree);
extern tree d_signed_type (tree);

extern void d_init_exceptions();

extern void d_keep (tree t);


/* In d-builtins.cc */
// In d-builtins.cc.
extern const attribute_spec d_langhook_attribute_table[];
extern const attribute_spec d_langhook_common_attribute_table[];
extern const attribute_spec d_langhook_format_attribute_table[];
Expand All @@ -191,7 +58,6 @@ void d_register_builtin_type (tree, const char *);
void d_backend_init();
void d_backend_term();

class Expression;
extern Expression *build_expression (tree cst);
extern Type *build_dtype(tree type);

Expand Down
2 changes: 1 addition & 1 deletion gcc/d/d-longdouble.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include "diagnostic.h"
#include "stor-layout.h"

#include "d-lang.h"
#include "d-tree.h"
#include "d-codegen.h"
#include "longdouble.h"

Expand Down
53 changes: 26 additions & 27 deletions gcc/d/d-objfile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
#include "debug.h"
#include "tree-pretty-print.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-objfile.h"
#include "d-irstate.h"
#include "d-codegen.h"
#include "id.h"

Expand Down Expand Up @@ -109,7 +109,7 @@ Dsymbol::toObjFile(bool)
// Get the context of this import, this should never be null.
tree context;
if (cfun != NULL)
context = current_irstate->func->toSymbol()->Stree;
context = current_function_decl;
else
context = current_module_decl->toImport()->Stree;

Expand Down Expand Up @@ -855,17 +855,16 @@ VarDeclaration::toObjFile(bool)
// a check for isVarDeclaration() in DeclarationExp::toElem.
if (!isDataseg() && !isMember())
{
IRState *irs = current_irstate;
build_local_var (this, toParent2()->isFuncDeclaration());
build_local_var (this);

if (init)
{
if (!init->isVoidInitializer())
{
ExpInitializer *vinit = init->isExpInitializer();
Expression *ie = vinit->toExpression();
tree exp = ie->toElem (irs);
irs->addExp (exp);
tree exp = ie->toElem(NULL);
add_stmt(exp);
}
else if (size (loc) != 0)
{
Expand Down Expand Up @@ -1219,7 +1218,7 @@ FuncDeclaration::toObjFile(bool force_p)
allocate_struct_function (fndecl, false);
set_function_end_locus (endloc);

IRState *irs = IRState::startFunction (this);
start_function(this);

tree parm_decl = NULL_TREE;
tree param_list = NULL_TREE;
Expand All @@ -1245,7 +1244,7 @@ FuncDeclaration::toObjFile(bool force_p)

set_decl_location (parm_decl, vthis);
param_list = chainon (param_list, parm_decl);
irs->sthis = parm_decl;
cfun->language->static_chain = parm_decl;
}

// _arguments parameter.
Expand All @@ -1272,9 +1271,9 @@ FuncDeclaration::toObjFile(bool force_p)
rest_of_decl_compilation (fndecl, 1, 0);
DECL_INITIAL (fndecl) = error_mark_node;

irs->pushStatementList();
push_binding_level();
irs->doLineNote (loc);
push_stmt_list();
push_binding_level(level_function);
set_input_location (loc);

// If this is a member function that nested (possibly indirectly) in another
// function, construct an expession for this member function's static chain
Expand All @@ -1293,20 +1292,20 @@ FuncDeclaration::toObjFile(bool force_p)
ad = d->isAggregateDeclaration();
if (ad == NULL)
{
irs->sthis = this_tree;
cfun->language->static_chain = this_tree;
break;
}
}
}

// May change irs->sthis.
build_closure(this, irs);
// May change cfun->static_chain
build_closure(this);

if (vresult)
build_local_var (vresult, this);
build_local_var (vresult);

if (v_argptr)
irs->pushStatementList();
push_stmt_list();

/* The fabled D named return value optimisation.
Implemented by overriding all the RETURN_EXPRs and replacing all
Expand Down Expand Up @@ -1338,27 +1337,27 @@ FuncDeclaration::toObjFile(bool force_p)
nrvsym->SnamedResult = result_decl;
}

build_ir (fbody, irs);
build_ir (this);

if (v_argptr)
{
tree body = irs->popStatementList();
tree var = get_decl_tree (v_argptr, this);
tree body = pop_stmt_list();
tree var = get_decl_tree (v_argptr);
var = build_address (var);

tree init_exp = d_build_call_nary (builtin_decl_explicit (BUILT_IN_VA_START), 2, var, parm_decl);
build_local_var (v_argptr, this);
irs->addExp (init_exp);
build_local_var (v_argptr);
add_stmt(init_exp);

tree cleanup = d_build_call_nary (builtin_decl_explicit (BUILT_IN_VA_END), 1, var);
irs->addExp (build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup));
add_stmt(build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup));
}

// Backend expects a statement list to come from somewhere, however
// popStatementList returns expressions when there is a single statement.
// So here we create a statement list unconditionally.
tree block = pop_binding_level(true);
tree body = irs->popStatementList();
tree block = pop_binding_level();
tree body = pop_stmt_list();
tree bind = build3(BIND_EXPR, void_type_node,
BLOCK_VARS (block), body, block);

Expand Down Expand Up @@ -1408,9 +1407,9 @@ FuncDeclaration::toObjFile(bool force_p)
d_finish_function (this);

// Process all deferred nested functions.
for (size_t i = 0; i < irs->deferred.length(); ++i)
for (size_t i = 0; i < cfun->language->deferred_fns.length(); ++i)
{
FuncDeclaration *fd = irs->deferred[i];
FuncDeclaration *fd = cfun->language->deferred_fns[i];
fd->toObjFile(false);
}

Expand All @@ -1423,7 +1422,7 @@ FuncDeclaration::toObjFile(bool force_p)
}
}

irs->endFunction();
end_function();

current_function_decl = old_current_function_decl;
set_cfun (old_cfun);
Expand Down
1 change: 1 addition & 0 deletions gcc/d/d-target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "tm.h"
#include "tm_p.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-codegen.h"

Expand Down
2 changes: 1 addition & 1 deletion gcc/d/d-todt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "toplev.h"
#include "stor-layout.h"

#include "d-lang.h"
#include "d-tree.h"
#include "d-codegen.h"
#include "d-objfile.h"
#include "d-dmd-gcc.h"
Expand Down
245 changes: 245 additions & 0 deletions gcc/d/d-tree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
// d-tree.h -- D frontend for GCC.
// Copyright (C) 2015 Free Software Foundation, Inc.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.


#ifndef GCC_D_TREE_H
#define GCC_D_TREE_H

// Forward type declarations to avoid including unnecessary headers.
class Declaration;
class FuncDeclaration;
class Module;
class Statement;
class Type;
class VarDeclaration;

// The kinds of scopes we recognise.
enum level_kind
{
level_block = 0, // An ordinary block scope.
level_try, // A try-block.
level_catch, // A catch-block.
level_finally, // A finally-block.
level_cond, // An if-condition.
level_switch, // A switch-block.
level_loop, // A for, do-while, or unrolled-loop block.
level_with, // A with-block.
level_function, // The block representing an entire function.
};

// For use with break and continue statements.
enum bc_kind
{
bc_break = 0,
bc_continue = 1,
};

// The datatype used to implement D scope. It is needed primarily to support
// the backend, but also helps debugging information for local variables.
struct GTY((chain_next ("%h.level_chain"))) binding_level
{
// A chain of declarations. These are in the reverse of the order supplied.
tree names;

// For each level (except the global one), a chain of BLOCK nodes for
// all the levels that were entered and exited one level down.
tree blocks;

// The binding level this one is contained in.
binding_level *level_chain;

// The kind of scope this object represents.
ENUM_BITFIELD (level_kind) kind : 4;
};

extern GTY(()) binding_level *current_binding_level;
extern GTY(()) binding_level *global_binding_level;


// Used only for jumps to as-yet undefined labels, since jumps to
// defined labels can have their validity checked immediately.
struct GTY((chain_next ("%h.next"))) d_label_use_entry
{
d_label_use_entry *next;

// The statement block associated with the jump.
Statement * GTY((skip)) statement;

// The binding level to which this entry is *currently* attached.
// This is initially the binding level in which the goto appeared,
// but is modified as scopes are closed.
binding_level *level;
};

struct GTY(()) d_label_entry
{
// The label decl itself.
tree label;

// The statement block associated with the label.
Statement * GTY((skip)) statement;

// The binding level to which this entry is *currently* attached.
// This is initially the binding level in which the label is defined,
// but is modified as scopes are closed.
binding_level *level;

// A list of forward references of the label.
d_label_use_entry *fwdrefs;

// The following bits are set after the label is defined, and are
// updated as scopes are popped. They indicate that a backward jump
// to the label will illegally enter a scope of the given flavor.
bool in_try_scope;
bool in_catch_scope;

// If set, the label we reference represents a break/continue pair.
bool bc_label;
};


// Nothing is added to tree_identifier.
struct GTY(()) lang_identifier
{
struct tree_identifier common;
};

// Global state pertinent to the current function.
struct GTY(()) language_function
{
// Our function and enclosing module.
FuncDeclaration * GTY((skip)) function;
Module * GTY((skip)) module;

// Static chain of function, for D2, this is a closure.
tree static_chain;

// Stack of statement lists being collected while we are
// compiling the function.
vec<tree, va_gc> *stmt_list;

// Any nested functions that were deferred during codegen.
vec<FuncDeclaration *> GTY((skip)) deferred_fns;

// Variables that are in scope that will need destruction later.
vec<VarDeclaration *> GTY((skip)) vars_in_scope;

// Table of all used or defined labels in the function.
hash_map<Statement *, d_label_entry> *labels;
};

This comment has been minimized.

Copy link
@jpf91

jpf91 Aug 11, 2015

Author Contributor

@ibuclaw I've got some problems backporting this hash_map. GCC < 5 doesn't have a hash_map. The pointer_map should work, but it doesn't provide a remove function. I think I can just set the values to NULL instead. This will require some changes, but it should work. pointer_map is also not integrated into the GCC garbage collector. If I mark labels as GTY((skip)) I'll have to allocate these manually instead of using ggc_alloc, right? AFAICS I can free the d_label_entry in pop_label?

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 11, 2015

Member

You can use hash_table as a suitable alternative. You'd have to provide a descriptor struct for providing hash and equality checks.

Something like:

// Hash map helper
struct d_label_hasher : typed_free_remove<d_label_entry>
{
  static inline hashval_t hash (const d_label_entry *);
  static inline bool equal (const d_label_entry *, const d_label_entry *);
}

// Hash a label statement in a d_label_entry
inline hashval_t
d_label_hasher::hash(const d_label_entry *label)
{
  return (hashval_t) ((intptr_t)label->statement >> 3);
}

// Return true if the statement in both d_label_entry's are equal.
inline bool
d_label_hasher::equal(const d_label_entry *a, const d_label_entry *b)
{
  return (a->statement == b->statement);
}

// ...
struct GTY(()) language_function
{
  // ...
  hash_table<d_label_hasher, d_label_entry> labels;
};

Note that the field is not a pointer, so needs no extra ggc allocation.

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 11, 2015

Member

NB: I did something similar to this initially, until I discovered that moving every GTY struct into one header solved all weirdities I was getting from gengtype and linking the compiler proper. (I tried to get hash_map working, failed, did it in this way, then switched back to hash_map post moving all structs to d-tree.h)

This comment has been minimized.

Copy link
@jpf91

jpf91 Aug 11, 2015

Author Contributor

I guess I'll have to read some GCC GC docs. Are you sure that hash_table has got GC support? I get this error:

./gtype-d.h: In function 'void gt_ggc_mx_language_function(void*)':
./gtype-d.h:46:32: error: no matching function for call to 'gt_ggc_mx(hash_table<d_label_hasher>*)'
       gt_ggc_mx (&((*x).labels));

And there's not a single GTY in hash-table.h

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 11, 2015

Member

Hmm... looking at some older code, maybe htab_t (from hashtab.h) is the only viable alternative.

Same code, but with a different interface:

// d-tree.h
// ...
struct GTY(()) language_function
{
  // ...
  htab_t GTY((param_is(d_label_entry))) labels;   // might need 'struct d_label_entry'
};

// d-codegen.cc
// Hash and equality functions for the d_label_entry table.
static hashval_t
d_label_entry_hash (const void *data)
{
  const d_label_entry *label = (const d_label_entry *) data;
  return (hashval_t) ((intptr_t)label->statement >> 3);
}

static int
d_label_entry_equal (const void *a, const void *b)
{
  const d_label_entry *label_a = (const d_label_entry *) a;
  const d_label_entry *label_b = (const d_label_entry *) b;
  return (label_a->statement == label_b->statement);
}

// ...
tree
lookup_label(Statement *s, Identifier *ident)
{
  // ...
  // Create the label htab for the function on demand.
  if (!cfun->language->labels)
    cfun->language->labels = htab_create_ggc(13, d_label_entry_hash,
                                             d_label_entry_equal, NULL);

  d_label_entry search;
  search.statement = s;
  void **slot = htab_find_slot(cfun->language->labels, &search, NO_INSERT);
  if (*slot != NULL)
    return ((d_label_entry *) *slot)->label;
  else
    {
      // ...
      d_label_entry *ent = ggc_alloc_cleared_d_label_entry();
      ent->statement = s;
      ent->label = decl;

      slot = htab_find_slot(cfun->language->labels, ent, INSERT);
      gcc_assert(*slot == NULL);
      *slot = ent;

      return decl;
    }

This is just making a quick guess-work though...

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 11, 2015

Member

And there's not a single GTY in hash-table.h

In gcc-5 and later, there are gt_* methods defined that provide for what you see as missing symbols in gcc-4.9 and earlier.

This comment has been minimized.

Copy link
@jpf91

jpf91 Aug 12, 2015

Author Contributor

Hmm... looking at some older code, maybe htab_t (from hashtab.h) is the only viable alternative.

Yet another hashtable ;-) Seems to be working with this, but would be great if you could do a quick review: jpf91@83983bb
I think there's no way to easily review merge commits on github. git show 83983bb produces more useful output.

BTW: Which code conventions are we using right now? Whitespace after function name before parenthesis? Whitespace after parenthesis for casts?

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 12, 2015

Member

The one I'm pushing for in my changes are:

MACRO_ACCESSOR (obj);  // space between macro and parenthesis.
function_call(obj);    // no space between functions and parenthesis.
((Cast *) obj)->foo;   // space between closing cast parenthesis and object

The only change has been to function calls, where there was a mix between:

some_call (foo)->bar()->baz (42);

Which was just bad...

This comment has been minimized.

Copy link
@jpf91

jpf91 Aug 12, 2015

Author Contributor

But for example in d-codegen.cc we have this:

int
pop_binding_label(void **slot, void *arg)
{
}

tree
build_local_temp (tree type)
{
}

I guess the new style is 'no space'?

This comment has been minimized.

Copy link
@ibuclaw

ibuclaw Aug 12, 2015

Member

Yes. Because of manpower, I'm only updating them as and when I write new code. :-)


// The D front end types have not been integrated into the GCC garbage
// collection system. Handle this by using the "skip" attribute. */
struct GTY(()) lang_decl
{
Declaration * GTY((skip)) d_decl;
};

// The lang_type field is not set for every GCC type.
struct GTY(()) lang_type
{
Type * GTY((skip)) d_type;
};

// Another required, but unused declaration. This could be simplified, since
// there is no special lang_identifier.
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON)"
" ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
lang_tree_node
{
union tree_node GTY((tag ("0"),
desc ("tree_node_structure (&%h)"))) generic;
lang_identifier GTY((tag ("1"))) identifier;
};

// True if the Tdelegate typed expression is not really a variable,
// but a literal function / method reference.
#define D_METHOD_CALL_EXPR(NODE) \
(TREE_LANG_FLAG_0 (NODE))

// True if the type is an imaginary float type.
#define D_TYPE_IMAGINARY_FLOAT(NODE) \
(TYPE_LANG_FLAG_1 (TREE_CHECK ((NODE), REAL_TYPE)))

// True if the symbol should be made "link one only". This is used to
// defer calling make_decl_one_only() before the decl has been prepared.
#define D_DECL_ONE_ONLY(NODE) \
(DECL_LANG_FLAG_0 (NODE))

// True if the symbol is a template member. Need to distinguish
// between templates and other shared static data so that the latter
// is not affected by -femit-templates.
#define D_DECL_IS_TEMPLATE(NODE) \
(DECL_LANG_FLAG_1 (NODE))

// True if the decl is a variable case label decl.
#define D_LABEL_VARIABLE_CASE(NODE) \
(DECL_LANG_FLAG_2 (LABEL_DECL_CHECK (NODE)))

enum d_tree_index
{
DTI_VTBL_PTR_TYPE,

DTI_BOOL_TYPE,
DTI_CHAR_TYPE,
DTI_WCHAR_TYPE,
DTI_DCHAR_TYPE,

DTI_BYTE_TYPE,
DTI_UBYTE_TYPE,
DTI_SHORT_TYPE,
DTI_USHORT_TYPE,
DTI_INT_TYPE,
DTI_UINT_TYPE,
DTI_LONG_TYPE,
DTI_ULONG_TYPE,
DTI_CENT_TYPE,
DTI_UCENT_TYPE,

DTI_IFLOAT_TYPE,
DTI_IDOUBLE_TYPE,
DTI_IREAL_TYPE,

DTI_UNKNOWN_TYPE,

DTI_MAX
};

extern GTY(()) tree d_global_trees[DTI_MAX];

#define vtbl_ptr_type_node d_global_trees[DTI_VTBL_PTR_TYPE]
#define bool_type_node d_global_trees[DTI_BOOL_TYPE]
#define char8_type_node d_global_trees[DTI_CHAR_TYPE]
#define char16_type_node d_global_trees[DTI_DCHAR_TYPE]
#define char32_type_node d_global_trees[DTI_WCHAR_TYPE]
#define byte_type_node d_global_trees[DTI_BYTE_TYPE]
#define ubyte_type_node d_global_trees[DTI_UBYTE_TYPE]
#define short_type_node d_global_trees[DTI_SHORT_TYPE]
#define ushort_type_node d_global_trees[DTI_USHORT_TYPE]
#define int_type_node d_global_trees[DTI_INT_TYPE]
#define uint_type_node d_global_trees[DTI_UINT_TYPE]
#define long_type_node d_global_trees[DTI_LONG_TYPE]
#define ulong_type_node d_global_trees[DTI_ULONG_TYPE]
#define cent_type_node d_global_trees[DTI_CENT_TYPE]
#define ucent_type_node d_global_trees[DTI_UCENT_TYPE]
#define ifloat_type_node d_global_trees[DTI_IFLOAT_TYPE]
#define idouble_type_node d_global_trees[DTI_IDOUBLE_TYPE]
#define ireal_type_node d_global_trees[DTI_IREAL_TYPE]
#define d_unknown_type_node d_global_trees[DTI_UNKNOWN_TYPE]

#endif
4 changes: 1 addition & 3 deletions gcc/d/dfrontend/arraytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ typedef Array<class GotoStatement *> GotoStatements;

typedef Array<class TemplateInstance *> TemplateInstances;

#ifdef IN_GCC
typedef Array<struct Label *> Blocks;
#else
#ifndef IN_GCC
typedef Array<struct block *> Blocks;
#endif

Expand Down
7 changes: 4 additions & 3 deletions gcc/d/dfrontend/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -3281,7 +3281,9 @@ CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
this->exp = exp;
this->statement = s;
index = 0;
#ifndef IN_GCC
cblock = NULL;
#endif
}

Statement *CaseStatement::syntaxCopy()
Expand Down Expand Up @@ -3471,9 +3473,6 @@ DefaultStatement::DefaultStatement(Loc loc, Statement *s)
: Statement(loc)
{
this->statement = s;
#ifdef IN_GCC
cblock = NULL;
#endif
}

Statement *DefaultStatement::syntaxCopy()
Expand Down Expand Up @@ -4918,8 +4917,10 @@ LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
this->os = NULL;
this->gotoTarget = NULL;
this->lastVar = NULL;
#ifndef IN_GCC
this->lblock = NULL;
this->fwdrefs = NULL;
#endif
}

Statement *LabelStatement::syntaxCopy()
Expand Down
7 changes: 4 additions & 3 deletions gcc/d/dfrontend/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,9 @@ class CaseStatement : public Statement
Statement *statement;

int index; // which case it is (since we sort this)
#ifndef IN_GCC
block *cblock; // back end: label for the block
#endif

CaseStatement(Loc loc, Expression *exp, Statement *s);
Statement *syntaxCopy();
Expand Down Expand Up @@ -476,9 +478,6 @@ class DefaultStatement : public Statement
{
public:
Statement *statement;
#ifdef IN_GCC
block *cblock; // back end: label for the block
#endif

DefaultStatement(Loc loc, Statement *s);
Statement *syntaxCopy();
Expand Down Expand Up @@ -703,9 +702,11 @@ class LabelStatement : public Statement
OnScopeStatement *os;
Statement *gotoTarget; // interpret
VarDeclaration *lastVar;
#ifndef IN_GCC
block *lblock; // back end

Blocks *fwdrefs; // forward references to this LabelStatement
#endif

LabelStatement(Loc loc, Identifier *ident, Statement *statement);
Statement *syntaxCopy();
Expand Down
542 changes: 378 additions & 164 deletions gcc/d/toir.cc

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions gcc/d/types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "stor-layout.h"
#include "attribs.h"

#include "d-tree.h"
#include "d-lang.h"
#include "d-codegen.h"
#include "d-objfile.h"
Expand Down