diff options
author | Diego Novillo <dnovillo@google.com> | 2013-11-08 17:46:16 -0500 |
---|---|---|
committer | Diego Novillo <dnovillo@gcc.gnu.org> | 2013-11-08 17:46:16 -0500 |
commit | 862d0b359fb98790d5fad654eecf471228d8bb77 (patch) | |
tree | 956d82c4131695b3b703c5ba7a83a02ad61d5928 /gcc/stmt.c | |
parent | f0e56cd667259c3bc4234cb75c5137136af7b25d (diff) | |
download | gcc-862d0b359fb98790d5fad654eecf471228d8bb77.zip gcc-862d0b359fb98790d5fad654eecf471228d8bb77.tar.gz gcc-862d0b359fb98790d5fad654eecf471228d8bb77.tar.bz2 |
Re-factor tree.h - Part 1.
This is the first patch in a series of patches to cleanup tree.h to
reduce the exposure it has all over the compiler.
In this patch, I'm moving functions that are used once into the files
that use them, and make them private to that file. These functions
were declared extern in tree.h and called from exactly one place.
The patch does not move EVERY function. This usually happens
when the function uses private state from its original file, and
moving that private state would mean moving other functions that made
no sense to move.
Additionally, the patch removes functions that were never used.
In subsequent patches, I will be moving out of tree.h extern definitions
that should be grouped in other files (e.g., all functions defined in
some FOO.c will be moved to the corresponding FOO.h). This will allow
me to remove the inclusion of tree.h from some files.
* attribs.c (lookup_scoped_attribute_spec): Make static.
(get_attribute_namespace): Likewise.
* builtins.c (more_const_call_expr_args_p): Move from
tree.h.
(validate_arglist): Move earlier in the file. Make static.
(expand_stack_restore): Move from stmt.c
(expand_stack_save): Move from stmt.c
(rewrite_call_expr_array): Move earlier in the file.
(rewrite_call_expr_valist): Likewise.
* cfgexpand.c: Include hard-reg-set.h before tree.h
Include recog.h.
Include output.h.
(expand_asm_loc): Move from stmt.c.
(n_occurrences): Move from stmt.c.
(check_operand_nalternatives): Move from stmt.c.
(tree_conflicts_with_clobbers_p): Move from stmt.c.
(expand_asm_operands): Move from stmt.c
(expand_asm_stmt): Move from stmt.c
(expand_computed_goto): Move from stmt.c
(expand_goto): Move from stmt.c
(expand_null_return_1): Move from stmt.c
(expand_null_return): Move from stmt.c
(expand_value_return): Move from stmt.c
(expand_return): Move from stmt.c
(expand_main_function): Move from function.c
(stack_protect_prologue): Move from function.c
* cgraphclones.c (build_function_type_skip_args): Move from tree.c.
(build_function_decl_skip_args): Move from tree.c.
* explow.c (tree_expr_size): Move from tree.c.
* expr.c (addr_expr_of_non_mem_decl_p): Remove.
(fields_length): Move from tree.c.
* fold-const.c (size_low_cst): Move from tree.c.
(tree_expr_nonzero_warnv_p): Make static. Move earlier in the file.
(tree_expr_nonzero_p): Make static. Move earlier in the file.
(fold_build3_initializer_loc): Remove.
(tree_invalid_nonnegative_warnv_p): Make static.
* function.c (expand_main_function): Move to cfgexpand.c.
(stack_protect_prologue): Move to cfgexpand.c.
(set_insn_locations): Move earlier in the file.
* gimple-fold.c: Include langhooks.h.
(truth_type_for): Move from tree.c.
* print-tree.c (print_vec_tree): Remove.
* stmt.c (expand_computed_goto): Move to cfgexpand.c.
(expand_goto): Move to cfgexpand.c.
(n_occurrences): Move to cfgexpand.c.
(expand_asm_loc): Move to cfgexpand.c
(tree_conflicts_with_clobbers_p): Move to cfgexpand.c.
(expand_asm_operands): Move to cfgexpand.c.
(expand_asm_stmt): Move to cfgexpand.c.
(check_operand_nalternatives): Move to cfgexpand.c
(expand_null_return): Move to cfgexpand.c.
(expand_value_return): Move to cfgexpand.c.
(expand_null_return_1): Move to cfgexpand.c.
(expand_return): Move to cfgexpand.c.
(expand_stack_save): Move to builtins.c.
(expand_stack_restore): Move to builtins.c
* symtab.c: Include output.h.
(decl_assembler_name_hash): Move from tree.c.
(decl_assembler_name_equal): Move from tree.c.
* trans-mem.c (is_tm_safe_or_pure): Move from tree.h.
* tree-eh.c (in_array_bounds_p): Move from tree.c.
(range_in_array_bounds_p): Move from tree.c.
* tree-object-size.c (fini_object_sizes): Make static.
* tree-ssa-dom.c (iterative_hash_exprs_commutative): Move from tree.h.
* tree-vrp.c (ssa_name_nonnegative_p): Remove.
* tree.c (decl_assembler_name_equal): Move to symtab.c.
(tree_expr_size): Move to explow.c.
(decl_assembler_name_hash): Move to symtab.c.
(real_twop): Remove.
(tree_expr_size): Move to explow.c.
(stabilize_reference_1): Move earlier in the file. Make static.
(omp_remove_redundant_declare_simd_attrs): Remove.
(simple_cst_list_equal): Move earlier in the file. Make static.
(size_low_cst): Move to fold-const.c.
(build_type_no_quals): Remove.
(build_function_type_skip_args): Move to cgraphclones.c.
(build_function_decl_skip_args): Move to cgraphclones.c.
(in_array_bounds_p): Move to tree-eh.c.
(range_in_array_bounds_p): Move to tree-eh.c.
(truth_type_for): Move to gimple-fold.c.
(list_equal_p): remove.
* tree.h (decl_assembler_name_equal): Remove.
(decl_assembler_name_hash): Remove.
(truth_type_for): Remove.
(build_type_no_quals): Remove.
(build_function_decl_skip_args): Remove.
(in_array_bounds_p): Remove.
(range_in_array_bounds_p): Remove.
(size_low_cst): Remove.
(omp_remove_redundant_declare_simd_attrs): Remove.
(tree_expr_size): Remove.
(fields_length): Remove.
(stabilize_reference_1): Remove.
(expand_goto): Remove.
(expand_stack_save): Remove.
(expand_stack_restore): Remove.
(expand_return): Remove.
(fold_build3_initializer_loc): Remove.
(tree_expr_nonzero_p): Remove.
(tree_invalid_nonnegative_warnv_p): Remove.
(tree_expr_nonzero_warnv_p): Remove.
(fold_builtin_snprintf_chk): Remove.
(validate_arglist): Remove.
(iterative_hash_exprs_commutative): Move to tree-ssa-dom.c.
(simple_cst_list_equal): Remove.
(real_twop): Remove.
(expand_main_function): Remove.
(stack_protect_prologue): Remove.
(print_vec_tree): Remove.
(lookup_scoped_attribute_spec): Remove.
(get_attribute_namespace): Remove.
(expand_computed_goto): Remove.
(expand_asm_stmt): Remove.
(list_equal_p): Remove.
(ssa_name_nonnegative_p): Remove.
(fini_object_sizes): Remove.
(addr_expr_of_non_mem_decl_p): Remove.
(is_tm_safe_or_pure): Move to trans-mem.c.
(more_const_call_expr_args_p): Remove.
(save_vtable_map_decl): Remove.
From-SVN: r204606
Diffstat (limited to 'gcc/stmt.c')
-rw-r--r-- | gcc/stmt.c | 886 |
1 files changed, 0 insertions, 886 deletions
@@ -102,13 +102,8 @@ typedef struct case_node *case_node_ptr; extern basic_block label_to_block_fn (struct function *, tree); -static int n_occurrences (int, const char *); -static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *); -static bool check_operand_nalternatives (tree, tree); static bool check_unique_operand_names (tree, tree, tree); static char *resolve_operand_name_1 (char *, tree, tree, tree); -static void expand_null_return_1 (void); -static void expand_value_return (rtx); static void balance_case_nodes (case_node_ptr *, case_node_ptr); static int node_has_low_bound (case_node_ptr, tree); static int node_has_high_bound (case_node_ptr, tree); @@ -157,20 +152,6 @@ emit_jump (rtx label) emit_jump_insn (gen_jump (label)); emit_barrier (); } - -/* Emit code to jump to the address - specified by the pointer expression EXP. */ - -void -expand_computed_goto (tree exp) -{ - rtx x = expand_normal (exp); - - x = convert_memory_address (Pmode, x); - - do_pending_stack_adjust (); - emit_indirect_jump (x); -} /* Handle goto statements and the labels that they can go to. */ @@ -209,56 +190,7 @@ expand_label (tree label) if (DECL_NONLOCAL (label) || FORCED_LABEL (label)) maybe_set_first_label_num (label_r); } - -/* Generate RTL code for a `goto' statement with target label LABEL. - LABEL should be a LABEL_DECL tree node that was or will later be - defined with `expand_label'. */ - -void -expand_goto (tree label) -{ -#ifdef ENABLE_CHECKING - /* Check for a nonlocal goto to a containing function. Should have - gotten translated to __builtin_nonlocal_goto. */ - tree context = decl_function_context (label); - gcc_assert (!context || context == current_function_decl); -#endif - - emit_jump (label_rtx (label)); -} - -/* Return the number of times character C occurs in string S. */ -static int -n_occurrences (int c, const char *s) -{ - int n = 0; - while (*s) - n += (*s++ == c); - return n; -} -/* Generate RTL for an asm statement (explicit assembler code). - STRING is a STRING_CST node containing the assembler code text, - or an ADDR_EXPR containing a STRING_CST. VOL nonzero means the - insn is volatile; don't optimize it. */ - -static void -expand_asm_loc (tree string, int vol, location_t locus) -{ - rtx body; - - if (TREE_CODE (string) == ADDR_EXPR) - string = TREE_OPERAND (string, 0); - - body = gen_rtx_ASM_INPUT_loc (VOIDmode, - ggc_strdup (TREE_STRING_POINTER (string)), - locus); - - MEM_VOLATILE_P (body) = vol; - - emit_insn (body); -} - /* Parse the output constraint pointed to by *CONSTRAINT_P. It is the OPERAND_NUMth output operand, indexed from zero. There are NINPUTS inputs and NOUTPUTS outputs to this extended-asm. Upon return, @@ -577,663 +509,6 @@ tree_overlaps_hard_reg_set (tree decl, HARD_REG_SET *regs) return walk_tree (&decl, decl_overlaps_hard_reg_set_p, regs, NULL); } -/* Check for overlap between registers marked in CLOBBERED_REGS and - anything inappropriate in T. Emit error and return the register - variable definition for error, NULL_TREE for ok. */ - -static bool -tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs) -{ - /* Conflicts between asm-declared register variables and the clobber - list are not allowed. */ - tree overlap = tree_overlaps_hard_reg_set (t, clobbered_regs); - - if (overlap) - { - error ("asm-specifier for variable %qE conflicts with asm clobber list", - DECL_NAME (overlap)); - - /* Reset registerness to stop multiple errors emitted for a single - variable. */ - DECL_REGISTER (overlap) = 0; - return true; - } - - return false; -} - -/* Generate RTL for an asm statement with arguments. - STRING is the instruction template. - OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs. - Each output or input has an expression in the TREE_VALUE and - a tree list in TREE_PURPOSE which in turn contains a constraint - name in TREE_VALUE (or NULL_TREE) and a constraint string - in TREE_PURPOSE. - CLOBBERS is a list of STRING_CST nodes each naming a hard register - that is clobbered by this insn. - - LABELS is a list of labels, and if LABELS is non-NULL, FALLTHRU_BB - should be the fallthru basic block of the asm goto. - - Not all kinds of lvalue that may appear in OUTPUTS can be stored directly. - Some elements of OUTPUTS may be replaced with trees representing temporary - values. The caller should copy those temporary values to the originally - specified lvalues. - - VOL nonzero means the insn is volatile; don't optimize it. */ - -static void -expand_asm_operands (tree string, tree outputs, tree inputs, - tree clobbers, tree labels, basic_block fallthru_bb, - int vol, location_t locus) -{ - rtvec argvec, constraintvec, labelvec; - rtx body; - int ninputs = list_length (inputs); - int noutputs = list_length (outputs); - int nlabels = list_length (labels); - int ninout; - int nclobbers; - HARD_REG_SET clobbered_regs; - int clobber_conflict_found = 0; - tree tail; - tree t; - int i; - /* Vector of RTX's of evaluated output operands. */ - rtx *output_rtx = XALLOCAVEC (rtx, noutputs); - int *inout_opnum = XALLOCAVEC (int, noutputs); - rtx *real_output_rtx = XALLOCAVEC (rtx, noutputs); - enum machine_mode *inout_mode = XALLOCAVEC (enum machine_mode, noutputs); - const char **constraints = XALLOCAVEC (const char *, noutputs + ninputs); - int old_generating_concat_p = generating_concat_p; - rtx fallthru_label = NULL_RTX; - - /* An ASM with no outputs needs to be treated as volatile, for now. */ - if (noutputs == 0) - vol = 1; - - if (! check_operand_nalternatives (outputs, inputs)) - return; - - string = resolve_asm_operand_names (string, outputs, inputs, labels); - - /* Collect constraints. */ - i = 0; - for (t = outputs; t ; t = TREE_CHAIN (t), i++) - constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); - for (t = inputs; t ; t = TREE_CHAIN (t), i++) - constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); - - /* Sometimes we wish to automatically clobber registers across an asm. - Case in point is when the i386 backend moved from cc0 to a hard reg -- - maintaining source-level compatibility means automatically clobbering - the flags register. */ - clobbers = targetm.md_asm_clobbers (outputs, inputs, clobbers); - - /* Count the number of meaningful clobbered registers, ignoring what - we would ignore later. */ - nclobbers = 0; - CLEAR_HARD_REG_SET (clobbered_regs); - for (tail = clobbers; tail; tail = TREE_CHAIN (tail)) - { - const char *regname; - int nregs; - - if (TREE_VALUE (tail) == error_mark_node) - return; - regname = TREE_STRING_POINTER (TREE_VALUE (tail)); - - i = decode_reg_name_and_count (regname, &nregs); - if (i == -4) - ++nclobbers; - else if (i == -2) - error ("unknown register name %qs in %<asm%>", regname); - - /* Mark clobbered registers. */ - if (i >= 0) - { - int reg; - - for (reg = i; reg < i + nregs; reg++) - { - ++nclobbers; - - /* Clobbering the PIC register is an error. */ - if (reg == (int) PIC_OFFSET_TABLE_REGNUM) - { - error ("PIC register clobbered by %qs in %<asm%>", regname); - return; - } - - SET_HARD_REG_BIT (clobbered_regs, reg); - } - } - } - - /* First pass over inputs and outputs checks validity and sets - mark_addressable if needed. */ - - ninout = 0; - for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - { - tree val = TREE_VALUE (tail); - tree type = TREE_TYPE (val); - const char *constraint; - bool is_inout; - bool allows_reg; - bool allows_mem; - - /* If there's an erroneous arg, emit no insn. */ - if (type == error_mark_node) - return; - - /* Try to parse the output constraint. If that fails, there's - no point in going further. */ - constraint = constraints[i]; - if (!parse_output_constraint (&constraint, i, ninputs, noutputs, - &allows_mem, &allows_reg, &is_inout)) - return; - - if (! allows_reg - && (allows_mem - || is_inout - || (DECL_P (val) - && REG_P (DECL_RTL (val)) - && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))) - mark_addressable (val); - - if (is_inout) - ninout++; - } - - ninputs += ninout; - if (ninputs + noutputs > MAX_RECOG_OPERANDS) - { - error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS); - return; - } - - for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail)) - { - bool allows_reg, allows_mem; - const char *constraint; - - /* If there's an erroneous arg, emit no insn, because the ASM_INPUT - would get VOIDmode and that could cause a crash in reload. */ - if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node) - return; - - constraint = constraints[i + noutputs]; - if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout, - constraints, &allows_mem, &allows_reg)) - return; - - if (! allows_reg && allows_mem) - mark_addressable (TREE_VALUE (tail)); - } - - /* Second pass evaluates arguments. */ - - /* Make sure stack is consistent for asm goto. */ - if (nlabels > 0) - do_pending_stack_adjust (); - - ninout = 0; - for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - { - tree val = TREE_VALUE (tail); - tree type = TREE_TYPE (val); - bool is_inout; - bool allows_reg; - bool allows_mem; - rtx op; - bool ok; - - ok = parse_output_constraint (&constraints[i], i, ninputs, - noutputs, &allows_mem, &allows_reg, - &is_inout); - gcc_assert (ok); - - /* If an output operand is not a decl or indirect ref and our constraint - allows a register, make a temporary to act as an intermediate. - Make the asm insn write into that, then our caller will copy it to - the real output operand. Likewise for promoted variables. */ - - generating_concat_p = 0; - - real_output_rtx[i] = NULL_RTX; - if ((TREE_CODE (val) == INDIRECT_REF - && allows_mem) - || (DECL_P (val) - && (allows_mem || REG_P (DECL_RTL (val))) - && ! (REG_P (DECL_RTL (val)) - && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))) - || ! allows_reg - || is_inout) - { - op = expand_expr (val, NULL_RTX, VOIDmode, - !allows_reg ? EXPAND_MEMORY : EXPAND_WRITE); - if (MEM_P (op)) - op = validize_mem (op); - - if (! allows_reg && !MEM_P (op)) - error ("output number %d not directly addressable", i); - if ((! allows_mem && MEM_P (op)) - || GET_CODE (op) == CONCAT) - { - real_output_rtx[i] = op; - op = gen_reg_rtx (GET_MODE (op)); - if (is_inout) - emit_move_insn (op, real_output_rtx[i]); - } - } - else - { - op = assign_temp (type, 0, 1); - op = validize_mem (op); - if (!MEM_P (op) && TREE_CODE (TREE_VALUE (tail)) == SSA_NAME) - set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (TREE_VALUE (tail)), op); - TREE_VALUE (tail) = make_tree (type, op); - } - output_rtx[i] = op; - - generating_concat_p = old_generating_concat_p; - - if (is_inout) - { - inout_mode[ninout] = TYPE_MODE (type); - inout_opnum[ninout++] = i; - } - - if (tree_conflicts_with_clobbers_p (val, &clobbered_regs)) - clobber_conflict_found = 1; - } - - /* Make vectors for the expression-rtx, constraint strings, - and named operands. */ - - argvec = rtvec_alloc (ninputs); - constraintvec = rtvec_alloc (ninputs); - labelvec = rtvec_alloc (nlabels); - - body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode - : GET_MODE (output_rtx[0])), - ggc_strdup (TREE_STRING_POINTER (string)), - empty_string, 0, argvec, constraintvec, - labelvec, locus); - - MEM_VOLATILE_P (body) = vol; - - /* Eval the inputs and put them into ARGVEC. - Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */ - - for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i) - { - bool allows_reg, allows_mem; - const char *constraint; - tree val, type; - rtx op; - bool ok; - - constraint = constraints[i + noutputs]; - ok = parse_input_constraint (&constraint, i, ninputs, noutputs, ninout, - constraints, &allows_mem, &allows_reg); - gcc_assert (ok); - - generating_concat_p = 0; - - val = TREE_VALUE (tail); - type = TREE_TYPE (val); - /* EXPAND_INITIALIZER will not generate code for valid initializer - constants, but will still generate code for other types of operand. - This is the behavior we want for constant constraints. */ - op = expand_expr (val, NULL_RTX, VOIDmode, - allows_reg ? EXPAND_NORMAL - : allows_mem ? EXPAND_MEMORY - : EXPAND_INITIALIZER); - - /* Never pass a CONCAT to an ASM. */ - if (GET_CODE (op) == CONCAT) - op = force_reg (GET_MODE (op), op); - else if (MEM_P (op)) - op = validize_mem (op); - - if (asm_operand_ok (op, constraint, NULL) <= 0) - { - if (allows_reg && TYPE_MODE (type) != BLKmode) - op = force_reg (TYPE_MODE (type), op); - else if (!allows_mem) - warning (0, "asm operand %d probably doesn%'t match constraints", - i + noutputs); - else if (MEM_P (op)) - { - /* We won't recognize either volatile memory or memory - with a queued address as available a memory_operand - at this point. Ignore it: clearly this *is* a memory. */ - } - else - gcc_unreachable (); - } - - generating_concat_p = old_generating_concat_p; - ASM_OPERANDS_INPUT (body, i) = op; - - ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i) - = gen_rtx_ASM_INPUT (TYPE_MODE (type), - ggc_strdup (constraints[i + noutputs])); - - if (tree_conflicts_with_clobbers_p (val, &clobbered_regs)) - clobber_conflict_found = 1; - } - - /* Protect all the operands from the queue now that they have all been - evaluated. */ - - generating_concat_p = 0; - - /* For in-out operands, copy output rtx to input rtx. */ - for (i = 0; i < ninout; i++) - { - int j = inout_opnum[i]; - char buffer[16]; - - ASM_OPERANDS_INPUT (body, ninputs - ninout + i) - = output_rtx[j]; - - sprintf (buffer, "%d", j); - ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i) - = gen_rtx_ASM_INPUT (inout_mode[i], ggc_strdup (buffer)); - } - - /* Copy labels to the vector. */ - for (i = 0, tail = labels; i < nlabels; ++i, tail = TREE_CHAIN (tail)) - { - rtx r; - /* If asm goto has any labels in the fallthru basic block, use - a label that we emit immediately after the asm goto. Expansion - may insert further instructions into the same basic block after - asm goto and if we don't do this, insertion of instructions on - the fallthru edge might misbehave. See PR58670. */ - if (fallthru_bb - && label_to_block_fn (cfun, TREE_VALUE (tail)) == fallthru_bb) - { - if (fallthru_label == NULL_RTX) - fallthru_label = gen_label_rtx (); - r = fallthru_label; - } - else - r = label_rtx (TREE_VALUE (tail)); - ASM_OPERANDS_LABEL (body, i) = gen_rtx_LABEL_REF (Pmode, r); - } - - generating_concat_p = old_generating_concat_p; - - /* Now, for each output, construct an rtx - (set OUTPUT (asm_operands INSN OUTPUTCONSTRAINT OUTPUTNUMBER - ARGVEC CONSTRAINTS OPNAMES)) - If there is more than one, put them inside a PARALLEL. */ - - if (nlabels > 0 && nclobbers == 0) - { - gcc_assert (noutputs == 0); - emit_jump_insn (body); - } - else if (noutputs == 0 && nclobbers == 0) - { - /* No output operands: put in a raw ASM_OPERANDS rtx. */ - emit_insn (body); - } - else if (noutputs == 1 && nclobbers == 0) - { - ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]); - emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body)); - } - else - { - rtx obody = body; - int num = noutputs; - - if (num == 0) - num = 1; - - body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num + nclobbers)); - - /* For each output operand, store a SET. */ - for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - { - XVECEXP (body, 0, i) - = gen_rtx_SET (VOIDmode, - output_rtx[i], - gen_rtx_ASM_OPERANDS - (GET_MODE (output_rtx[i]), - ggc_strdup (TREE_STRING_POINTER (string)), - ggc_strdup (constraints[i]), - i, argvec, constraintvec, labelvec, locus)); - - MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol; - } - - /* If there are no outputs (but there are some clobbers) - store the bare ASM_OPERANDS into the PARALLEL. */ - - if (i == 0) - XVECEXP (body, 0, i++) = obody; - - /* Store (clobber REG) for each clobbered register specified. */ - - for (tail = clobbers; tail; tail = TREE_CHAIN (tail)) - { - const char *regname = TREE_STRING_POINTER (TREE_VALUE (tail)); - int reg, nregs; - int j = decode_reg_name_and_count (regname, &nregs); - rtx clobbered_reg; - - if (j < 0) - { - if (j == -3) /* `cc', which is not a register */ - continue; - - if (j == -4) /* `memory', don't cache memory across asm */ - { - XVECEXP (body, 0, i++) - = gen_rtx_CLOBBER (VOIDmode, - gen_rtx_MEM - (BLKmode, - gen_rtx_SCRATCH (VOIDmode))); - continue; - } - - /* Ignore unknown register, error already signaled. */ - continue; - } - - for (reg = j; reg < j + nregs; reg++) - { - /* Use QImode since that's guaranteed to clobber just - * one reg. */ - clobbered_reg = gen_rtx_REG (QImode, reg); - - /* Do sanity check for overlap between clobbers and - respectively input and outputs that hasn't been - handled. Such overlap should have been detected and - reported above. */ - if (!clobber_conflict_found) - { - int opno; - - /* We test the old body (obody) contents to avoid - tripping over the under-construction body. */ - for (opno = 0; opno < noutputs; opno++) - if (reg_overlap_mentioned_p (clobbered_reg, - output_rtx[opno])) - internal_error - ("asm clobber conflict with output operand"); - - for (opno = 0; opno < ninputs - ninout; opno++) - if (reg_overlap_mentioned_p (clobbered_reg, - ASM_OPERANDS_INPUT (obody, - opno))) - internal_error - ("asm clobber conflict with input operand"); - } - - XVECEXP (body, 0, i++) - = gen_rtx_CLOBBER (VOIDmode, clobbered_reg); - } - } - - if (nlabels > 0) - emit_jump_insn (body); - else - emit_insn (body); - } - - if (fallthru_label) - emit_label (fallthru_label); - - /* For any outputs that needed reloading into registers, spill them - back to where they belong. */ - for (i = 0; i < noutputs; ++i) - if (real_output_rtx[i]) - emit_move_insn (real_output_rtx[i], output_rtx[i]); - - crtl->has_asm_statement = 1; - free_temp_slots (); -} - -void -expand_asm_stmt (gimple stmt) -{ - int noutputs; - tree outputs, tail, t; - tree *o; - size_t i, n; - const char *s; - tree str, out, in, cl, labels; - location_t locus = gimple_location (stmt); - basic_block fallthru_bb = NULL; - - /* Meh... convert the gimple asm operands into real tree lists. - Eventually we should make all routines work on the vectors instead - of relying on TREE_CHAIN. */ - out = NULL_TREE; - n = gimple_asm_noutputs (stmt); - if (n > 0) - { - t = out = gimple_asm_output_op (stmt, 0); - for (i = 1; i < n; i++) - t = TREE_CHAIN (t) = gimple_asm_output_op (stmt, i); - } - - in = NULL_TREE; - n = gimple_asm_ninputs (stmt); - if (n > 0) - { - t = in = gimple_asm_input_op (stmt, 0); - for (i = 1; i < n; i++) - t = TREE_CHAIN (t) = gimple_asm_input_op (stmt, i); - } - - cl = NULL_TREE; - n = gimple_asm_nclobbers (stmt); - if (n > 0) - { - t = cl = gimple_asm_clobber_op (stmt, 0); - for (i = 1; i < n; i++) - t = TREE_CHAIN (t) = gimple_asm_clobber_op (stmt, i); - } - - labels = NULL_TREE; - n = gimple_asm_nlabels (stmt); - if (n > 0) - { - edge fallthru = find_fallthru_edge (gimple_bb (stmt)->succs); - if (fallthru) - fallthru_bb = fallthru->dest; - t = labels = gimple_asm_label_op (stmt, 0); - for (i = 1; i < n; i++) - t = TREE_CHAIN (t) = gimple_asm_label_op (stmt, i); - } - - s = gimple_asm_string (stmt); - str = build_string (strlen (s), s); - - if (gimple_asm_input_p (stmt)) - { - expand_asm_loc (str, gimple_asm_volatile_p (stmt), locus); - return; - } - - outputs = out; - noutputs = gimple_asm_noutputs (stmt); - /* o[I] is the place that output number I should be written. */ - o = (tree *) alloca (noutputs * sizeof (tree)); - - /* Record the contents of OUTPUTS before it is modified. */ - for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - o[i] = TREE_VALUE (tail); - - /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of - OUTPUTS some trees for where the values were actually stored. */ - expand_asm_operands (str, outputs, in, cl, labels, fallthru_bb, - gimple_asm_volatile_p (stmt), locus); - - /* Copy all the intermediate outputs into the specified outputs. */ - for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - { - if (o[i] != TREE_VALUE (tail)) - { - expand_assignment (o[i], TREE_VALUE (tail), false); - free_temp_slots (); - - /* Restore the original value so that it's correct the next - time we expand this function. */ - TREE_VALUE (tail) = o[i]; - } - } -} - -/* A subroutine of expand_asm_operands. Check that all operands have - the same number of alternatives. Return true if so. */ - -static bool -check_operand_nalternatives (tree outputs, tree inputs) -{ - if (outputs || inputs) - { - tree tmp = TREE_PURPOSE (outputs ? outputs : inputs); - int nalternatives - = n_occurrences (',', TREE_STRING_POINTER (TREE_VALUE (tmp))); - tree next = inputs; - - if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES) - { - error ("too many alternatives in %<asm%>"); - return false; - } - - tmp = outputs; - while (tmp) - { - const char *constraint - = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tmp))); - - if (n_occurrences (',', constraint) != nalternatives) - { - error ("operand constraints for %<asm%> differ " - "in number of alternatives"); - return false; - } - - if (TREE_CHAIN (tmp)) - tmp = TREE_CHAIN (tmp); - else - tmp = next, next = 0; - } - } - - return true; -} /* A subroutine of expand_asm_operands. Check that all operand names are unique. Return true if so. We rely on the fact that these names @@ -1427,19 +702,6 @@ resolve_operand_name_1 (char *p, tree outputs, tree inputs, tree labels) return p; } -/* Generate RTL to return from the current function, with no value. - (That is, we do not do anything about returning any value.) */ - -void -expand_null_return (void) -{ - /* If this function was declared to return a value, but we - didn't, clobber the return registers so that they are not - propagated live to the rest of the function. */ - clobber_return_register (); - - expand_null_return_1 (); -} /* Generate RTL to return directly from the current function. (That is, we bypass any return value.) */ @@ -1459,154 +721,6 @@ expand_naked_return (void) emit_jump (end_label); } -/* Generate RTL to return from the current function, with value VAL. */ - -static void -expand_value_return (rtx val) -{ - /* Copy the value to the return location unless it's already there. */ - - tree decl = DECL_RESULT (current_function_decl); - rtx return_reg = DECL_RTL (decl); - if (return_reg != val) - { - tree funtype = TREE_TYPE (current_function_decl); - tree type = TREE_TYPE (decl); - int unsignedp = TYPE_UNSIGNED (type); - enum machine_mode old_mode = DECL_MODE (decl); - enum machine_mode mode; - if (DECL_BY_REFERENCE (decl)) - mode = promote_function_mode (type, old_mode, &unsignedp, funtype, 2); - else - mode = promote_function_mode (type, old_mode, &unsignedp, funtype, 1); - - if (mode != old_mode) - val = convert_modes (mode, old_mode, val, unsignedp); - - if (GET_CODE (return_reg) == PARALLEL) - emit_group_load (return_reg, val, type, int_size_in_bytes (type)); - else - emit_move_insn (return_reg, val); - } - - expand_null_return_1 (); -} - -/* Output a return with no value. */ - -static void -expand_null_return_1 (void) -{ - clear_pending_stack_adjust (); - do_pending_stack_adjust (); - emit_jump (return_label); -} - -/* Generate RTL to evaluate the expression RETVAL and return it - from the current function. */ - -void -expand_return (tree retval) -{ - rtx result_rtl; - rtx val = 0; - tree retval_rhs; - - /* If function wants no value, give it none. */ - if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE) - { - expand_normal (retval); - expand_null_return (); - return; - } - - if (retval == error_mark_node) - { - /* Treat this like a return of no value from a function that - returns a value. */ - expand_null_return (); - return; - } - else if ((TREE_CODE (retval) == MODIFY_EXPR - || TREE_CODE (retval) == INIT_EXPR) - && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL) - retval_rhs = TREE_OPERAND (retval, 1); - else - retval_rhs = retval; - - result_rtl = DECL_RTL (DECL_RESULT (current_function_decl)); - - /* If we are returning the RESULT_DECL, then the value has already - been stored into it, so we don't have to do anything special. */ - if (TREE_CODE (retval_rhs) == RESULT_DECL) - expand_value_return (result_rtl); - - /* If the result is an aggregate that is being returned in one (or more) - registers, load the registers here. */ - - else if (retval_rhs != 0 - && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode - && REG_P (result_rtl)) - { - val = copy_blkmode_to_reg (GET_MODE (result_rtl), retval_rhs); - if (val) - { - /* Use the mode of the result value on the return register. */ - PUT_MODE (result_rtl, GET_MODE (val)); - expand_value_return (val); - } - else - expand_null_return (); - } - else if (retval_rhs != 0 - && !VOID_TYPE_P (TREE_TYPE (retval_rhs)) - && (REG_P (result_rtl) - || (GET_CODE (result_rtl) == PARALLEL))) - { - /* Calculate the return value into a temporary (usually a pseudo - reg). */ - tree ot = TREE_TYPE (DECL_RESULT (current_function_decl)); - tree nt = build_qualified_type (ot, TYPE_QUALS (ot) | TYPE_QUAL_CONST); - - val = assign_temp (nt, 0, 1); - val = expand_expr (retval_rhs, val, GET_MODE (val), EXPAND_NORMAL); - val = force_not_mem (val); - /* Return the calculated value. */ - expand_value_return (val); - } - else - { - /* No hard reg used; calculate value into hard return reg. */ - expand_expr (retval, const0_rtx, VOIDmode, EXPAND_NORMAL); - expand_value_return (result_rtl); - } -} - - -/* Emit code to save the current value of stack. */ -rtx -expand_stack_save (void) -{ - rtx ret = NULL_RTX; - - do_pending_stack_adjust (); - emit_stack_save (SAVE_BLOCK, &ret); - return ret; -} - -/* Emit code to restore the current value of stack. */ -void -expand_stack_restore (tree var) -{ - rtx prev, sa = expand_normal (var); - - sa = convert_memory_address (Pmode, sa); - - prev = get_last_insn (); - emit_stack_restore (SAVE_BLOCK, sa); - fixup_args_size_notes (prev, get_last_insn (), 0); -} - /* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. PROB is the probability of jumping to LABEL. */ static void |