static enum gimplify_status
gimplify_compound_lval (tree *expr_p, tree *pre_p,
- tree *post_p, bool want_lvalue)
+ tree *post_p, fallback_t fallback)
{
tree *p;
varray_type stack;
}
/* Step 2 is to gimplify the base expression. */
- tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
- want_lvalue ? fb_lvalue : fb_rvalue);
+ tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
ret = MIN (ret, tret);
/* And finally, the indices and operands to BIT_FIELD_REF. */
VARRAY_POP (stack);
}
- tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
- want_lvalue ? fb_lvalue : fb_rvalue);
+ tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
ret = MIN (ret, tret);
/* If the outermost expression is a COMPONENT_REF, canonicalize its type. */
- if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
+ if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF)
{
canonicalize_component_ref (expr_p);
ret = MIN (ret, GS_OK);
}
}
-/* Gimplify the CALL_EXPR node pointed by EXPR_P.
-
- call_expr
- : ID '(' arglist ')'
-
- arglist
- : arglist ',' val
- | val
-
- PRE_P points to the list where side effects that must happen before
- *EXPR_P should be stored. */
+/* Gimplify the CALL_EXPR node pointed by EXPR_P. PRE_P points to the
+ list where side effects that must happen before *EXPR_P should be stored.
+ WANT_VALUE is true if the result of the call is desired. */
static enum gimplify_status
-gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
+gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
{
tree decl;
tree arglist;
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE)
gimplify_ctxp->save_stack = false;
- new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
+ new = simplify_builtin (*expr_p, !want_value);
if (new && new != *expr_p)
{
arglist = TREE_CHAIN (arglist))
{
enum gimplify_status t;
+ bool (*test) (tree);
+ fallback_t fb;
+
+ /* In general, we allow lvalues for function arguments to avoid
+ extra overhead of copying large aggregates out of even larger
+ aggregates into temporaries only to copy the temporaries to
+ the argument list. Make optimizers happy by pulling out to
+ temporaries those types that fit in registers. */
+ if (is_gimple_reg_type (TREE_TYPE (TREE_VALUE (arglist))))
+ test = is_gimple_val, fb = fb_rvalue;
+ else
+ test = is_gimple_lvalue, fb = fb_either;
/* There is a sequence point before a function call. Side effects in
the argument list must occur before the actual call. So, when
gimplifying arguments, force gimplify_expr to use an internal
post queue which is then appended to the end of PRE_P. */
- t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, is_gimple_val,
- fb_rvalue);
+ t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, test, fb);
if (t == GS_ERROR)
ret = GS_ERROR;
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
{
- tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
+ tree new = simplify_builtin (*expr_p, !want_value);
if (new && new != *expr_p)
{
args = tree_cons (NULL, t, args);
to_ptr = build_fold_addr_expr (to);
- args = tree_cons (NULL, to, args);
+ args = tree_cons (NULL, to_ptr, args);
t = implicit_built_in_decls[BUILT_IN_MEMCPY];
t = build_function_call_expr (t, args);
case IMAGPART_EXPR:
case COMPONENT_REF:
ret = gimplify_compound_lval (expr_p, pre_p, post_p,
- fallback & fb_lvalue);
+ fallback ? fallback : fb_rvalue);
break;
case COND_EXPR:
break;
case CALL_EXPR:
- ret = gimplify_call_expr (expr_p, pre_p, gimple_test_f);
+ ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
break;
case TREE_LIST:
enum gimplify_status r0, r1, r2;
r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
- is_gimple_min_lval, fb_either);
+ is_gimple_lvalue, fb_either);
r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
is_gimple_val, fb_rvalue);
r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p,
http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html
- function:
- FUNCTION_DECL
- DECL_SAVED_TREE -> block
- block:
- BIND_EXPR
- BIND_EXPR_VARS -> DECL chain
- BIND_EXPR_BLOCK -> BLOCK
- BIND_EXPR_BODY -> compound-stmt
- compound-stmt:
- COMPOUND_EXPR
- op0 -> non-compound-stmt
- op1 -> stmt
- | EXPR_VEC
- (or other alternate solution)
- stmt: compound-stmt | non-compound-stmt
- non-compound-stmt:
- block
- | if-stmt
- | switch-stmt
- | jump-stmt
- | label-stmt
- | try-stmt
- | modify-stmt
- | call-stmt
- if-stmt:
- COND_EXPR
- op0 -> condition
- op1 -> stmt
- op2 -> stmt
- switch-stmt:
- SWITCH_EXPR
- op0 -> val
- op1 -> stmt
- op2 -> array of case labels (as LABEL_DECLs?)
- FIXME: add case value info
- The SWITCH_LABELS (op2) are sorted in ascending order, and the
- last label in the vector is always the default case.
- jump-stmt:
- GOTO_EXPR
- op0 -> LABEL_DECL | '*' ID
- | RETURN_EXPR
- op0 -> NULL_TREE
- | RESULT_DECL
- | MODIFY_EXPR -> RESULT_DECL, varname
- | THROW_EXPR? do we need/want such a thing for opts, perhaps
- to generate an ERT_THROW region? I think so.
- Hmm...this would only work at the GIMPLE level, where we know that
- the call args don't have any EH impact. Perhaps
- annotation of the CALL_EXPR would work better.
- | RESX_EXPR
- label-stmt:
- LABEL_EXPR
- op0 -> LABEL_DECL
- | CASE_LABEL_EXPR
- CASE_LOW -> val | NULL_TREE
- CASE_HIGH -> val | NULL_TREE
- CASE_LABEL -> LABEL_DECL FIXME
- try-stmt:
- TRY_CATCH_EXPR
- op0 -> stmt
- op1 -> handler
- | TRY_FINALLY_EXPR
- op0 -> stmt
- op1 -> stmt
- handler:
- catch-seq
- | EH_FILTER_EXPR
- | stmt
- modify-stmt:
- MODIFY_EXPR
- op0 -> lhs
- op1 -> rhs
- call-stmt: CALL_EXPR
- op0 -> ID | '&' ID | OBJ_TYPE_REF
- op1 -> arglist
-
- addr-expr-arg : compref | ID
- lhs: addr-expr-arg | '*' ID | bitfieldref
- min-lval: ID | '*' ID
- bitfieldref :
- BIT_FIELD_REF
- op0 -> inner_compref
- op1 -> CONST
- op2 -> var
- compref :
- COMPONENT_REF
- op0 -> inner_compref
- | ARRAY_REF
- op0 -> inner_compref
- op1 -> val
- op2 -> val
- op3 -> val
- | ARRAY_RANGE_REF
- op0 -> inner_compref
- op1 -> val
- op2 -> val
- op3 -> val
- | REALPART_EXPR
- op0 -> inner_compref
- | IMAGPART_EXPR
- op0 -> inner_compref
-
- inner_compref : compref | min_lval
- | VIEW_CONVERT_EXPR
- op0 -> inner_compref
- | NOP_EXPR
- op0 -> inner_compref
- | CONVERT_EXPR
- op0 -> inner_compref
-
- condition : val | val relop val
- val : ID | CONST
-
- rhs : varname | CONST
- | '*' ID
- | '&' addr-expr-arg
- | call_expr
- | unop val
- | val binop val
- | '(' cast ')' val
- | method_ref
-
- (cast here stands for all valid C typecasts)
-
- unop
- : '+'
- | '-'
- | '!'
- | '~'
-
- binop
- : relop | '-'
- | '+'
- | '/'
- | '*'
- | '%'
- | '&'
- | '|'
- | '<<'
- | '>>'
- | '^'
-
- relop
- : '<'
- | '<='
- | '>'
- | '>='
- | '=='
- | '!='
-
+ function : FUNCTION_DECL
+ DECL_SAVED_TREE -> compound-stmt
+
+ compound-stmt: STATEMENT_LIST
+ members -> stmt
+
+ stmt : block
+ | if-stmt
+ | switch-stmt
+ | goto-stmt
+ | return-stmt
+ | resx-stmt
+ | label-stmt
+ | try-stmt
+ | modify-stmt
+ | call-stmt
+
+ block : BIND_EXPR
+ BIND_EXPR_VARS -> chain of DECLs
+ BIND_EXPR_BLOCK -> BLOCK
+ BIND_EXPR_BODY -> compound-stmt
+
+ if-stmt : COND_EXPR
+ op0 -> condition
+ op1 -> compound-stmt
+ op2 -> compound-stmt
+
+ switch-stmt : SWITCH_EXPR
+ op0 -> val
+ op1 -> NULL
+ op2 -> TREE_VEC of CASE_LABEL_EXPRs
+ The CASE_LABEL_EXPRs are sorted by CASE_LOW,
+ and default is last.
+
+ goto-stmt : GOTO_EXPR
+ op0 -> LABEL_DECL | val
+
+ return-stmt : RETURN_EXPR
+ op0 -> return-value
+
+ return-value : NULL
+ | RESULT_DECL
+ | MODIFY_EXPR
+ op0 -> RESULT_DECL
+ op1 -> lhs
+
+ resx-stmt : RESX_EXPR
+
+ label-stmt : LABEL_EXPR
+ op0 -> LABEL_DECL
+
+ try-stmt : TRY_CATCH_EXPR
+ op0 -> compound-stmt
+ op1 -> handler
+ | TRY_FINALLY_EXPR
+ op0 -> compound-stmt
+ op1 -> compound-stmt
+
+ handler : catch-seq
+ | EH_FILTER_EXPR
+ | compound-stmt
+
+ catch-seq : STATEMENT_LIST
+ members -> CATCH_EXPR
+
+ modify-stmt : MODIFY_EXPR
+ op0 -> lhs
+ op1 -> rhs
+
+ call-stmt : CALL_EXPR
+ op0 -> val | OBJ_TYPE_REF
+ op1 -> call-arg-list
+
+ call-arg-list: TREE_LIST
+ members -> lhs
+
+ addr-expr-arg: ID
+ | compref
+
+ lhs : addr-expr-arg
+ | '*' val
+ | bitfieldref
+
+ min-lval : ID
+ | '*' val
+
+ bitfieldref : BIT_FIELD_REF
+ op0 -> inner-compref
+ op1 -> CONST
+ op2 -> var
+
+ compref : inner-compref
+ | REALPART_EXPR
+ op0 -> inner-compref
+ | IMAGPART_EXPR
+ op0 -> inner-compref
+
+ inner-compref: min-lval
+ | COMPONENT_REF
+ op0 -> inner-compref
+ op1 -> FIELD_DECL
+ op2 -> val
+ | ARRAY_REF
+ op0 -> inner-compref
+ op1 -> val
+ op2 -> val
+ op3 -> val
+ | ARRAY_RANGE_REF
+ op0 -> inner-compref
+ op1 -> val
+ op2 -> val
+ op3 -> val
+ | VIEW_CONVERT_EXPR
+ op0 -> inner-compref
+
+ condition : val
+ | val RELOP val
+
+ val : ID
+ | CONST
+
+ rhs : lhs
+ | CONST
+ | '&' addr-expr-arg
+ | call_expr
+ | UNOP val
+ | val BINOP val
+ | val RELOP val
*/
static inline bool is_gimple_id (tree);
/* Validation of GIMPLE expressions. */
-/* Return nonzero if T is a GIMPLE RHS:
-
- rhs : varname | CONST
- | '*' ID
- | '&' varname_or_temp
- | call_expr
- | unop val
- | val binop val
- | '(' cast ')' val
- | <CONSTRUCTOR <gimple_val ...>>
-
- The last option is only valid GIMPLE for vector and complex types;
- aggregate types should have their constructors decomposed. */
+/* Return true if T is a GIMPLE RHS. */
bool
is_gimple_rhs (tree t)
case '1':
case '2':
case '<':
- return 1;
+ return true;
default:
break;
case COMPLEX_CST:
case VECTOR_CST:
case OBJ_TYPE_REF:
- return 1;
+ return true;
default:
break;
}
- if (is_gimple_lvalue (t) || is_gimple_val (t))
- return 1;
-
- return 0;
+ return is_gimple_lvalue (t) || is_gimple_val (t);
}
-/* Returns nonzero if T is a valid CONSTRUCTOR component in GIMPLE, either
+/* Returns true if T is a valid CONSTRUCTOR component in GIMPLE, either
a val or another CONSTRUCTOR. */
bool
|| TREE_CODE (t) == CONSTRUCTOR);
}
-/* Return nonzero if T is a valid LHS for a GIMPLE assignment expression. */
+/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
bool
is_gimple_lvalue (tree t)
|| TREE_CODE (t) == BIT_FIELD_REF);
}
-
-/* Return nonzero if T is a GIMPLE condition:
-
- condexpr
- : val
- | val relop val */
+/* Return true if T is a GIMPLE condition. */
bool
is_gimple_condexpr (tree t)
|| TREE_CODE_CLASS (TREE_CODE (t)) == '<');
}
-
-/* Return nonzero if T is a valid operand for '&':
-
- varname
- : arrayref
- | compref
- | ID */
+/* Return true if T is a valid operand for ADDR_EXPR. */
bool
is_gimple_addr_expr_arg (tree t)
|| TREE_CODE (t) == INDIRECT_REF);
}
-/* Return nonzero if T is function invariant. Or rather a restricted
+/* Return true if T is function invariant. Or rather a restricted
form of function invariant. */
bool
}
}
-/* Return nonzero if T looks like a valid GIMPLE statement. */
+/* Return true if T looks like a valid GIMPLE statement. */
bool
is_gimple_stmt (tree t)
case PHI_NODE:
case STATEMENT_LIST:
/* These are always void. */
- return 1;
+ return true;
case VA_ARG_EXPR:
/* FIXME this should be lowered. */
- return 1;
+ return true;
- case COMPOUND_EXPR:
- /* FIXME should we work harder to make COMPOUND_EXPRs void? */
case CALL_EXPR:
case MODIFY_EXPR:
/* These are valid regardless of their type. */
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
-/* Return nonzero if T is a variable. */
+/* Return true if T is a variable. */
bool
is_gimple_variable (tree t)
|| TREE_CODE (t) == SSA_NAME);
}
-/* Return nonzero if T is a GIMPLE identifier (something with an address). */
+/* Return true if T is a GIMPLE identifier (something with an address). */
static inline bool
is_gimple_id (tree t)
|| TREE_CODE (t) == STRING_CST);
}
-/* Return nonzero if TYPE is a suitable type for a scalar register
- variable. */
+/* Return true if TYPE is a suitable type for a scalar register variable. */
bool
is_gimple_reg_type (tree type)
}
-/* Return nonzero if T is a scalar register variable. */
+/* Return true if T is a scalar register variable. */
bool
is_gimple_reg (tree t)
&& ! needs_to_live_in_memory (t));
}
-/* Return nonzero if T is a GIMPLE variable whose address is not needed. */
+/* Return true if T is a GIMPLE variable whose address is not needed. */
bool
is_gimple_non_addressable (tree t)
&& ! needs_to_live_in_memory (t));
}
-/* Return nonzero if T is a GIMPLE rvalue, i.e. an identifier or a
- constant. */
+/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
bool
is_gimple_val (tree t)
if (is_gimple_variable (t)
&& is_gimple_reg_type (TREE_TYPE (t))
&& !is_gimple_reg (t))
- return 0;
+ return false;
/* FIXME make these decls. That can happen only when we expose the
entire landing-pad construct at the tree level. */
}
-/* Return true if T is a GIMPLE minimal lvalue, of the form
-
- min_lval: ID | '(' '*' ID ')'
-
- This never actually appears in the original SIMPLE grammar, but is
- repeated in several places. */
+/* Return true if T is a GIMPLE minimal lvalue. */
bool
is_gimple_min_lval (tree t)
|| TREE_CODE (t) == INDIRECT_REF);
}
-/* Return nonzero if T is a typecast operation of the form
- '(' cast ')' val. */
+/* Return true if T is a typecast operation. */
bool
is_gimple_cast (tree t)
tree
get_call_expr_in (tree t)
{
+ if (TREE_CODE (t) == MODIFY_EXPR)
+ t = TREE_OPERAND (t, 1);
if (TREE_CODE (t) == CALL_EXPR)
return t;
- else if (TREE_CODE (t) == MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
- return TREE_OPERAND (t, 1);
- else if (TREE_CODE (t) == RETURN_EXPR
- && TREE_OPERAND (t, 0)
- && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == CALL_EXPR)
- return TREE_OPERAND (TREE_OPERAND (t, 0), 1);
-
return NULL_TREE;
}