From 9bca182f24ed0baf8da63e15ea7a21fc067ce19b Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 1 May 2018 12:12:26 +0200 Subject: [PATCH 1/5] Add build_unary_op, use it instead of stabilize_expr for NOP_EXPR --- gcc/d/ChangeLog | 5 +++++ gcc/d/d-codegen.cc | 24 +++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 1fb57244c..ed727675b 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,8 @@ +2018-05-01 Iain Buclaw + + * d-codegen.cc (build_unary_op): New function. + (build_nop): Use build_unary_op. + 2018-04-02 Iain Buclaw * d-lang.cc (doing_semantic_analysis_p): New variable. diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index b7c746b93..2bc9cf9b0 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -517,6 +517,24 @@ d_save_expr (tree exp) return exp; } +/* Build an unary op CODE to the expression ARG. If the expression can be + broken down so that the operation is applied only to the part whose value we + care about, then handle lowering to keep lvalues trivial. */ + +static tree +build_unary_op (tree_code code, tree type, tree arg) +{ + /* Given ((e1, ...), eN): + Treat the last RHS 'eN' expression as the lvalue part. */ + if (TREE_CODE (arg) == COMPOUND_EXPR) + { + tree result = build_unary_op (code, type, TREE_OPERAND (arg, 1)); + return compound_expr (TREE_OPERAND (arg, 0), result); + } + + return fold_build1_loc (input_location, code, type, arg); +} + /* VALUEP is an expression we want to pre-evaluate or perform a computation on. The expression returned by this function is the part whose value we don't care about, storing the value in VALUEP. Callers must ensure that the @@ -1360,11 +1378,7 @@ build_nop (tree type, tree exp) if (error_operand_p (exp)) return exp; - /* Maybe rewrite: cast(TYPE)(e1, e2) => (e1, cast(TYPE) e2) */ - tree init = stabilize_expr (&exp); - exp = fold_build1_loc (input_location, NOP_EXPR, type, exp); - - return compound_expr (init, exp); + return build_unary_op (NOP_EXPR, type, exp); } /* Return EXP to be viewed as being another type TYPE. Same as build_nop, From 6f56053ed67b44733397532348618a85e24516f0 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 1 May 2018 17:43:57 +0200 Subject: [PATCH 2/5] Use build_unary_op instead of stabilize_expr for ADDR_EXPR --- gcc/d/ChangeLog | 1 + gcc/d/d-codegen.cc | 41 ++++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index ed727675b..29d3f0a46 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -2,6 +2,7 @@ * d-codegen.cc (build_unary_op): New function. (build_nop): Use build_unary_op. + (build_address): Move expression handling to build_unary_op. 2018-04-02 Iain Buclaw diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2bc9cf9b0..2066f7db6 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -532,6 +532,27 @@ build_unary_op (tree_code code, tree type, tree arg) return compound_expr (TREE_OPERAND (arg, 0), result); } + if (code == ADDR_EXPR) + { + /* Can't take the address of a manifest constant, get the real value of + the decl instead. */ + if (TREE_CODE (arg) == CONST_DECL) + arg = DECL_INITIAL (arg); + + /* Some expression lowering may request an address of a compile-time + constant. Make sure it is assigned to a location we can reference. */ + if (CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != STRING_CST) + arg = force_target_expr (arg); + + d_mark_addressable (arg); + tree result = build_fold_addr_expr_with_type_loc (input_location, arg, + type); + if (TREE_CODE (result) == ADDR_EXPR) + TREE_NO_TRAMPOLINE (result) = 1; + + return result; + } + return fold_build1_loc (input_location, code, type, arg); } @@ -624,25 +645,7 @@ build_address (tree exp) else ptrtype = build_pointer_type (type); - /* Maybe rewrite: &(e1, e2) => (e1, &e2). */ - tree init = stabilize_expr (&exp); - - /* Can't take the address of a manifest constant, instead use its value. */ - if (TREE_CODE (exp) == CONST_DECL) - exp = DECL_INITIAL (exp); - - /* Some expression lowering may request an address of a compile-time constant. - Make sure it is assigned to a location we can reference. */ - if (CONSTANT_CLASS_P (exp) && TREE_CODE (exp) != STRING_CST) - exp = force_target_expr (exp); - - d_mark_addressable (exp); - exp = build_fold_addr_expr_with_type_loc (input_location, exp, ptrtype); - - if (TREE_CODE (exp) == ADDR_EXPR) - TREE_NO_TRAMPOLINE (exp) = 1; - - return compound_expr (init, exp); + return build_unary_op (ADDR_EXPR, ptrtype, exp); } /* Mark EXP saying that we need to be able to take the From 98c08266b34bd5804aec2ec6af140b8111eb8f3f Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Wed, 2 May 2018 15:34:33 +0200 Subject: [PATCH 3/5] Use target_expr based stabilize in indirect_ref --- gcc/d/d-codegen.cc | 20 ++++++++++++++++++-- gcc/d/d-tree.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2066f7db6..26f6a8cbb 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -561,6 +561,21 @@ build_unary_op (tree_code code, tree type, tree arg) care about, storing the value in VALUEP. Callers must ensure that the returned expression is evaluated before VALUEP. */ +tree +stabilize_expr2 (tree *valuep) +{ + tree expr = *valuep; + + /* No side effects or expression has no value. */ + if (!TREE_SIDE_EFFECTS (expr) || VOID_TYPE_P (TREE_TYPE (expr))) + return NULL_TREE; + + tree init = force_target_expr (expr); + *valuep = TARGET_EXPR_SLOT (init); + + return init; +} + tree stabilize_expr (tree *valuep) { @@ -1193,6 +1208,7 @@ find_aggregate_field (tree type, tree ident, tree offset) return NULL_TREE; } + /* Return a constructor that matches the layout of the class expression EXP. */ tree @@ -1530,7 +1546,7 @@ indirect_ref (tree type, tree exp) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ - tree init = stabilize_expr (&exp); + tree init = stabilize_expr2 (&exp); if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE) exp = fold_build1 (INDIRECT_REF, type, exp); @@ -1552,7 +1568,7 @@ build_deref (tree exp) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ - tree init = stabilize_expr (&exp); + tree init = stabilize_expr2 (&exp); gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp))); diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index 06a7190cf..1dbdfe3f8 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -508,6 +508,7 @@ extern void extract_from_method_call (tree, tree &, tree &); extern tree build_vindex_ref (tree, tree, size_t); extern tree d_save_expr (tree); extern tree stabilize_expr (tree *); +extern tree stabilize_expr2 (tree *); extern tree build_target_expr (tree, tree); extern tree force_target_expr (tree); extern tree build_address (tree); From 48b809bd00d8174bb6e74af6df70ed59c0c438e1 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Thu, 3 May 2018 11:36:26 +0200 Subject: [PATCH 4/5] Remove stabilize in component_ref, add case for modify expressions. --- gcc/d/d-codegen.cc | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 26f6a8cbb..4e078fd32 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -524,14 +524,30 @@ d_save_expr (tree exp) static tree build_unary_op (tree_code code, tree type, tree arg) { - /* Given ((e1, ...), eN): - Treat the last RHS 'eN' expression as the lvalue part. */ + /* Given ((e1, ...), eN), treat the last RHS 'eN' expression as the + lvalue part. */ if (TREE_CODE (arg) == COMPOUND_EXPR) { tree result = build_unary_op (code, type, TREE_OPERAND (arg, 1)); return compound_expr (TREE_OPERAND (arg, 0), result); } + /* Given (e1 = e2), (++e1), or (--e1), convert 'e1' into an lvalue. */ + if (TREE_CODE (arg) == MODIFY_EXPR + || TREE_CODE (arg) == PREINCREMENT_EXPR + || TREE_CODE (arg) == PREDECREMENT_EXPR) + { + if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0))) + { + arg = build2 (TREE_CODE (arg), TREE_TYPE (arg), + stabilize_reference (TREE_OPERAND (arg, 0)), + TREE_OPERAND (arg, 1)); + gcc_unreachable (); + } + return build_unary_op (code, type, + compound_expr (arg, TREE_OPERAND (arg, 0))); + } + if (code == ADDR_EXPR) { /* Can't take the address of a manifest constant, get the real value of @@ -567,7 +583,8 @@ stabilize_expr2 (tree *valuep) tree expr = *valuep; /* No side effects or expression has no value. */ - if (!TREE_SIDE_EFFECTS (expr) || VOID_TYPE_P (TREE_TYPE (expr))) + if (!TREE_SIDE_EFFECTS (expr) || TREE_CODE (expr) == SAVE_EXPR + || VOID_TYPE_P (TREE_TYPE (expr))) return NULL_TREE; tree init = force_target_expr (expr); @@ -1322,9 +1339,6 @@ component_ref (tree object, tree field) gcc_assert (TREE_CODE (field) == FIELD_DECL); - /* Maybe rewrite: (e1, e2).field => (e1, e2.field) */ - tree init = stabilize_expr (&object); - /* If the FIELD is from an anonymous aggregate, generate a reference to the anonymous data member, and recur to find FIELD. */ if (ANON_AGGR_TYPE_P (DECL_CONTEXT (field))) @@ -1334,10 +1348,8 @@ component_ref (tree object, tree field) object = component_ref (object, anonymous_field); } - tree result = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (field), object, field, NULL_TREE); - - return compound_expr (init, result); + return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), + object, field, NULL_TREE); } /* Build an assignment expression of lvalue LHS from value RHS. From 4ee33cc0f6568750617af97ada402a655293e143 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 4 May 2018 15:14:29 +0200 Subject: [PATCH 5/5] Use target_expr based stabilize in build_struct_comparison --- gcc/d/d-codegen.cc | 91 +++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 4e078fd32..89e4ad0fc 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -517,6 +517,28 @@ d_save_expr (tree exp) return exp; } +/* Adjust EXPR so that it is a valid lvalue, and can be evaluated multiple times + if it has any side effects. */ + +static tree +compound_lvalue (tree expr) +{ + const tree_code code = TREE_CODE (expr); + + if (code == MODIFY_EXPR || code == PREINCREMENT_EXPR + || code == PREDECREMENT_EXPR) + { + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) + expr = build2 (TREE_CODE (expr), TREE_TYPE (expr), + stabilize_reference (TREE_OPERAND (expr, 0)), + TREE_OPERAND (expr, 1)); + + return compound_expr (expr, TREE_OPERAND (expr, 0)); + } + + return expr; +} + /* Build an unary op CODE to the expression ARG. If the expression can be broken down so that the operation is applied only to the part whose value we care about, then handle lowering to keep lvalues trivial. */ @@ -532,21 +554,7 @@ build_unary_op (tree_code code, tree type, tree arg) return compound_expr (TREE_OPERAND (arg, 0), result); } - /* Given (e1 = e2), (++e1), or (--e1), convert 'e1' into an lvalue. */ - if (TREE_CODE (arg) == MODIFY_EXPR - || TREE_CODE (arg) == PREINCREMENT_EXPR - || TREE_CODE (arg) == PREDECREMENT_EXPR) - { - if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0))) - { - arg = build2 (TREE_CODE (arg), TREE_TYPE (arg), - stabilize_reference (TREE_OPERAND (arg, 0)), - TREE_OPERAND (arg, 1)); - gcc_unreachable (); - } - return build_unary_op (code, type, - compound_expr (arg, TREE_OPERAND (arg, 0))); - } + arg = compound_lvalue (arg); if (code == ADDR_EXPR) { @@ -587,6 +595,16 @@ stabilize_expr2 (tree *valuep) || VOID_TYPE_P (TREE_TYPE (expr))) return NULL_TREE; + /* Stabilize only the right hand side of compound expressions. */ + if (TREE_CODE (expr) == COMPOUND_EXPR) + { + tree lhs = TREE_OPERAND (expr, 0); + tree rhs = TREE_OPERAND (expr, 1); + lhs = compound_expr (lhs, stabilize_expr2 (&rhs)); + *valuep = rhs; + return lhs; + } + tree init = force_target_expr (expr); *valuep = TARGET_EXPR_SLOT (init); @@ -929,13 +947,10 @@ build_struct_comparison (tree_code code, StructDeclaration *sd, return build_boolop (code, integer_zero_node, integer_zero_node); /* Make temporaries to prevent multiple evaluations. */ - tree t1init = stabilize_expr (&t1); - tree t2init = stabilize_expr (&t2); + tree t1init = stabilize_expr2 (&t1); + tree t2init = stabilize_expr2 (&t2); tree result; - t1 = d_save_expr (t1); - t2 = d_save_expr (t2); - /* Bitwise comparison of structs not returned in memory may not work due to data holes loosing its zero padding upon return. As a heuristic, small structs are not compared using memcmp either. */ @@ -1337,6 +1352,12 @@ component_ref (tree object, tree field) if (error_operand_p (object) || error_operand_p (field)) return error_mark_node; + if (TREE_CODE (object) == COMPOUND_EXPR) + { + tree result = component_ref (TREE_OPERAND (object, 1), field); + return compound_expr (TREE_OPERAND (object, 0), result); + } + gcc_assert (TREE_CODE (field) == FIELD_DECL); /* If the FIELD is from an anonymous aggregate, generate a reference @@ -1359,8 +1380,14 @@ component_ref (tree object, tree field) tree build_assign (tree_code code, tree lhs, tree rhs) { - tree init = stabilize_expr (&lhs); - init = compound_expr (init, stabilize_expr (&rhs)); + /* Handle control structure constructs used as lvalues. */ + if (TREE_CODE (lhs) == COMPOUND_EXPR) + { + tree result = build_assign (code, TREE_OPERAND (lhs, 1), rhs); + return compound_expr (TREE_OPERAND (lhs, 0), result); + } + + lhs = compound_lvalue (lhs); /* If initializing the LHS using a function that returns via NRVO. */ if (code == INIT_EXPR && TREE_CODE (rhs) == CALL_EXPR @@ -1388,9 +1415,7 @@ build_assign (tree_code code, tree lhs, tree rhs) } } - tree result = fold_build2_loc (input_location, code, - TREE_TYPE (lhs), lhs, rhs); - return compound_expr (init, result); + return fold_build2_loc (input_location, code, TREE_TYPE (lhs), lhs, rhs); } /* Build an assignment expression of lvalue LHS from value RHS. */ @@ -1558,7 +1583,11 @@ indirect_ref (tree type, tree exp) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ - tree init = stabilize_expr2 (&exp); + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree result = indirect_ref (type, TREE_OPERAND (exp, 1)); + return compound_expr (TREE_OPERAND (exp, 0), result); + } if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE) exp = fold_build1 (INDIRECT_REF, type, exp); @@ -1568,7 +1597,7 @@ indirect_ref (tree type, tree exp) exp = build_deref (exp); } - return compound_expr (init, exp); + return exp; } /* Returns indirect reference of EXP, which must be a pointer type. */ @@ -1580,7 +1609,11 @@ build_deref (tree exp) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ - tree init = stabilize_expr2 (&exp); + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree result = build_deref (TREE_OPERAND (exp, 1)); + return compound_expr (TREE_OPERAND (exp, 0), result); + } gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp))); @@ -1589,7 +1622,7 @@ build_deref (tree exp) else exp = build_fold_indirect_ref (exp); - return compound_expr (init, exp); + return exp; } /* Builds pointer offset expression PTR[INDEX]. */