diff options
Diffstat (limited to 'gcc/stmt.c')
-rw-r--r-- | gcc/stmt.c | 129 |
1 files changed, 76 insertions, 53 deletions
@@ -110,8 +110,8 @@ static int n_occurrences (int, const char *); static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *); static void expand_nl_goto_receiver (void); static bool check_operand_nalternatives (tree, tree); -static bool check_unique_operand_names (tree, tree); -static char *resolve_operand_name_1 (char *, 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 int estimate_case_costs (case_node_ptr); @@ -633,12 +633,13 @@ tree_conflicts_with_clobbers_p (tree t, HARD_REG_SET *clobbered_regs) static void expand_asm_operands (tree string, tree outputs, tree inputs, - tree clobbers, int vol, location_t locus) + tree clobbers, tree labels, int vol, location_t locus) { - rtvec argvec, constraintvec; + 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; @@ -661,7 +662,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, if (! check_operand_nalternatives (outputs, inputs)) return; - string = resolve_asm_operand_names (string, outputs, inputs); + string = resolve_asm_operand_names (string, outputs, inputs, labels); /* Collect constraints. */ i = 0; @@ -845,12 +846,13 @@ expand_asm_operands (tree string, tree outputs, tree inputs, 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, - locus); + labelvec, locus); MEM_VOLATILE_P (body) = vol; @@ -959,6 +961,11 @@ expand_asm_operands (tree string, tree outputs, tree inputs, = 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)) + ASM_OPERANDS_LABEL (body, i) + = gen_rtx_LABEL_REF (Pmode, label_rtx (TREE_VALUE (tail))); + generating_concat_p = old_generating_concat_p; /* Now, for each output, construct an rtx @@ -966,18 +973,21 @@ expand_asm_operands (tree string, tree outputs, tree inputs, ARGVEC CONSTRAINTS OPNAMES)) If there is more than one, put them inside a PARALLEL. */ - if (noutputs == 1 && nclobbers == 0) + if (nlabels > 0 && nclobbers == 0) { - ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = ggc_strdup (constraints[0]); - emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body)); + 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; @@ -998,7 +1008,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs, (GET_MODE (output_rtx[i]), ggc_strdup (TREE_STRING_POINTER (string)), ggc_strdup (constraints[i]), - i, argvec, constraintvec, locus)); + i, argvec, constraintvec, labelvec, locus)); MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol; } @@ -1062,7 +1072,10 @@ expand_asm_operands (tree string, tree outputs, tree inputs, = gen_rtx_CLOBBER (VOIDmode, clobbered_reg); } - emit_insn (body); + if (nlabels > 0) + emit_jump_insn (body); + else + emit_insn (body); } /* For any outputs that needed reloading into registers, spill them @@ -1083,7 +1096,7 @@ expand_asm_stmt (gimple stmt) tree *o; size_t i, n; const char *s; - tree str, out, in, cl; + tree str, out, in, cl, labels; /* Meh... convert the gimple asm operands into real tree lists. Eventually we should make all routines work on the vectors instead @@ -1094,10 +1107,7 @@ expand_asm_stmt (gimple stmt) { t = out = gimple_asm_output_op (stmt, 0); for (i = 1; i < n; i++) - { - TREE_CHAIN (t) = gimple_asm_output_op (stmt, i); - t = gimple_asm_output_op (stmt, i); - } + t = TREE_CHAIN (t) = gimple_asm_output_op (stmt, i); } in = NULL_TREE; @@ -1106,10 +1116,7 @@ expand_asm_stmt (gimple stmt) { t = in = gimple_asm_input_op (stmt, 0); for (i = 1; i < n; i++) - { - TREE_CHAIN (t) = gimple_asm_input_op (stmt, i); - t = gimple_asm_input_op (stmt, i); - } + t = TREE_CHAIN (t) = gimple_asm_input_op (stmt, i); } cl = NULL_TREE; @@ -1118,10 +1125,16 @@ expand_asm_stmt (gimple stmt) { t = cl = gimple_asm_clobber_op (stmt, 0); for (i = 1; i < n; i++) - { - TREE_CHAIN (t) = gimple_asm_clobber_op (stmt, i); - t = gimple_asm_clobber_op (stmt, i); - } + t = TREE_CHAIN (t) = gimple_asm_clobber_op (stmt, i); + } + + labels = NULL_TREE; + n = gimple_asm_nlabels (stmt); + if (n > 0) + { + 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); @@ -1144,8 +1157,8 @@ expand_asm_stmt (gimple stmt) /* 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, gimple_asm_volatile_p (stmt), - input_location); + expand_asm_operands (str, outputs, in, cl, labels, + gimple_asm_volatile_p (stmt), input_location); /* Copy all the intermediate outputs into the specified outputs. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) @@ -1210,7 +1223,7 @@ check_operand_nalternatives (tree outputs, tree inputs) so all we need are pointer comparisons. */ static bool -check_unique_operand_names (tree outputs, tree inputs) +check_unique_operand_names (tree outputs, tree inputs, tree labels) { tree i, j; @@ -1239,6 +1252,20 @@ check_unique_operand_names (tree outputs, tree inputs) goto failure; } + for (i = labels; i ; i = TREE_CHAIN (i)) + { + tree i_name = TREE_PURPOSE (i); + if (! i_name) + continue; + + for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j)) + if (simple_cst_equal (i_name, TREE_PURPOSE (j))) + goto failure; + for (j = inputs; j ; j = TREE_CHAIN (j)) + if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j)))) + goto failure; + } + return true; failure: @@ -1252,14 +1279,14 @@ check_unique_operand_names (tree outputs, tree inputs) STRING and in the constraints to those numbers. */ tree -resolve_asm_operand_names (tree string, tree outputs, tree inputs) +resolve_asm_operand_names (tree string, tree outputs, tree inputs, tree labels) { char *buffer; char *p; const char *c; tree t; - check_unique_operand_names (outputs, inputs); + check_unique_operand_names (outputs, inputs, labels); /* Substitute [<name>] in input constraint strings. There should be no named operands in output constraints. */ @@ -1270,7 +1297,7 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) { p = buffer = xstrdup (c); while ((p = strchr (p, '[')) != NULL) - p = resolve_operand_name_1 (p, outputs, inputs); + p = resolve_operand_name_1 (p, outputs, inputs, NULL); TREE_VALUE (TREE_PURPOSE (t)) = build_string (strlen (buffer), buffer); free (buffer); @@ -1313,7 +1340,7 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) continue; } - p = resolve_operand_name_1 (p, outputs, inputs); + p = resolve_operand_name_1 (p, outputs, inputs, labels); } string = build_string (strlen (buffer), buffer); @@ -1329,53 +1356,49 @@ resolve_asm_operand_names (tree string, tree outputs, tree inputs) balance of the string after substitution. */ static char * -resolve_operand_name_1 (char *p, tree outputs, tree inputs) +resolve_operand_name_1 (char *p, tree outputs, tree inputs, tree labels) { char *q; int op; tree t; - size_t len; /* Collect the operand name. */ - q = strchr (p, ']'); + q = strchr (++p, ']'); if (!q) { error ("missing close brace for named operand"); return strchr (p, '\0'); } - len = q - p - 1; + *q = '\0'; /* Resolve the name to a number. */ for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++) { tree name = TREE_PURPOSE (TREE_PURPOSE (t)); - if (name) - { - const char *c = TREE_STRING_POINTER (name); - if (strncmp (c, p + 1, len) == 0 && c[len] == '\0') - goto found; - } + if (name && strcmp (TREE_STRING_POINTER (name), p) == 0) + goto found; } for (t = inputs; t ; t = TREE_CHAIN (t), op++) { tree name = TREE_PURPOSE (TREE_PURPOSE (t)); - if (name) - { - const char *c = TREE_STRING_POINTER (name); - if (strncmp (c, p + 1, len) == 0 && c[len] == '\0') - goto found; - } + if (name && strcmp (TREE_STRING_POINTER (name), p) == 0) + goto found; + } + for (t = labels; t ; t = TREE_CHAIN (t), op++) + { + tree name = TREE_PURPOSE (t); + if (name && strcmp (TREE_STRING_POINTER (name), p) == 0) + goto found; } - *q = '\0'; - error ("undefined named operand %qs", identifier_to_locale (p + 1)); + error ("undefined named operand %qs", identifier_to_locale (p)); op = 0; - found: + found: /* Replace the name with the number. Unfortunately, not all libraries get the return value of sprintf correct, so search for the end of the generated string by hand. */ - sprintf (p, "%d", op); + sprintf (--p, "%d", op); p = strchr (p, '\0'); /* Verify the no extra buffer space assumption. */ |