/gcc/d/expr.cc
C++ | 3125 lines | 2171 code | 525 blank | 429 comment | 614 complexity | ccf9a32e649ddf1cd5a460bac888f711 MD5 | raw file
Possible License(s): AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /* expr.cc -- Lower D frontend expressions to GCC trees.
- Copyright (C) 2015-2018 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/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "dmd/aggregate.h"
- #include "dmd/ctfe.h"
- #include "dmd/declaration.h"
- #include "dmd/expression.h"
- #include "dmd/identifier.h"
- #include "dmd/init.h"
- #include "dmd/module.h"
- #include "dmd/mtype.h"
- #include "dmd/template.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "diagnostic.h"
- #include "langhooks.h"
- #include "tm.h"
- #include "function.h"
- #include "toplev.h"
- #include "varasm.h"
- #include "predict.h"
- #include "stor-layout.h"
- #include "d-tree.h"
- /* Implements the visitor interface to build the GCC trees of all Expression
- AST classes emitted from the D Front-end.
- All visit methods accept one parameter E, which holds the frontend AST
- of the expression to compile. They also don't return any value, instead
- generated code is cached in RESULT_ and returned from the caller. */
- class ExprVisitor : public Visitor
- {
- using Visitor::visit;
- tree result_;
- bool constp_;
- /* Determine if type is a struct that has a postblit. */
- bool needs_postblit (Type *t)
- {
- t = t->baseElemOf ();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *) t)->sym;
- if (sd->postblit)
- return true;
- }
- return false;
- }
- /* Determine if type is a struct that has a destructor. */
- bool needs_dtor (Type *t)
- {
- t = t->baseElemOf ();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *) t)->sym;
- if (sd->dtor)
- return true;
- }
- return false;
- }
- /* Determine if expression is suitable lvalue. */
- bool lvalue_p (Expression *e)
- {
- return ((e->op != TOKslice && e->isLvalue ())
- || (e->op == TOKslice && ((UnaExp *) e)->e1->isLvalue ())
- || (e->op == TOKcast && ((UnaExp *) e)->e1->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 = (CastExp *) e1b;
- 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:
- ExprVisitor (bool constp)
- {
- this->result_ = NULL_TREE;
- this->constp_ = constp;
- }
- tree result (void)
- {
- return this->result_;
- }
- /* Visitor interfaces, each Expression class should have
- overridden the default. */
- void visit (Expression *)
- {
- gcc_unreachable ();
- }
- /* Build a conditional expression. If either the second or third
- expression is void, then the resulting type is void. Otherwise
- they are implicitly converted to a common type. */
- void visit (CondExp *e)
- {
- tree cond = convert_for_condition (build_expr (e->econd),
- e->econd->type);
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- if (e->type->ty != Tvoid)
- {
- t1 = convert_expr (t1, e->e1->type, e->type);
- t2 = convert_expr (t2, e->e2->type, e->type);
- }
- this->result_ = build_condition (build_ctype (e->type), cond, t1, t2);
- }
- /* Build an identity comparison expression. Operands go through the
- usual conversions to bring them to a common type before comparison.
- The result type is bool. */
- void visit (IdentityExp *e)
- {
- tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
- {
- /* For static and dynamic arrays, identity is defined as referring to
- the same array elements and the same number of elements. */
- tree t1 = d_array_convert (e->e1);
- tree t2 = d_array_convert (e->e2);
- this->result_ = d_convert (build_ctype (e->type),
- build_boolop (code, t1, t2));
- }
- else if (tb1->isfloating () && tb1->ty != Tvector)
- {
- /* For floating-point values, identity is defined as the bits in the
- operands being identical. */
- tree t1 = d_save_expr (build_expr (e->e1));
- tree t2 = d_save_expr (build_expr (e->e2));
- tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
- tree size = size_int (TYPE_PRECISION (TREE_TYPE (t1)) / BITS_PER_UNIT);
- tree result = build_call_expr (tmemcmp, 3, build_address (t1),
- build_address (t2), size);
- this->result_ = build_boolop (code, result, integer_zero_node);
- }
- else if (tb1->ty == Tstruct)
- {
- /* For struct objects, identity is defined as bits in operands being
- identical also. Alignment holes in structs are ignored. */
- StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- gcc_assert (same_type_p (tb1, tb2));
- this->result_ = build_struct_comparison (code, sd, t1, t2);
- }
- else
- {
- /* For operands of other types, identity is defined as being the
- same as equality expressions. */
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- this->result_ = d_convert (build_ctype (e->type),
- build_boolop (code, t1, t2));
- }
- }
- /* Build an equality expression, which compare the two operands for either
- equality or inequality. Operands go through the usual conversions to bring
- them to a common type before comparison. The result type is bool. */
- void visit (EqualExp *e)
- {
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
- {
- /* For static and dynamic arrays, equality is defined as the lengths of
- the arrays matching, and all the elements are equal. */
- Type *t1elem = tb1->nextOf ()->toBasetype ();
- Type *t2elem = tb1->nextOf ()->toBasetype ();
- /* Check if comparisons of arrays can be optimized using memcmp.
- This will inline EQ expressions as:
- e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
- Or when generating a NE expression:
- e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */
- if ((t1elem->isintegral () || t1elem->ty == Tvoid
- || (t1elem->ty == Tstruct && !((TypeStruct *)t1elem)->sym->xeq))
- && t1elem->ty == t2elem->ty)
- {
- tree t1 = d_array_convert (e->e1);
- tree t2 = d_array_convert (e->e2);
- tree result;
- /* Make temporaries to prevent multiple evaluations. */
- tree t1saved = d_save_expr (t1);
- tree t2saved = d_save_expr (t2);
- /* Length of arrays, for comparisons done before calling memcmp. */
- tree t1len = d_array_length (t1saved);
- tree t2len = d_array_length (t2saved);
- /* Reference to array data. */
- tree t1ptr = d_array_ptr (t1saved);
- tree t2ptr = d_array_ptr (t2saved);
- /* Compare arrays using memcmp if possible, otherwise for structs,
- each field is compared inline. */
- if (t1elem->ty != Tstruct
- || identity_compare_p (((TypeStruct *) t1elem)->sym))
- {
- tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
- tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
- result = build_call_expr (tmemcmp, 3, t1ptr, t2ptr, size);
- result = build_boolop (code, result, integer_zero_node);
- }
- else
- {
- StructDeclaration *sd = ((TypeStruct *) t1elem)->sym;
- result = build_array_struct_comparison (code, sd, t1len,
- t1ptr, t2ptr);
- }
- /* Check array length first before passing to memcmp.
- For equality expressions, this becomes:
- (e1.length == 0 || memcmp);
- Otherwise for inequality:
- (e1.length != 0 && memcmp); */
- tree tsizecmp = build_boolop (code, t1len, size_zero_node);
- if (e->op == TOKequal)
- result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
- else
- result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
- /* Finally, check if lengths of both arrays match if dynamic.
- The frontend should have already guaranteed that static arrays
- have same size. */
- if (tb1->ty == Tsarray && tb2->ty == Tsarray)
- gcc_assert (tb1->size () == tb2->size ());
- else
- {
- tree tlencmp = build_boolop (code, t1len, t2len);
- if (e->op == TOKequal)
- result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
- else
- result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
- }
- /* Ensure left-to-right order of evaluation. */
- if (TREE_SIDE_EFFECTS (t2))
- result = compound_expr (t2saved, result);
- if (TREE_SIDE_EFFECTS (t1))
- result = compound_expr (t1saved, result);
- this->result_ = result;
- }
- else
- {
- /* Use _adEq2() to compare each element. */
- Type *t1array = t1elem->arrayOf ();
- tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
- d_array_convert (e->e1),
- d_array_convert (e->e2),
- build_typeinfo (e->loc, t1array));
- if (e->op == TOKnotequal)
- result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
- this->result_ = result;
- }
- }
- else if (tb1->ty == Tstruct)
- {
- /* Equality for struct objects means the logical product of all
- equality results of the corresponding object fields. */
- StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- gcc_assert (same_type_p (tb1, tb2));
- this->result_ = build_struct_comparison (code, sd, t1, t2);
- }
- else if (tb1->ty == Taarray && tb2->ty == Taarray)
- {
- /* Use _aaEqual() for associative arrays. */
- TypeAArray *taa1 = (TypeAArray *) tb1;
- tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
- build_typeinfo (e->loc, taa1),
- build_expr (e->e1),
- build_expr (e->e2));
- if (e->op == TOKnotequal)
- result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
- this->result_ = result;
- }
- else
- {
- /* For operands of other types, equality is defined as the bit pattern
- of the type matches exactly. */
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- this->result_ = d_convert (build_ctype (e->type),
- build_boolop (code, t1, t2));
- }
- }
- /* Build an `in' expression. This is a condition to see if an element
- exists in an associative array. The result is a pointer to the
- element, or null if false. */
- void visit (InExp *e)
- {
- Type *tb2 = e->e2->type->toBasetype ();
- gcc_assert (tb2->ty == Taarray);
- Type *tkey = ((TypeAArray *) tb2)->index->toBasetype ();
- tree key = convert_expr (build_expr (e->e1), e->e1->type, tkey);
- /* Build a call to _aaInX(). */
- this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3,
- build_expr (e->e2),
- build_typeinfo (e->loc, tkey),
- build_address (key));
- }
- /* Build a relational expression. The result type is bool. */
- void visit (CmpExp *e)
- {
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- tree result;
- tree_code code;
- switch (e->op)
- {
- case TOKle:
- code = LE_EXPR;
- break;
- case TOKlt:
- code = LT_EXPR;
- break;
- case TOKge:
- code = GE_EXPR;
- break;
- case TOKgt:
- code = GT_EXPR;
- break;
- default:
- gcc_unreachable ();
- }
- /* For static and dynamic arrays, the relational op is turned into a
- library call. It is not lowered during codegen. */
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
- {
- error ("cannot handle comparison of type %<%s == %s%>",
- tb1->toChars (), tb2->toChars ());
- gcc_unreachable ();
- }
- /* Simple comparison. */
- result = build_boolop (code, build_expr (e->e1), build_expr (e->e2));
- this->result_ = d_convert (build_ctype (e->type), result);
- }
- /* Build a logical `and if' or `or if' expression. If the right operand
- expression is void, then the resulting type is void. Otherwise the
- result is bool. */
- void visit (LogicalExp *e)
- {
- tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
- if (e->e2->type->toBasetype ()->ty != Tvoid)
- {
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- t1 = convert_for_condition (t1, e->e1->type);
- t2 = convert_for_condition (t2, e->e2->type);
- this->result_ = d_convert (build_ctype (e->type),
- build_boolop (code, t1, t2));
- }
- else
- {
- tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
- tree t2 = build_expr_dtor (e->e2);
- /* Invert condition for logical or if expression. */
- if (e->op == TOKoror)
- t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1);
- this->result_ = build_condition (build_ctype (e->type),
- t1, t2, void_node);
- }
- }
- /* Build a binary operand expression. Operands go through usual arithmetic
- conversions to bring them to a common type before evaluating. */
- void visit (BinExp *e)
- {
- tree_code code;
- switch (e->op)
- {
- case TOKadd:
- case TOKmin:
- if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
- || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
- {
- /* If the result is complex, then we can shortcut binary_op.
- Frontend should have already validated types and sizes. */
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- if (e->op == TOKmin)
- t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
- if (e->e1->type->isreal ())
- this->result_ = complex_expr (build_ctype (e->type), t1, t2);
- else
- this->result_ = complex_expr (build_ctype (e->type), t2, t1);
- return;
- }
- else
- code = (e->op == TOKadd)
- ? PLUS_EXPR : MINUS_EXPR;
- break;
- case TOKmul:
- code = MULT_EXPR;
- break;
- case TOKdiv:
- code = e->e1->type->isintegral ()
- ? TRUNC_DIV_EXPR : RDIV_EXPR;
- break;
- case TOKmod:
- code = e->e1->type->isfloating ()
- ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
- break;
- case TOKand:
- code = BIT_AND_EXPR;
- break;
- case TOKor:
- code = BIT_IOR_EXPR;
- break;
- case TOKxor:
- code = BIT_XOR_EXPR;
- break;
- case TOKshl:
- code = LSHIFT_EXPR;
- break;
- case TOKshr:
- code = RSHIFT_EXPR;
- break;
- case TOKushr:
- code = UNSIGNED_RSHIFT_EXPR;
- break;
- default:
- gcc_unreachable ();
- }
- this->result_ = this->binary_op (code, build_ctype (e->type),
- build_expr (e->e1), build_expr (e->e2));
- }
- /* Build a concat expression, which concatenates two or more arrays of the
- same type, producing a dynamic array with the result. If one operand
- is an element type, that element is converted to an array of length 1. */
- void visit (CatExp *e)
- {
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- Type *etype;
- if (tb1->ty == Tarray || tb1->ty == Tsarray)
- etype = tb1->nextOf ();
- else
- etype = tb2->nextOf ();
- vec<tree, va_gc> *elemvars = NULL;
- tree result;
- if (e->e1->op == TOKcat)
- {
- /* Flatten multiple concatenations to an array.
- So the expression ((a ~ b) ~ c) becomes [a, b, c] */
- int ndims = 2;
- for (Expression *ex = e->e1; ex->op == TOKcat;)
- {
- if (ex->op == TOKcat)
- {
- ex = ((CatExp *) ex)->e1;
- ndims++;
- }
- }
- /* Store all concatenation args to a temporary byte[][ndims] array. */
- Type *targselem = Type::tint8->arrayOf ();
- tree var = create_temporary_var (make_array_type (targselem, ndims));
- tree init = build_constructor (TREE_TYPE (var), NULL);
- vec_safe_push (elemvars, var);
- /* Loop through each concatenation from right to left. */
- vec<constructor_elt, va_gc> *elms = NULL;
- CatExp *ce = e;
- int dim = ndims - 1;
- for (Expression *oe = ce->e2; oe != NULL;
- (ce->e1->op != TOKcat
- ? (oe = ce->e1)
- : (ce = (CatExp *)ce->e1, oe = ce->e2)))
- {
- tree arg = d_array_convert (etype, oe, &elemvars);
- tree index = size_int (dim);
- CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg));
- /* Finished pushing all arrays. */
- if (oe == ce->e1)
- break;
- dim -= 1;
- }
- /* Check there is no logic bug in constructing byte[][] of arrays. */
- gcc_assert (dim == 0);
- CONSTRUCTOR_ELTS (init) = elms;
- DECL_INITIAL (var) = init;
- tree arrs = d_array_value (build_ctype (targselem->arrayOf ()),
- size_int (ndims), build_address (var));
- result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
- build_typeinfo (e->loc, e->type), arrs);
- }
- else
- {
- /* Handle single concatenation (a ~ b). */
- result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3,
- build_typeinfo (e->loc, e->type),
- d_array_convert (etype, e->e1, &elemvars),
- d_array_convert (etype, e->e2, &elemvars));
- }
- for (size_t i = 0; i < vec_safe_length (elemvars); ++i)
- result = bind_expr ((*elemvars)[i], result);
- this->result_ = result;
- }
- /* Build an assignment operator expression. The right operand is implicitly
- converted to the type of the left operand, and assigned to it. */
- void visit (BinAssignExp *e)
- {
- tree_code code;
- Expression *e1b = e->e1;
- switch (e->op)
- {
- case TOKaddass:
- code = PLUS_EXPR;
- break;
- case TOKminass:
- code = MINUS_EXPR;
- break;
- case TOKmulass:
- code = MULT_EXPR;
- break;
- case TOKdivass:
- code = e->e1->type->isintegral ()
- ? TRUNC_DIV_EXPR : RDIV_EXPR;
- break;
- case TOKmodass:
- code = e->e1->type->isfloating ()
- ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
- break;
- case TOKandass:
- code = BIT_AND_EXPR;
- break;
- case TOKorass:
- code = BIT_IOR_EXPR;
- break;
- case TOKxorass:
- code = BIT_XOR_EXPR;
- break;
- case TOKpowass:
- gcc_unreachable ();
- case TOKshlass:
- code = LSHIFT_EXPR;
- break;
- case TOKshrass:
- case TOKushrass:
- /* Use the original lhs type before it was promoted. The left operand
- of `>>>=' does not undergo integral promotions before shifting.
- Strip off casts just incase anyway. */
- while (e1b->op == TOKcast)
- {
- CastExp *ce = (CastExp *) e1b;
- gcc_assert (same_type_p (ce->type, ce->to));
- e1b = ce->e1;
- }
- code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
- break;
- default:
- gcc_unreachable ();
- }
- tree exp = this->binop_assignment (code, e1b, e->e2);
- this->result_ = convert_expr (exp, e1b->type, e->type);
- }
- /* Build a concat assignment expression. The right operand is appended
- to the the left operand. */
- void visit (CatAssignExp *e)
- {
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- Type *etype = tb1->nextOf ()->toBasetype ();
- if (tb1->ty == Tarray && tb2->ty == Tdchar
- && (etype->ty == Tchar || etype->ty == Twchar))
- {
- /* Append a dchar to a char[] or wchar[] */
- libcall_fn libcall = (etype->ty == Tchar)
- ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
- this->result_ = build_libcall (libcall, e->type, 2,
- build_address (build_expr (e->e1)),
- build_expr (e->e2));
- }
- else
- {
- gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray);
- tree tinfo = build_typeinfo (e->loc, e->type);
- tree ptr = build_address (build_expr (e->e1));
- if ((tb2->ty == Tarray || tb2->ty == Tsarray)
- && same_type_p (etype, tb2->nextOf ()->toBasetype ()))
- {
- /* Append an array. */
- this->result_ = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3,
- tinfo, ptr, d_array_convert (e->e2));
- }
- else if (same_type_p (etype, tb2))
- {
- /* Append an element. */
- tree result = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3,
- tinfo, ptr, size_one_node);
- result = d_save_expr (result);
- /* Assign e2 to last element. */
- tree offexp = d_array_length (result);
- offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp),
- offexp, size_one_node);
- offexp = d_save_expr (offexp);
- tree ptrexp = d_array_ptr (result);
- ptrexp = void_okay_p (ptrexp);
- ptrexp = build_array_index (ptrexp, offexp);
- /* Evaluate expression before appending. */
- tree t2 = build_expr (e->e2);
- tree expr = stabilize_expr (&t2);
- t2 = d_save_expr (t2);
- result = modify_expr (build_deref (ptrexp), t2);
- result = compound_expr (t2, result);
- this->result_ = compound_expr (expr, result);
- }
- else
- gcc_unreachable ();
- }
- }
- /* Build an assignment expression. The right operand is implicitly
- converted to the type of the left operand, and assigned to it. */
- void visit (AssignExp *e)
- {
- /* First, handle special assignment semantics. */
- /* Look for array.length = n; */
- if (e->e1->op == TOKarraylength)
- {
- /* Assignment to an array's length property; resize the array. */
- ArrayLengthExp *ale = (ArrayLengthExp *) e->e1;
- tree newlength = convert_expr (build_expr (e->e2), e->e2->type,
- Type::tsize_t);
- tree ptr = build_address (build_expr (ale->e1));
- /* Don't want the basetype for the element type. */
- Type *etype = ale->e1->type->toBasetype ()->nextOf ();
- libcall_fn libcall = etype->isZeroInit ()
- ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
- tree result = build_libcall (libcall, ale->e1->type, 3,
- build_typeinfo (ale->loc, ale->e1->type),
- newlength, ptr);
- this->result_ = d_array_length (result);
- return;
- }
- /* Look for array[] = n; */
- if (e->e1->op == TOKslice)
- {
- SliceExp *se = (SliceExp *) e->e1;
- Type *stype = se->e1->type->toBasetype ();
- Type *etype = stype->nextOf ()->toBasetype ();
- /* Determine if we need to run postblit or dtor. */
- bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2);
- bool destructor = this->needs_dtor (etype);
- if (e->memset & blockAssign)
- {
- /* Set a range of elements to one value. */
- tree t1 = d_save_expr (build_expr (e->e1));
- tree t2 = build_expr (e->e2);
- tree result;
- if ((postblit || destructor) && e->op != TOKblit)
- {
- libcall_fn libcall = (e->op == TOKconstruct)
- ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
- /* So we can call postblits on const/immutable objects. */
- Type *tm = etype->unSharedOf ()->mutableOf ();
- tree ti = build_typeinfo (e->loc, tm);
- tree result = build_libcall (libcall, Type::tvoid, 4,
- d_array_ptr (t1),
- build_address (t2),
- d_array_length (t1), ti);
- this->result_ = compound_expr (result, t1);
- return;
- }
- if (integer_zerop (t2))
- {
- tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
- tree size = size_mult_expr (d_array_length (t1),
- size_int (etype->size ()));
- result = build_call_expr (tmemset, 3, d_array_ptr (t1),
- integer_zero_node, size);
- }
- else
- result = build_array_set (d_array_ptr (t1),
- d_array_length (t1), t2);
- this->result_ = compound_expr (result, t1);
- }
- else
- {
- /* Perform a memcpy operation. */
- gcc_assert (e->e2->type->ty != Tpointer);
- if (!postblit && !destructor && !array_bounds_check ())
- {
- tree t1 = d_save_expr (d_array_convert (e->e1));
- tree t2 = d_array_convert (e->e2);
- tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
- tree size = size_mult_expr (d_array_length (t1),
- size_int (etype->size ()));
- tree result = build_call_expr (tmemcpy, 3, d_array_ptr (t1),
- d_array_ptr (t2), size);
- this->result_ = compound_expr (result, t1);
- }
- else if ((postblit || destructor) && e->op != TOKblit)
- {
- /* Generate: _d_arrayassign(ti, from, to)
- or: _d_arrayctor(ti, from, to) */
- libcall_fn libcall = (e->op == TOKconstruct)
- ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
- this->result_ = build_libcall (libcall, e->type, 3,
- build_typeinfo (e->loc, etype),
- d_array_convert (e->e2),
- d_array_convert (e->e1));
- }
- else
- {
- /* Generate: _d_arraycopy() */
- this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
- size_int (etype->size ()),
- d_array_convert (e->e2),
- d_array_convert (e->e1));
- }
- }
- return;
- }
- /* Look for reference initializations. */
- if (e->memset & referenceInit)
- {
- gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
- gcc_assert (e->e1->op == TOKvar);
- Declaration *decl = ((VarExp *) e->e1)->var;
- if (decl->storage_class & (STCout | STCref))
- {
- tree t2 = convert_for_assignment (build_expr (e->e2),
- e->e2->type, e->e1->type);
- tree t1 = build_expr (e->e1);
- /* Want reference to lhs, not indirect ref. */
- t1 = TREE_OPERAND (t1, 0);
- t2 = build_address (t2);
- this->result_ = indirect_ref (build_ctype (e->type),
- build_assign (INIT_EXPR, t1, t2));
- return;
- }
- }
- /* Other types of assignments that may require post construction. */
- Type *tb1 = e->e1->type->toBasetype ();
- tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
- /* Look for struct assignment. */
- if (tb1->ty == Tstruct)
- {
- tree t1 = build_expr (e->e1);
- tree t2 = convert_for_assignment (build_expr (e->e2),
- e->e2->type, e->e1->type);
- /* Look for struct = 0. */
- if (e->e2->op == TOKint64)
- {
- /* Use memset to fill struct. */
- gcc_assert (e->op == TOKblit);
- StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
- tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
- tree result = build_call_expr (tmemset, 3, build_address (t1),
- t2, size_int (sd->structsize));
- /* Maybe set-up hidden pointer to outer scope context. */
- if (sd->isNested ())
- {
- tree field = get_symbol_decl (sd->vthis);
- tree value = build_vthis (sd);
- tree vthis_exp = modify_expr (component_ref (t1, field), value);
- result = compound_expr (result, vthis_exp);
- }
- this->result_ = compound_expr (result, t1);
- }
- else
- this->result_ = build_assign (modifycode, t1, t2);
- return;
- }
- /* Look for static array assignment. */
- if (tb1->ty == Tsarray)
- {
- /* Look for array = 0. */
- if (e->e2->op == TOKint64)
- {
- /* Use memset to fill the array. */
- gcc_assert (e->op == TOKblit);
- tree t1 = build_expr (e->e1);
- tree t2 = convert_for_assignment (build_expr (e->e2),
- e->e2->type, e->e1->type);
- tree size = size_int (e->e1->type->size ());
- tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
- this->result_ = build_call_expr (tmemset, 3, build_address (t1),
- t2, size);
- return;
- }
- Type *etype = tb1->nextOf ();
- gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
- /* Determine if we need to run postblit. */
- bool postblit = this->needs_postblit (etype);
- bool destructor = this->needs_dtor (etype);
- bool lvalue_p = this->lvalue_p (e->e2);
- /* Even if the elements in rhs are all rvalues and don't have
- to call postblits, this assignment should call dtors on old
- assigned elements. */
- if ((!postblit && !destructor)
- || (e->op == TOKconstruct && !lvalue_p && postblit)
- || (e->op == TOKblit || e->e1->type->size () == 0))
- {
- tree t1 = build_expr (e->e1);
- tree t2 = convert_for_assignment (build_expr (e->e2),
- e->e2->type, e->e1->type);
- this->result_ = build_assign (modifycode, t1, t2);
- return;
- }
- Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type;
- tree result;
- if (e->op == TOKconstruct)
- {
- /* Generate: _d_arrayctor(ti, from, to) */
- result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
- build_typeinfo (e->loc, etype),
- d_array_convert (e->e2),
- d_array_convert (e->e1));
- }
- else
- {
- /* Generate: _d_arrayassign_l()
- or: _d_arrayassign_r() */
- libcall_fn libcall = (lvalue_p)
- ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
- tree elembuf = build_local_temp (build_ctype (etype));
- result = build_libcall (libcall, arrtype, 4,
- build_typeinfo (e->loc, etype),
- d_array_convert (e->e2),
- d_array_convert (e->e1),
- build_address (elembuf));
- }
- /* Cast the libcall result back to a static array. */
- if (e->type->ty == Tsarray)
- result = indirect_ref (build_ctype (e->type),
- d_array_ptr (result));
- this->result_ = result;
- return;
- }
- /* Simple assignment. */
- tree t1 = build_expr (e->e1);
- tree t2 = convert_for_assignment (build_expr (e->e2),
- e->e2->type, e->e1->type);
- this->result_ = build_assign (modifycode, t1, t2);
- }
- /* Build a postfix expression. */
- void visit (PostExp *e)
- {
- tree result;
- if (e->op == TOKplusplus)
- {
- result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
- build_expr (e->e1), build_expr (e->e2));
- }
- else if (e->op == TOKminusminus)
- {
- result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
- build_expr (e->e1), build_expr (e->e2));
- }
- else
- gcc_unreachable ();
- TREE_SIDE_EFFECTS (result) = 1;
- this->result_ = result;
- }
- /* Build an index expression. */
- void visit (IndexExp *e)
- {
- Type *tb1 = e->e1->type->toBasetype ();
- if (tb1->ty == Taarray)
- {
- /* Get the key for the associative array. */
- Type *tkey = ((TypeAArray *) tb1)->index->toBasetype ();
- tree key = convert_expr (build_expr (e->e2), e->e2->type, tkey);
- libcall_fn libcall;
- tree tinfo, ptr;
- if (e->modifiable)
- {
- libcall = LIBCALL_AAGETY;
- ptr = build_address (build_expr (e->e1));
- tinfo = build_typeinfo (e->loc, tb1->unSharedOf ()->mutableOf ());
- }
- else
- {
- libcall = LIBCALL_AAGETRVALUEX;
- ptr = build_expr (e->e1);
- tinfo = build_typeinfo (e->loc, tkey);
- }
- /* Index the associative array. */
- tree result = build_libcall (libcall, e->type->pointerTo (), 4,
- ptr, tinfo,
- size_int (tb1->nextOf ()->size ()),
- build_address (key));
- if (!e->indexIsInBounds && array_bounds_check ())
- {
- tree tassert = (global.params.checkAction == CHECKACTION_C)
- ? build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0)
- : d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS);
- result = d_save_expr (result);
- result = build_condition (TREE_TYPE (result),
- d_truthvalue_conversion (result),
- result, tassert);
- }
- this->result_ = indirect_ref (build_ctype (e->type), result);
- }
- else
- {
- /* Get the data pointer and length for static and dynamic arrays. */
- tree array = d_save_expr (build_expr (e->e1));
- tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
- tree length = NULL_TREE;
- if (tb1->ty != Tpointer)
- length = get_array_length (array, tb1);
- else
- gcc_assert (e->lengthVar == NULL);
- /* The __dollar variable just becomes a placeholder for the
- actual length. */
- if (e->lengthVar)
- e->lengthVar->csym = length;
- /* Generate the index. */
- tree index = build_expr (e->e2);
- /* If it's a static array and the index is constant, the front end has
- already checked the bounds. */
- if (tb1->ty != Tpointer && !e->indexIsInBounds)
- index = build_bounds_condition (e->e2->loc, index, length, false);
- /* Index the .ptr. */
- ptr = void_okay_p (ptr);
- this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)),
- build_array_index (ptr, index));
- }
- }
- /* Build a comma expression. The type is the type of the right operand. */
- void visit (CommaExp *e)
- {
- tree t1 = build_expr (e->e1);
- tree t2 = build_expr (e->e2);
- tree type = e->type ? build_ctype (e->type) : void_type_node;
- this->result_ = build2 (COMPOUND_EXPR, type, t1, t2);
- }
- /* Build an array length expression. Returns the number of elements
- in the array. The result is of type size_t. */
- void visit (ArrayLengthExp *e)
- {
- if (e->e1->type->toBasetype ()->ty == Tarray)
- this->result_ = d_array_length (build_expr (e->e1));
- else
- {
- /* Static arrays have already been handled by the front-end. */
- error ("unexpected type for array length: %qs", e->type->toChars ());
- this->result_ = error_mark_node;
- }
- }
- /* Build a delegate pointer expression. This will return the frame
- pointer value as a type void*. */
- void visit (DelegatePtrExp *e)
- {
- tree t1 = build_expr (e->e1);
- this->result_ = delegate_object (t1);
- }
- /* Build a delegate function pointer expression. This will return the
- function pointer value as a function type. */
- void visit (DelegateFuncptrExp *e)
- {
- tree t1 = build_expr (e->e1);
- this->result_ = delegate_method (t1);
- }
- /* Build a slice expression. */
- void visit (SliceExp *e)
- {
- Type *tb = e->type->toBasetype ();
- Type *tb1 = e->e1->type->toBasetype ();
- gcc_assert (tb->ty == Tarray || tb->ty == Tsarray);
- /* Use convert-to-dynamic-array code if possible. */
- if (!e->lwr)
- {
- tree result = build_expr (e->e1);
- if (e->e1->type->toBasetype ()->ty == Tsarray)
- result = convert_expr (result, e->e1->type, e->type);
- this->result_ = result;
- return;
- }
- else
- gcc_assert (e->upr != NULL);
- /* Get the data pointer and length for static and dynamic arrays. */
- tree array = d_save_expr (build_expr (e->e1));
- tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
- tree length = NULL_TREE;
- /* Our array is already a SAVE_EXPR if necessary, so we don't make length
- a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array. */
- if (tb1->ty != Tpointer)
- length = get_array_length (array, tb1);
- else
- gcc_assert (e->lengthVar == NULL);
- /* The __dollar variable just becomes a placeholder for the
- actual length. */
- if (e->lengthVar)
- e->lengthVar->csym = length;
- /* Generate upper and lower bounds. */
- tree lwr_tree = d_save_expr (build_expr (e->lwr));
- tree upr_tree = d_save_expr (build_expr (e->upr));
- /* If the upper bound has any side effects, then the lower bound should be
- copied to a temporary always. */
- if (TREE_CODE (upr_tree) == SAVE_EXPR && TREE_CODE (lwr_tree) != SAVE_EXPR)
- lwr_tree = save_expr (lwr_tree);
- /* Adjust the .ptr offset. */
- if (!integer_zerop (lwr_tree))
- {
- tree ptrtype = TREE_TYPE (ptr);
- ptr = build_array_index (void_okay_p (ptr), lwr_tree);
- ptr = build_nop (ptrtype, ptr);
- }
- else
- lwr_tree = NULL_TREE;
- /* Nothing more to do for static arrays, their bounds checking has been
- done at compile-time. */
- if (tb->ty == Tsarray)
- {
- this->result_ = indirect_ref (build_ctype (e->type), ptr);
- return;
- }
- else
- gcc_assert (tb->ty == Tarray);
- /* Generate bounds checking code. */
- tree newlength;
- if (!e->upperIsInBounds)
- {
- if (length)
- {
- newlength = build_bounds_condition (e->upr->loc, upr_tree,
- length, true);
- }
- else
- {
- /* Still need to check bounds lwr <= upr for pointers. */
- gcc_assert (tb1->ty == Tpointer);
- newlength = upr_tree;
- }
- }
- else
- newlength = upr_tree;
- if (lwr_tree)
- {
- /* Enforces lwr <= upr. No need to check lwr <= length as
- we've already ensured that upr <= length. */
- if (!e->lowerIsLessThanUpper)
- {
- tree cond = build_bounds_condition (e->lwr->loc, lwr_tree,
- upr_tree, true);
- /* When bounds checking is off, the index value is
- returned directly. */
- if (cond != lwr_tree)
- newlength = compound_expr (cond, newlength);
- }
- /* Need to ensure lwr always gets evaluated first, as it may be a
- function call. Generates (lwr, upr) - lwr. */
- newlength = fold_build2 (MINUS_EXPR, TREE_TYPE (newlength),
- compound_expr (lwr_tree, newlength), lwr_tree);
- }
- tree result = d_array_value (build_ctype (e->type), newlength, ptr);
- this->result_ = compound_expr (array, result);
- }
- /* Build a cast expression, which converts the given unary expression to the
- type of result. */
- void visit (CastExp *e)
- {
- Type *ebtype = e->e1->type->toBasetype ();
- Type *tbtype = e->to->toBasetype ();
- tree result = build_expr (e->e1, this->constp_);
- /* Just evaluate e1 if it has any side effects. */
- if (tbtype->ty == Tvoid)
- this->result_ = build_nop (build_ctype (tbtype), result);
- else
- this->result_ = convert_expr (result, ebtype, tbtype);
- }
- /* Build a delete expression. */
- void visit (DeleteExp *e)
- {
- tree t1 = build_expr (e->e1);
- Type *tb1 = e->e1->type->toBasetype ();
- if (tb1->ty == Tclass)
- {
- /* For class object references, if there is a destructor for that class,
- the destructor is called for the object instance. */
- libcall_fn libcall;
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *) e->e1)->var->isVarDeclaration ();
- if (v && v->onstack)
- {
- libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
- ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
- this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
- return;
- }
- }
- /* Otherwise, the garbage collector is called to immediately free the
- memory allocated for the class instance. */
- libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
- ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS;
- t1 = build_address (t1);
- this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
- }
- else if (tb1->ty == Tarray)
- {
- /* For dynamic arrays, the garbage collector is called to immediately
- release the memory. */
- Type *telem = tb1->nextOf ()->baseElemOf ();
- tree ti = null_pointer_node;
- if (telem->ty == Tstruct)
- {
- /* Might need to run destructor on array contents. */
- TypeStruct *ts = (TypeStruct *) telem;
- if (ts->sym->dtor)
- ti = build_typeinfo (e->loc, tb1->nextOf ());
- }
- /* Generate: _delarray_t (&t1, ti); */
- this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
- build_address (t1), ti);
- }
- else if (tb1->ty == Tpointer)
- {
- /* For pointers to a struct instance, if the struct has overloaded
- operator delete, then that operator is called. */
- t1 = build_address (t1);
- Type *tnext = ((TypePointer *)tb1)->next->toBasetype ();
- if (tnext->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tnext;
- if (ts->sym->dtor)
- {
- tree ti = build_typeinfo (e->loc, tnext);
- this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
- 2, t1, ti);
- return;
- }
- }
- /* Otherwise, the garbage collector is called to immediately free the
- memory allocated for the pointer. */
- this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
- }
- else
- {
- error ("don't know how to delete %qs", e->e1->toChars ());
- this->result_ = error_mark_node;
- }
- }
- /* Build a remove expression, which removes a particular key from an
- associative array. */
- void visit (RemoveExp *e)
- {
- /* Check that the array is actually an associative array. */
- if (e->e1->type->toBasetype ()->ty == Taarray)
- {
- Type *tb = e->e1->type->toBasetype ();
- Type *tkey = ((TypeAArray *) tb)->index->toBasetype ();
- tree index = convert_expr (build_expr (e->e2), e->e2->type, tkey);
- this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3,
- build_expr (e->e1),
- build_typeinfo (e->loc, tkey),
- build_address (index));
- }
- else
- {
- error ("%qs is not an associative array", e->e1->toChars ());
- this->result_ = error_mark_node;
- }
- }
- /* Build an unary not expression. */
- void visit (NotExp *e)
- {
- tree result = convert_for_condition (build_expr (e->e1), e->e1->type);
- /* Need to convert to boolean type or this will fail. */
- result = fold_build1 (TRUTH_NOT_EXPR, d_bool_type, result);
- this->result_ = d_convert (build_ctype (e->type), result);
- }
- /* Build a compliment expression, where all the bits in the value are
- complemented. Note: unlike in C, the usual integral promotions
- are not performed prior to the complement operation. */
- void visit (ComExp *e)
- {
- TY ty1 = e->e1->type->toBasetype ()->ty;
- gcc_assert (ty1 != Tarray && ty1 != Tsarray);
- this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type),
- build_expr (e->e1));
- }
- /* Build an unary negation expression. */
- void visit (NegExp *e)
- {
- TY ty1 = e->e1->type->toBasetype ()->ty;
- gcc_assert (ty1 != Tarray && ty1 != Tsarray);
- tree type = build_ctype (e->type);
- tree expr = build_expr (e->e1);
- /* If the operation needs excess precision. */
- tree eptype = excess_precision_type (type);
- if (eptype != NULL_TREE)
- expr = d_convert (eptype, expr);
- else
- eptype = type;
- tree ret = fold_build1 (NEGATE_EXPR, eptype, expr);
- this->result_ = d_convert (type, ret);
- }
- /* Build a pointer index expression. */
- void visit (PtrExp *e)
- {
- Type *tnext = NULL;
- size_t offset;
- tree result;
- if (e->e1->op == TOKadd)
- {
- BinExp *be = (BinExp *) e->e1;
- if (be->e1->op == TOKaddress
- && be->e2->isConst () && be->e2->type->isintegral ())
- {
- Expression *ae = ((AddrExp *) be->e1)->e1;
- tnext = ae->type->toBasetype ();
- result = build_expr (ae);
- offset = be->e2->toUInteger ();
- }
- }
- else if (e->e1->op == TOKsymoff)
- {
- SymOffExp *se = (SymOffExp *) e->e1;
- if (!declaration_reference_p (se->var))
- {
- tnext = se->var->type->toBasetype ();
- result = get_decl_tree (se->var);
- offset = se->offset;
- }
- }
- /* Produce better code by converting *(#record + n) to
- COMPONENT_REFERENCE. Otherwise, the variable will always be
- allocated in memory because its address is taken. */
- if (tnext && tnext->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *) tnext)->sym;
- for (size_t i = 0; i < sd->fields.dim; i++)
- {
- VarDeclaration *field = sd->fields[i];
- if (field->offset == offset
- && same_type_p (field->type, e->type))
- {
- /* Catch errors, backend will ICE otherwise. */
- if (error_operand_p (result))
- this->result_ = result;
- else
- {
- result = component_ref (result, get_symbol_decl (field));
- this->result_ = result;
- }
- return;
- }
- else if (field->offset > offset)
- break;
- }
- }
- this->result_ = indirect_ref (build_ctype (e->type), build_expr (e->e1));
- }
- /* Build an unary address expression. */
- void visit (AddrExp *e)
- {
- tree type = build_ctype (e->type);
- tree exp;
- /* The frontend optimizer can convert const symbol into a struct literal.
- Taking the address of a struct literal is otherwise illegal. */
- if (e->e1->op == TOKstructliteral)
- {
- StructLiteralExp *sle = ((StructLiteralExp *) e->e1)->origin;
- gcc_assert (sle != NULL);
- /* Build the reference symbol, the decl is built first as the
- initializer may have recursive references. */
- if (!sle->sym)
- {
- sle->sym = build_artificial_decl (build_ctype (sle->type),
- NULL_TREE, "S");
- DECL_INITIAL (sle->sym) = build_expr (sle, true);
- d_pushdecl (sle->sym);
- rest_of_decl_compilation (sle->sym, 1, 0);
- }
- exp = sle->sym;
- }
- else
- exp = build_expr (e->e1, this->constp_);
- TREE_CONSTANT (exp) = 0;
- this->result_ = d_convert (type, build_address (exp));
- }
- /* Build a function call expression. */
- void visit (CallExp *e)
- {
- Type *tb = e->e1->type->toBasetype ();
- Expression *e1b = e->e1;
- tree callee = NULL_TREE;
- tree object = NULL_TREE;
- tree cleanup = NULL_TREE;
- TypeFunction *tf = NULL;
- /* Calls to delegates can sometimes look like this. */
- if (e1b->op == TOKcomma)
- {
- e1b = ((CommaExp *) e1b)->e2;
- gcc_assert (e1b->op == TOKvar);
- Declaration *var = ((VarExp *) e1b)->var;
- gcc_assert (var->isFuncDeclaration () && !var->needThis ());
- }
- if (e1b->op == TOKdotvar && tb->ty != Tdelegate)
- {
- DotVarExp *dve = (DotVarExp *) e1b;
- /* Don't modify the static initializer for struct literals. */
- if (dve->e1->op == TOKstructliteral)
- {
- StructLiteralExp *sle = (StructLiteralExp *) dve->e1;
- sle->useStaticInit = false;
- }
- FuncDeclaration *fd = dve->var->isFuncDeclaration ();
- if (fd != NULL)
- {
- /* Get the correct callee from the DotVarExp object. */
- tree fndecl = get_symbol_decl (fd);
- AggregateDeclaration *ad = fd->isThis ();
- /* Static method; ignore the object instance. */
- if (!ad)
- callee = build_address (fndecl);
- else
- {
- tree thisexp = build_expr (dve->e1);
- /* When constructing temporaries, if the constructor throws,
- then the object is destructed even though it is not a fully
- constructed object yet. And so this call will need to be
- moved inside the TARGET_EXPR_INITIAL slot. */
- if (fd->isCtorDeclaration ()
- && TREE_CODE (thisexp) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (thisexp, 0)) == TARGET_EXPR
- && TARGET_EXPR_CLEANUP (TREE_OPERAND (thisexp, 0)))
- {
- cleanup = TREE_OPERAND (thisexp, 0);
- thisexp = TREE_OPERAND (thisexp, 1);
- }
- /* Want reference to 'this' object. */
- if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
- thisexp = build_address (thisexp);
- /* Make the callee a virtual call. */
- if (fd->isVirtual () && !fd->isFinalFunc () && !e->directcall)
- {
- tree fntype = build_pointer_type (TREE_TYPE (fndecl));
- tree thistype = build_ctype (ad->handleType ());
- thisexp = build_nop (thistype, d_save_expr (thisexp));
- fndecl = build_vindex_ref (thisexp, fntype, fd->vtblIndex);
- }
- else
- fndecl = build_address (fndecl);
- callee = build_method_call (fndecl, thisexp, fd->type);
- }
- }
- }
- if (callee == NULL_TREE)…
Large files files are truncated, but you can click here to view the full file