d: Move private functions out of ExprVisitor into local statics

None of these functions need access to the context pointer of the
visitor class, so have been made free standing.

gcc/d/ChangeLog:

	* expr.cc (needs_postblit): Move out of ExprVisitor as a static
	function.  Update all callers.
	(needs_dtor): Likewise.
	(lvalue_p): Likewise.
	(binary_op): Likewise.
	(binop_assignment): Likewise.
This commit is contained in:
Iain Buclaw 2020-07-16 14:02:24 +02:00
parent 561a19c301
commit dc60d67674
1 changed files with 178 additions and 173 deletions

View File

@ -43,6 +43,174 @@ along with GCC; see the file COPYING3. If not see
#include "d-tree.h" #include "d-tree.h"
/* Determine if type T is a struct that has a postblit. */
static bool
needs_postblit (Type *t)
{
t = t->baseElemOf ();
if (TypeStruct *ts = t->isTypeStruct ())
{
if (ts->sym->postblit)
return true;
}
return false;
}
/* Determine if type T is a struct that has a destructor. */
static bool
needs_dtor (Type *t)
{
t = t->baseElemOf ();
if (TypeStruct *ts = t->isTypeStruct ())
{
if (ts->sym->dtor)
return true;
}
return false;
}
/* Determine if expression E is a suitable lvalue. */
static bool
lvalue_p (Expression *e)
{
SliceExp *se = e->isSliceExp ();
if (se != NULL && se->e1->isLvalue ())
return true;
CastExp *ce = e->isCastExp ();
if (ce != NULL && ce->e1->isLvalue ())
return true;
return (e->op != TOKslice && e->isLvalue ());
}
/* Build an expression of code CODE, data type TYPE, and operands ARG0 and
ARG1. Perform relevant conversions needed for correct code operations. */
static tree
binary_op (tree_code code, tree type, tree arg0, tree arg1)
{
tree t0 = TREE_TYPE (arg0);
tree t1 = TREE_TYPE (arg1);
tree ret = NULL_TREE;
bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1);
/* Deal with float mod expressions immediately. */
if (code == FLOAT_MOD_EXPR)
return build_float_modulus (type, arg0, arg1);
if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1))
return build_nop (type, build_offset_op (code, arg0, arg1));
if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1))
return build_nop (type, build_offset_op (code, arg1, arg0));
if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1))
{
gcc_assert (code == MINUS_EXPR);
tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode, 0);
/* POINTER_DIFF_EXPR requires a signed integer type of the same size as
pointers. If some platform cannot provide that, or has a larger
ptrdiff_type to support differences larger than half the address
space, cast the pointers to some larger integer type and do the
computations in that type. */
if (TYPE_PRECISION (ptrtype) > TYPE_PRECISION (t0))
ret = fold_build2 (MINUS_EXPR, ptrtype,
d_convert (ptrtype, arg0),
d_convert (ptrtype, arg1));
else
ret = fold_build2 (POINTER_DIFF_EXPR, ptrtype, arg0, arg1);
}
else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp))
{
tree inttype = (unsignedp)
? d_unsigned_type (type) : d_signed_type (type);
ret = fold_build2 (code, inttype, arg0, arg1);
}
else
{
/* If the operation needs excess precision. */
tree eptype = excess_precision_type (type);
if (eptype != NULL_TREE)
{
arg0 = d_convert (eptype, arg0);
arg1 = d_convert (eptype, arg1);
}
else
{
/* Front-end does not do this conversion and GCC does not
always do it right. */
if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1))
arg1 = d_convert (t0, arg1);
else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0))
arg0 = d_convert (t1, arg0);
eptype = type;
}
ret = fold_build2 (code, eptype, arg0, arg1);
}
return d_convert (type, ret);
}
/* Build a binary expression of code CODE, assigning the result into E1. */
static tree
binop_assignment (tree_code code, Expression *e1, Expression *e2)
{
/* Skip casts for lhs assignment. */
Expression *e1b = e1;
while (e1b->op == TOKcast)
{
CastExp *ce = e1b->isCastExp ();
gcc_assert (same_type_p (ce->type, ce->to));
e1b = ce->e1;
}
/* Stabilize LHS for assignment. */
tree lhs = build_expr (e1b);
tree lexpr = stabilize_expr (&lhs);
/* The LHS expression could be an assignment, to which its operation gets
lost during gimplification. */
if (TREE_CODE (lhs) == MODIFY_EXPR)
{
/* If LHS has side effects, call stabilize_reference on it, so it can
be evaluated multiple times. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build_assign (MODIFY_EXPR,
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
lexpr = compound_expr (lexpr, lhs);
lhs = TREE_OPERAND (lhs, 0);
}
lhs = stabilize_reference (lhs);
/* Save RHS, to ensure that the expression is evaluated before LHS. */
tree rhs = build_expr (e2);
tree rexpr = d_save_expr (rhs);
rhs = binary_op (code, build_ctype (e1->type),
convert_expr (lhs, e1b->type, e1->type), rexpr);
if (TREE_SIDE_EFFECTS (rhs))
rhs = compound_expr (rexpr, rhs);
tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type));
return compound_expr (lexpr, expr);
}
/* Implements the visitor interface to build the GCC trees of all Expression /* Implements the visitor interface to build the GCC trees of all Expression
AST classes emitted from the D Front-end. AST classes emitted from the D Front-end.
All visit methods accept one parameter E, which holds the frontend AST All visit methods accept one parameter E, which holds the frontend AST
@ -56,169 +224,6 @@ class ExprVisitor : public Visitor
tree result_; tree result_;
bool constp_; bool constp_;
/* Determine if type is a struct that has a postblit. */
bool needs_postblit (Type *t)
{
t = t->baseElemOf ();
if (TypeStruct *ts = t->isTypeStruct ())
{
if (ts->sym->postblit)
return true;
}
return false;
}
/* Determine if type is a struct that has a destructor. */
bool needs_dtor (Type *t)
{
t = t->baseElemOf ();
if (TypeStruct *ts = t->isTypeStruct ())
{
if (ts->sym->dtor)
return true;
}
return false;
}
/* Determine if expression is suitable lvalue. */
bool lvalue_p (Expression *e)
{
SliceExp *se = e->isSliceExp ();
if (se != NULL && se->e1->isLvalue ())
return true;
CastExp *ce = e->isCastExp ();
if (ce != NULL && ce->e1->isLvalue ())
return true;
return (e->op != TOKslice && e->isLvalue ());
}
/* Build an expression of code CODE, data type TYPE, and operands ARG0 and
ARG1. Perform relevant conversions needed for correct code operations. */
tree binary_op (tree_code code, tree type, tree arg0, tree arg1)
{
tree t0 = TREE_TYPE (arg0);
tree t1 = TREE_TYPE (arg1);
tree ret = NULL_TREE;
bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1);
/* Deal with float mod expressions immediately. */
if (code == FLOAT_MOD_EXPR)
return build_float_modulus (type, arg0, arg1);
if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1))
return build_nop (type, build_offset_op (code, arg0, arg1));
if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1))
return build_nop (type, build_offset_op (code, arg1, arg0));
if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1))
{
gcc_assert (code == MINUS_EXPR);
tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode, 0);
/* POINTER_DIFF_EXPR requires a signed integer type of the same size as
pointers. If some platform cannot provide that, or has a larger
ptrdiff_type to support differences larger than half the address
space, cast the pointers to some larger integer type and do the
computations in that type. */
if (TYPE_PRECISION (ptrtype) > TYPE_PRECISION (t0))
ret = fold_build2 (MINUS_EXPR, ptrtype,
d_convert (ptrtype, arg0),
d_convert (ptrtype, arg1));
else
ret = fold_build2 (POINTER_DIFF_EXPR, ptrtype, arg0, arg1);
}
else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp))
{
tree inttype = (unsignedp)
? d_unsigned_type (type) : d_signed_type (type);
ret = fold_build2 (code, inttype, arg0, arg1);
}
else
{
/* If the operation needs excess precision. */
tree eptype = excess_precision_type (type);
if (eptype != NULL_TREE)
{
arg0 = d_convert (eptype, arg0);
arg1 = d_convert (eptype, arg1);
}
else
{
/* Front-end does not do this conversion and GCC does not
always do it right. */
if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1))
arg1 = d_convert (t0, arg1);
else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0))
arg0 = d_convert (t1, arg0);
eptype = type;
}
ret = fold_build2 (code, eptype, arg0, arg1);
}
return d_convert (type, ret);
}
/* Build a binary expression of code CODE, assigning the result into E1. */
tree binop_assignment (tree_code code, Expression *e1, Expression *e2)
{
/* Skip casts for lhs assignment. */
Expression *e1b = e1;
while (e1b->op == TOKcast)
{
CastExp *ce = e1b->isCastExp ();
gcc_assert (same_type_p (ce->type, ce->to));
e1b = ce->e1;
}
/* Stabilize LHS for assignment. */
tree lhs = build_expr (e1b);
tree lexpr = stabilize_expr (&lhs);
/* The LHS expression could be an assignment, to which its operation gets
lost during gimplification. */
if (TREE_CODE (lhs) == MODIFY_EXPR)
{
/* If LHS has side effects, call stabilize_reference on it, so it can
be evaluated multiple times. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build_assign (MODIFY_EXPR,
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
lexpr = compound_expr (lexpr, lhs);
lhs = TREE_OPERAND (lhs, 0);
}
lhs = stabilize_reference (lhs);
/* Save RHS, to ensure that the expression is evaluated before LHS. */
tree rhs = build_expr (e2);
tree rexpr = d_save_expr (rhs);
rhs = this->binary_op (code, build_ctype (e1->type),
convert_expr (lhs, e1b->type, e1->type), rexpr);
if (TREE_SIDE_EFFECTS (rhs))
rhs = compound_expr (rexpr, rhs);
tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type));
return compound_expr (lexpr, expr);
}
public: public:
ExprVisitor (bool constp) ExprVisitor (bool constp)
{ {
@ -653,8 +658,8 @@ public:
gcc_unreachable (); gcc_unreachable ();
} }
this->result_ = this->binary_op (code, build_ctype (e->type), this->result_ = binary_op (code, build_ctype (e->type),
build_expr (e->e1), build_expr (e->e2)); build_expr (e->e1), build_expr (e->e2));
} }
@ -807,7 +812,7 @@ public:
gcc_unreachable (); gcc_unreachable ();
} }
tree exp = this->binop_assignment (code, e1b, e->e2); tree exp = binop_assignment (code, e1b, e->e2);
this->result_ = convert_expr (exp, e1b->type, e->type); this->result_ = convert_expr (exp, e1b->type, e->type);
} }
@ -915,8 +920,8 @@ public:
Type *etype = stype->nextOf ()->toBasetype (); Type *etype = stype->nextOf ()->toBasetype ();
/* Determine if we need to run postblit or dtor. */ /* Determine if we need to run postblit or dtor. */
bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2); bool postblit = needs_postblit (etype) && lvalue_p (e->e2);
bool destructor = this->needs_dtor (etype); bool destructor = needs_dtor (etype);
if (e->memset & blockAssign) if (e->memset & blockAssign)
{ {
@ -1098,15 +1103,15 @@ public:
gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray); gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
/* Determine if we need to run postblit. */ /* Determine if we need to run postblit. */
bool postblit = this->needs_postblit (etype); bool postblit = needs_postblit (etype);
bool destructor = this->needs_dtor (etype); bool destructor = needs_dtor (etype);
bool lvalue_p = this->lvalue_p (e->e2); bool lvalue = lvalue_p (e->e2);
/* Even if the elements in rhs are all rvalues and don't have /* Even if the elements in rhs are all rvalues and don't have
to call postblits, this assignment should call dtors on old to call postblits, this assignment should call dtors on old
assigned elements. */ assigned elements. */
if ((!postblit && !destructor) if ((!postblit && !destructor)
|| (e->op == TOKconstruct && !lvalue_p && postblit) || (e->op == TOKconstruct && !lvalue && postblit)
|| (e->op == TOKblit || e->e1->type->size () == 0)) || (e->op == TOKblit || e->e1->type->size () == 0))
{ {
tree t1 = build_expr (e->e1); tree t1 = build_expr (e->e1);
@ -1132,7 +1137,7 @@ public:
{ {
/* Generate: _d_arrayassign_l() /* Generate: _d_arrayassign_l()
or: _d_arrayassign_r() */ or: _d_arrayassign_r() */
libcall_fn libcall = (lvalue_p) libcall_fn libcall = (lvalue)
? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
tree elembuf = build_local_temp (build_ctype (etype)); tree elembuf = build_local_temp (build_ctype (etype));