void gimple_return_set_retval (gimple gs, tree retval) { const_gimple __gs = (gs); if (gimple_code (__gs) != (GIMPLE_RETURN)) abort (); gimple_set_op (gs, 0, retval); }
void gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) { size_t i, num_ops; tree lhs; gimple_seq pre = NULL; gimple post_stmt = NULL; push_gimplify_context (gimple_in_ssa_p (cfun)); switch (gimple_code (stmt)) { case GIMPLE_COND: gimplify_expr (gimple_cond_lhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_SWITCH: gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_OMP_ATOMIC_LOAD: gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; case GIMPLE_ASM: { size_t i, noutputs = gimple_asm_noutputs (stmt); const char *constraint, **oconstraints; bool allows_mem, allows_reg, is_inout; oconstraints = (const char **) alloca ((noutputs) * sizeof (const char *)); for (i = 0; i < noutputs; i++) { tree op = gimple_asm_output_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); oconstraints[i] = constraint; parse_output_constraint (&constraint, i, 0, 0, &allows_mem, &allows_reg, &is_inout); gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_inout ? is_gimple_min_lval : is_gimple_lvalue, fb_lvalue | fb_mayfail); } for (i = 0; i < gimple_asm_ninputs (stmt); i++) { tree op = gimple_asm_input_op (stmt, i); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op))); parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg); if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem) allows_reg = 0; if (!allows_reg && allows_mem) gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_lvalue, fb_lvalue | fb_mayfail); else gimplify_expr (&TREE_VALUE (op), &pre, NULL, is_gimple_asm_val, fb_rvalue); } } break; default: /* NOTE: We start gimplifying operands from last to first to make sure that side-effects on the RHS of calls, assignments and ASMs are executed before the LHS. The ordering is not important for other statements. */ num_ops = gimple_num_ops (stmt); for (i = num_ops; i > 0; i--) { tree op = gimple_op (stmt, i - 1); if (op == NULL_TREE) continue; if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt))) gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue); else if (i == 2 && is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (&op, &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (i == 2 && is_gimple_call (stmt)) { if (TREE_CODE (op) == FUNCTION_DECL) continue; gimplify_expr (&op, &pre, NULL, is_gimple_call_addr, fb_rvalue); } else gimplify_expr (&op, &pre, NULL, is_gimple_val, fb_rvalue); gimple_set_op (stmt, i - 1, op); } lhs = gimple_get_lhs (stmt); /* If the LHS changed it in a way that requires a simple RHS, create temporary. */ if (lhs && !is_gimple_reg (lhs)) { bool need_temp = false; if (is_gimple_assign (stmt) && num_ops == 2 && get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS) gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL, rhs_predicate_for (gimple_assign_lhs (stmt)), fb_rvalue); else if (is_gimple_reg (lhs)) { if (is_gimple_reg_type (TREE_TYPE (lhs))) { if (is_gimple_call (stmt)) { i = gimple_call_flags (stmt); if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE))) need_temp = true; } if (stmt_can_throw_internal (stmt)) need_temp = true; } } else { if (is_gimple_reg_type (TREE_TYPE (lhs))) need_temp = true; else if (TYPE_MODE (TREE_TYPE (lhs)) != BLKmode) { if (is_gimple_call (stmt)) { tree fndecl = gimple_call_fndecl (stmt); if (!aggregate_value_p (TREE_TYPE (lhs), fndecl) && !(fndecl && DECL_RESULT (fndecl) && DECL_BY_REFERENCE (DECL_RESULT (fndecl)))) need_temp = true; } else need_temp = true; } } if (need_temp) { tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL); if (gimple_in_ssa_p (cfun)) temp = make_ssa_name (temp, NULL); gimple_set_lhs (stmt, temp); post_stmt = gimple_build_assign (lhs, temp); } } break; } if (!gimple_seq_empty_p (pre)) gsi_insert_seq_before (gsi_p, pre, GSI_SAME_STMT); if (post_stmt) gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT); pop_gimplify_context (NULL); }
static gimple input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, struct function *fn, enum LTO_tags tag) { gimple stmt; enum gimple_code code; unsigned HOST_WIDE_INT num_ops; size_t i; struct bitpack_d bp; code = lto_tag_to_gimple_code (tag); /* Read the tuple header. */ bp = streamer_read_bitpack (ib); num_ops = bp_unpack_var_len_unsigned (&bp); stmt = gimple_alloc (code, num_ops); stmt->gsbase.no_warning = bp_unpack_value (&bp, 1); if (is_gimple_assign (stmt)) stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1); stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1); stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp); /* Read location information. */ gimple_set_location (stmt, lto_input_location (ib, data_in)); /* Read lexical block reference. */ gimple_set_block (stmt, stream_read_tree (ib, data_in)); /* Read in all the operands. */ switch (code) { case GIMPLE_RESX: gimple_resx_set_region (stmt, streamer_read_hwi (ib)); break; case GIMPLE_EH_MUST_NOT_THROW: gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in)); break; case GIMPLE_EH_DISPATCH: gimple_eh_dispatch_set_region (stmt, streamer_read_hwi (ib)); break; case GIMPLE_ASM: { /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ tree str; stmt->gimple_asm.ni = streamer_read_uhwi (ib); stmt->gimple_asm.no = streamer_read_uhwi (ib); stmt->gimple_asm.nc = streamer_read_uhwi (ib); stmt->gimple_asm.nl = streamer_read_uhwi (ib); str = streamer_read_string_cst (data_in, ib); stmt->gimple_asm.string = TREE_STRING_POINTER (str); } /* Fallthru */ case GIMPLE_ASSIGN: case GIMPLE_CALL: case GIMPLE_RETURN: case GIMPLE_SWITCH: case GIMPLE_LABEL: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_DEBUG: for (i = 0; i < num_ops; i++) { tree op = stream_read_tree (ib, data_in); gimple_set_op (stmt, i, op); if (!op) continue; /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled by decl merging. */ if (TREE_CODE (op) == ADDR_EXPR) op = TREE_OPERAND (op, 0); while (handled_component_p (op)) { if (TREE_CODE (op) == COMPONENT_REF) { tree field, type, tem; tree closest_match = NULL_TREE; field = TREE_OPERAND (op, 1); type = DECL_CONTEXT (field); for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { if (TREE_CODE (tem) != FIELD_DECL) continue; if (tem == field) break; if (DECL_NONADDRESSABLE_P (tem) == DECL_NONADDRESSABLE_P (field) && gimple_compare_field_offset (tem, field)) { if (types_compatible_p (TREE_TYPE (tem), TREE_TYPE (field))) break; else closest_match = tem; } } /* In case of type mismatches across units we can fail to unify some types and thus not find a proper field-decl here. */ if (tem == NULL_TREE) { /* Thus, emit a ODR violation warning. */ if (warning_at (gimple_location (stmt), 0, "use of type %<%E%> with two mismatching " "declarations at field %<%E%>", type, TREE_OPERAND (op, 1))) { if (TYPE_FIELDS (type)) inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)), "original type declared here"); inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)), "field in mismatching type declared here"); if (TYPE_NAME (TREE_TYPE (field)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (field))), "type of field declared here"); if (closest_match && TYPE_NAME (TREE_TYPE (closest_match)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (closest_match))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (closest_match))), "type of mismatching field declared here"); } /* And finally fixup the types. */ TREE_OPERAND (op, 0) = build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op, 0)); } else TREE_OPERAND (op, 1) = tem; } op = TREE_OPERAND (op, 0); } } if (is_gimple_call (stmt)) { if (gimple_call_internal_p (stmt)) gimple_call_set_internal_fn (stmt, streamer_read_enum (ib, internal_fn, IFN_LAST)); else gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in)); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gimple_transaction_set_label (stmt, stream_read_tree (ib, data_in)); break; default: internal_error ("bytecode stream: unknown GIMPLE statement tag %s", lto_tag_name (tag)); } /* Update the properties of symbols, SSA names and labels associated with STMT. */ if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL) { tree lhs = gimple_get_lhs (stmt); if (lhs && TREE_CODE (lhs) == SSA_NAME) SSA_NAME_DEF_STMT (lhs) = stmt; } else if (code == GIMPLE_LABEL) gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt)) || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl); else if (code == GIMPLE_ASM) { unsigned i; for (i = 0; i < gimple_asm_noutputs (stmt); i++) { tree op = TREE_VALUE (gimple_asm_output_op (stmt, i)); if (TREE_CODE (op) == SSA_NAME) SSA_NAME_DEF_STMT (op) = stmt; } } /* Reset alias information. */ if (code == GIMPLE_CALL) gimple_call_reset_alias_info (stmt); /* Mark the statement modified so its operand vectors can be filled in. */ gimple_set_modified (stmt, true); return stmt; }
static gimple * input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, enum LTO_tags tag) { gimple *stmt; enum gimple_code code; unsigned HOST_WIDE_INT num_ops; size_t i; struct bitpack_d bp; bool has_hist; code = lto_tag_to_gimple_code (tag); /* Read the tuple header. */ bp = streamer_read_bitpack (ib); num_ops = bp_unpack_var_len_unsigned (&bp); stmt = gimple_alloc (code, num_ops); stmt->no_warning = bp_unpack_value (&bp, 1); if (is_gimple_assign (stmt)) stmt->nontemporal_move = bp_unpack_value (&bp, 1); stmt->has_volatile_ops = bp_unpack_value (&bp, 1); has_hist = bp_unpack_value (&bp, 1); stmt->subcode = bp_unpack_var_len_unsigned (&bp); /* Read location information. Caching here makes no sense until streamer cache can handle the following gimple_set_block. */ gimple_set_location (stmt, stream_input_location_now (&bp, data_in)); /* Read lexical block reference. */ gimple_set_block (stmt, stream_read_tree (ib, data_in)); /* Read in all the operands. */ switch (code) { case GIMPLE_RESX: gimple_resx_set_region (as_a <gresx *> (stmt), streamer_read_hwi (ib)); break; case GIMPLE_EH_MUST_NOT_THROW: gimple_eh_must_not_throw_set_fndecl ( as_a <geh_mnt *> (stmt), stream_read_tree (ib, data_in)); break; case GIMPLE_EH_DISPATCH: gimple_eh_dispatch_set_region (as_a <geh_dispatch *> (stmt), streamer_read_hwi (ib)); break; case GIMPLE_ASM: { /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ gasm *asm_stmt = as_a <gasm *> (stmt); tree str; asm_stmt->ni = streamer_read_uhwi (ib); asm_stmt->no = streamer_read_uhwi (ib); asm_stmt->nc = streamer_read_uhwi (ib); asm_stmt->nl = streamer_read_uhwi (ib); str = streamer_read_string_cst (data_in, ib); asm_stmt->string = TREE_STRING_POINTER (str); } /* Fallthru */ case GIMPLE_ASSIGN: case GIMPLE_CALL: case GIMPLE_RETURN: case GIMPLE_SWITCH: case GIMPLE_LABEL: case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_DEBUG: for (i = 0; i < num_ops; i++) { tree *opp, op = stream_read_tree (ib, data_in); gimple_set_op (stmt, i, op); if (!op) continue; opp = gimple_op_ptr (stmt, i); if (TREE_CODE (*opp) == ADDR_EXPR) opp = &TREE_OPERAND (*opp, 0); while (handled_component_p (*opp)) opp = &TREE_OPERAND (*opp, 0); /* At LTO output time we wrap all global decls in MEM_REFs to allow seamless replacement with prevailing decls. Undo this here if the prevailing decl allows for this. ??? Maybe we should simply fold all stmts. */ if (TREE_CODE (*opp) == MEM_REF && TREE_CODE (TREE_OPERAND (*opp, 0)) == ADDR_EXPR && integer_zerop (TREE_OPERAND (*opp, 1)) && (TREE_THIS_VOLATILE (*opp) == TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0))) && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*opp, 1))) && (TREE_TYPE (*opp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (*opp, 1)))) && (TREE_TYPE (*opp) == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0)))) *opp = TREE_OPERAND (TREE_OPERAND (*opp, 0), 0); } if (gcall *call_stmt = dyn_cast <gcall *> (stmt)) { if (gimple_call_internal_p (call_stmt)) gimple_call_set_internal_fn (call_stmt, streamer_read_enum (ib, internal_fn, IFN_LAST)); else gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in)); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gimple_transaction_set_label (as_a <gtransaction *> (stmt), stream_read_tree (ib, data_in)); break; default: internal_error ("bytecode stream: unknown GIMPLE statement tag %s", lto_tag_name (tag)); } /* Update the properties of symbols, SSA names and labels associated with STMT. */ if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL) { tree lhs = gimple_get_lhs (stmt); if (lhs && TREE_CODE (lhs) == SSA_NAME) SSA_NAME_DEF_STMT (lhs) = stmt; } else if (code == GIMPLE_ASM) { gasm *asm_stmt = as_a <gasm *> (stmt); unsigned i; for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++) { tree op = TREE_VALUE (gimple_asm_output_op (asm_stmt, i)); if (TREE_CODE (op) == SSA_NAME) SSA_NAME_DEF_STMT (op) = stmt; } } /* Reset alias information. */ if (code == GIMPLE_CALL) gimple_call_reset_alias_info (as_a <gcall *> (stmt)); /* Mark the statement modified so its operand vectors can be filled in. */ gimple_set_modified (stmt, true); if (has_hist) stream_in_histogram_value (ib, stmt); return stmt; }