Skip to content

Commit e3b3b59

Browse files
committed
[PATCH] Implementation of asm goto outputs
gcc/ * cfgexpand.c (expand_asm_stmt): Output asm goto with outputs too. Place insns after asm goto on edges. * doc/extend.texi: Reflect the changes in asm goto documentation. * gimple.c (gimple_build_asm_1): Remove an assert checking output absence for asm goto. * gimple.h (gimple_asm_label_op, gimple_asm_set_label_op): Take possible asm goto outputs into account. * ira.c (ira): Remove critical edges for potential asm goto output reloads. (ira_nullify_asm_goto): New function. * ira.h (ira_nullify_asm_goto): New prototype. * lra-assigns.c (lra_split_hard_reg_for): Use ira_nullify_asm_goto. Check that splitting is done inside a basic block. * lra-constraints.c (curr_insn_transform): Permit output reloads for any jump insn. * lra-spills.c (lra_final_code_change): Remove USEs added in ira for asm gotos. * lra.c (lra_process_new_insns): Place output reload insns after jumps in the beginning of destination BBs. * reload.c (find_reloads): Report error for asm gotos with outputs. Modify them to keep CFG consistency to avoid crashes. * tree-into-ssa.c (rewrite_stmt): Don't put debug stmt after asm goto. gcc/c/ * c-parser.c (c_parser_asm_statement): Parse outputs for asm goto too. * c-typeck.c (build_asm_expr): Remove an assert checking output absence for asm goto. gcc/cp * parser.c (cp_parser_asm_definition): Parse outputs for asm goto too. gcc/testsuite/ * c-c++-common/asmgoto-2.c: Permit output in asm goto. * gcc.c-torture/compile/asmgoto-2.c: New. * gcc.c-torture/compile/asmgoto-3.c: New. * gcc.c-torture/compile/asmgoto-4.c: New. * gcc.c-torture/compile/asmgoto-5.c: New.
1 parent 67100cb commit e3b3b59

File tree

20 files changed

+455
-59
lines changed

20 files changed

+455
-59
lines changed

gcc/c/c-parser.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7144,10 +7144,7 @@ c_parser_asm_statement (c_parser *parser)
71447144
switch (section)
71457145
{
71467146
case 0:
7147-
/* For asm goto, we don't allow output operands, but reserve
7148-
the slot for a future extension that does allow them. */
7149-
if (!is_goto)
7150-
outputs = c_parser_asm_operands (parser);
7147+
outputs = c_parser_asm_operands (parser);
71517148
break;
71527149
case 1:
71537150
inputs = c_parser_asm_operands (parser);

gcc/c/c-typeck.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10666,10 +10666,6 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
1066610666
TREE_VALUE (tail) = input;
1066710667
}
1066810668

10669-
/* ASMs with labels cannot have outputs. This should have been
10670-
enforced by the parser. */
10671-
gcc_assert (outputs == NULL || labels == NULL);
10672-
1067310669
args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers, labels);
1067410670

1067510671
/* asm statements without outputs, including simple ones, are treated

gcc/cfgexpand.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,20 +3371,21 @@ expand_asm_stmt (gasm *stmt)
33713371
ARGVEC CONSTRAINTS OPNAMES))
33723372
If there is more than one, put them inside a PARALLEL. */
33733373

3374-
if (nlabels > 0 && nclobbers == 0)
3375-
{
3376-
gcc_assert (noutputs == 0);
3377-
emit_jump_insn (body);
3378-
}
3379-
else if (noutputs == 0 && nclobbers == 0)
3374+
if (noutputs == 0 && nclobbers == 0)
33803375
{
33813376
/* No output operands: put in a raw ASM_OPERANDS rtx. */
3382-
emit_insn (body);
3377+
if (nlabels > 0)
3378+
emit_jump_insn (body);
3379+
else
3380+
emit_insn (body);
33833381
}
33843382
else if (noutputs == 1 && nclobbers == 0)
33853383
{
33863384
ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
3387-
emit_insn (gen_rtx_SET (output_rvec[0], body));
3385+
if (nlabels > 0)
3386+
emit_jump_insn (gen_rtx_SET (output_rvec[0], body));
3387+
else
3388+
emit_insn (gen_rtx_SET (output_rvec[0], body));
33883389
}
33893390
else
33903391
{
@@ -3461,7 +3462,27 @@ expand_asm_stmt (gasm *stmt)
34613462
if (after_md_seq)
34623463
emit_insn (after_md_seq);
34633464
if (after_rtl_seq)
3464-
emit_insn (after_rtl_seq);
3465+
{
3466+
if (nlabels == 0)
3467+
emit_insn (after_rtl_seq);
3468+
else
3469+
{
3470+
edge e;
3471+
edge_iterator ei;
3472+
3473+
FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs)
3474+
{
3475+
start_sequence ();
3476+
for (rtx_insn *curr = after_rtl_seq;
3477+
curr != NULL_RTX;
3478+
curr = NEXT_INSN (curr))
3479+
emit_insn (copy_insn (PATTERN (curr)));
3480+
rtx_insn *copy = get_insns ();
3481+
end_sequence ();
3482+
insert_insn_on_edge (copy, e);
3483+
}
3484+
}
3485+
}
34653486

34663487
free_temp_slots ();
34673488
crtl->has_asm_statement = 1;

gcc/cp/parser.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20534,8 +20534,7 @@ cp_parser_asm_definition (cp_parser* parser)
2053420534
&& cp_lexer_next_token_is_not (parser->lexer,
2053520535
CPP_SCOPE)
2053620536
&& cp_lexer_next_token_is_not (parser->lexer,
20537-
CPP_CLOSE_PAREN)
20538-
&& !goto_p)
20537+
CPP_CLOSE_PAREN))
2053920538
{
2054020539
outputs = cp_parser_asm_operand_list (parser);
2054120540
if (outputs == error_mark_node)

gcc/doc/extend.texi

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9566,7 +9566,7 @@ asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
95669566
@r{[} : @var{Clobbers} @r{]} @r{]})
95679567

95689568
asm @var{asm-qualifiers} ( @var{AssemblerTemplate}
9569-
:
9569+
: @var{OutputOperands}
95709570
: @var{InputOperands}
95719571
: @var{Clobbers}
95729572
: @var{GotoLabels})
@@ -9673,7 +9673,7 @@ there is no need for the output variables. Also, the optimizers may move
96739673
code out of loops if they believe that the code will always return the same
96749674
result (i.e.@: none of its input values change between calls). Using the
96759675
@code{volatile} qualifier disables these optimizations. @code{asm} statements
9676-
that have no output operands, including @code{asm goto} statements,
9676+
that have no output operands and @code{asm goto} statements,
96779677
are implicitly volatile.
96789678

96799679
This i386 code demonstrates a case that does not use (or require) the
@@ -10532,9 +10532,6 @@ case, consider using the @code{__builtin_unreachable} intrinsic after the
1053210532
using the @code{hot} and @code{cold} label attributes (@pxref{Label
1053310533
Attributes}).
1053410534

10535-
An @code{asm goto} statement cannot have outputs.
10536-
This is due to an internal restriction of
10537-
the compiler: control transfer instructions cannot have outputs.
1053810535
If the assembler code does modify anything, use the @code{"memory"} clobber
1053910536
to force the
1054010537
optimizers to flush all register values to memory and reload them if
@@ -10543,6 +10540,13 @@ necessary after the @code{asm} statement.
1054310540
Also note that an @code{asm goto} statement is always implicitly
1054410541
considered volatile.
1054510542

10543+
Be careful when you set output operands inside @code{asm goto} only on
10544+
some possible control flow paths. If you don't set up the output on
10545+
given path and never use it on this path, it is okay. Otherwise, you
10546+
should use @samp{+} constraint modifier meaning that the operand is
10547+
input and output one. With this modifier you will have the correct
10548+
values on all possible paths from the @code{asm goto}.
10549+
1054610550
To reference a label in the assembler template,
1054710551
prefix it with @samp{%l} (lowercase @samp{L}) followed
1054810552
by its (zero-based) position in @var{GotoLabels} plus the number of input
@@ -10588,6 +10592,41 @@ error:
1058810592
@}
1058910593
@end example
1059010594

10595+
The following example shows an @code{asm goto} that uses an output.
10596+
10597+
@example
10598+
int foo(int count)
10599+
@{
10600+
asm goto ("dec %0; jb %l[stop]"
10601+
: "+r" (count)
10602+
:
10603+
:
10604+
: stop);
10605+
return count;
10606+
stop:
10607+
return 0;
10608+
@}
10609+
@end example
10610+
10611+
The following artificial example shows an @code{asm goto} that sets
10612+
up an output only on one path inside the @code{asm goto}. Usage of
10613+
constraint modifier @code{=} instead of @code{+} would be wrong as
10614+
@code{factor} is used on all paths from the @code{asm goto}.
10615+
10616+
@example
10617+
int foo(int inp)
10618+
@{
10619+
int factor = 0;
10620+
asm goto ("cmp %1, 10; jb %l[lab]; mov 2, %0"
10621+
: "+r" (factor)
10622+
: "r" (inp)
10623+
:
10624+
: lab);
10625+
lab:
10626+
return inp * factor; /* return 2 * inp or 0 if inp < 10 */
10627+
@}
10628+
@end example
10629+
1059110630
@anchor{x86Operandmodifiers}
1059210631
@subsubsection x86 Operand Modifiers
1059310632

gcc/gimple.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,10 +611,6 @@ gimple_build_asm_1 (const char *string, unsigned ninputs, unsigned noutputs,
611611
gasm *p;
612612
int size = strlen (string);
613613

614-
/* ASMs with labels cannot have outputs. This should have been
615-
enforced by the front end. */
616-
gcc_assert (nlabels == 0 || noutputs == 0);
617-
618614
p = as_a <gasm *> (
619615
gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK,
620616
ninputs + noutputs + nclobbers + nlabels));

gcc/gimple.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4025,7 +4025,7 @@ static inline tree
40254025
gimple_asm_label_op (const gasm *asm_stmt, unsigned index)
40264026
{
40274027
gcc_gimple_checking_assert (index < asm_stmt->nl);
4028-
return asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc];
4028+
return asm_stmt->op[index + asm_stmt->no + asm_stmt->ni + asm_stmt->nc];
40294029
}
40304030

40314031
/* Set LABEL_OP to be label operand INDEX in GIMPLE_ASM ASM_STMT. */
@@ -4035,7 +4035,7 @@ gimple_asm_set_label_op (gasm *asm_stmt, unsigned index, tree label_op)
40354035
{
40364036
gcc_gimple_checking_assert (index < asm_stmt->nl
40374037
&& TREE_CODE (label_op) == TREE_LIST);
4038-
asm_stmt->op[index + asm_stmt->ni + asm_stmt->nc] = label_op;
4038+
asm_stmt->op[index + asm_stmt->no + asm_stmt->ni + asm_stmt->nc] = label_op;
40394039
}
40404040

40414041
/* Return the string representing the assembly instruction in

gcc/ira.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5401,6 +5401,48 @@ ira (FILE *f)
54015401
int ira_max_point_before_emit;
54025402
bool saved_flag_caller_saves = flag_caller_saves;
54035403
enum ira_region saved_flag_ira_region = flag_ira_region;
5404+
basic_block bb;
5405+
edge_iterator ei;
5406+
edge e;
5407+
bool output_jump_reload_p = false;
5408+
5409+
if (ira_use_lra_p)
5410+
{
5411+
/* First put potential jump output reloads on the output edges
5412+
as USE which will be removed at the end of LRA. The major
5413+
goal is actually to create BBs for critical edges for LRA and
5414+
populate them later by live info. In LRA it will be
5415+
difficult to do this. */
5416+
FOR_EACH_BB_FN (bb, cfun)
5417+
{
5418+
rtx_insn *end = BB_END (bb);
5419+
if (!JUMP_P (end))
5420+
continue;
5421+
extract_insn (end);
5422+
for (int i = 0; i < recog_data.n_operands; i++)
5423+
if (recog_data.operand_type[i] != OP_IN)
5424+
{
5425+
output_jump_reload_p = true;
5426+
FOR_EACH_EDGE (e, ei, bb->succs)
5427+
if (EDGE_CRITICAL_P (e)
5428+
&& e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
5429+
{
5430+
ira_assert (!(e->flags & EDGE_ABNORMAL));
5431+
start_sequence ();
5432+
/* We need to put some no-op insn here. We can
5433+
not put a note as commit_edges insertion will
5434+
fail. */
5435+
emit_insn (gen_rtx_USE (VOIDmode, const1_rtx));
5436+
rtx_insn *insns = get_insns ();
5437+
end_sequence ();
5438+
insert_insn_on_edge (insns, e);
5439+
}
5440+
break;
5441+
}
5442+
}
5443+
if (output_jump_reload_p)
5444+
commit_edge_insertions ();
5445+
}
54045446

54055447
if (flag_ira_verbose < 10)
54065448
{
@@ -5709,6 +5751,21 @@ ira (FILE *f)
57095751
}
57105752
}
57115753

5754+
/* Modify asm goto to avoid further trouble with this insn. We can
5755+
not replace the insn by USE as in other asm insns as we still
5756+
need to keep CFG consistency. */
5757+
void
5758+
ira_nullify_asm_goto (rtx_insn *insn)
5759+
{
5760+
ira_assert (JUMP_P (insn) && INSN_CODE (insn) < 0);
5761+
rtx tmp = extract_asm_operands (PATTERN (insn));
5762+
PATTERN (insn) = gen_rtx_ASM_OPERANDS (VOIDmode, ggc_strdup (""), "", 0,
5763+
rtvec_alloc (0),
5764+
rtvec_alloc (0),
5765+
ASM_OPERANDS_LABEL_VEC (tmp),
5766+
ASM_OPERANDS_SOURCE_LOCATION(tmp));
5767+
}
5768+
57125769
static void
57135770
do_reload (void)
57145771
{

gcc/ira.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ extern void ira_register_new_scratch_op (rtx_insn *insn, int nop, int icode);
213213
extern bool ira_remove_insn_scratches (rtx_insn *insn, bool all_p, FILE *dump_file,
214214
rtx (*get_reg) (rtx original));
215215
extern void ira_restore_scratches (FILE *dump_file);
216+
extern void ira_nullify_asm_goto (rtx_insn *insn);
216217

217218
/* ira-costs.c */
218219
extern void ira_costs_c_finalize (void);

gcc/lra-assigns.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,8 +1715,8 @@ find_reload_regno_insns (int regno, rtx_insn * &start, rtx_insn * &finish)
17151715
start_insn = lra_insn_recog_data[uid]->insn;
17161716
n++;
17171717
}
1718-
/* For reload pseudo we should have at most 3 insns referring for it:
1719-
input/output reload insns and the original insn. */
1718+
/* For reload pseudo we should have at most 3 insns referring for
1719+
it: input/output reload insns and the original insn. */
17201720
if (n > 3)
17211721
return false;
17221722
if (n > 1)
@@ -1792,7 +1792,8 @@ lra_split_hard_reg_for (void)
17921792
{
17931793
if (! find_reload_regno_insns (i, first, last))
17941794
continue;
1795-
if (spill_hard_reg_in_range (i, rclass, first, last))
1795+
if (BLOCK_FOR_INSN (first) == BLOCK_FOR_INSN (last)
1796+
&& spill_hard_reg_in_range (i, rclass, first, last))
17961797
{
17971798
bitmap_clear (&failed_reload_pseudos);
17981799
return true;
@@ -1817,16 +1818,10 @@ lra_split_hard_reg_for (void)
18171818
lra_asm_error_p = asm_p = true;
18181819
error_for_asm (insn,
18191820
"%<asm%> operand has impossible constraints");
1820-
/* Avoid further trouble with this insn.
1821-
For asm goto, instead of fixing up all the edges
1822-
just clear the template and clear input operands
1823-
(asm goto doesn't have any output operands). */
1821+
/* Avoid further trouble with this insn. */
18241822
if (JUMP_P (insn))
18251823
{
1826-
rtx asm_op = extract_asm_operands (PATTERN (insn));
1827-
ASM_OPERANDS_TEMPLATE (asm_op) = ggc_strdup ("");
1828-
ASM_OPERANDS_INPUT_VEC (asm_op) = rtvec_alloc (0);
1829-
ASM_OPERANDS_INPUT_CONSTRAINT_VEC (asm_op) = rtvec_alloc (0);
1824+
ira_nullify_asm_goto (insn);
18301825
lra_update_insn_regno_info (insn);
18311826
}
18321827
else

gcc/lra-constraints.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3954,10 +3954,10 @@ curr_insn_transform (bool check_only_p)
39543954
no_input_reloads_p = no_output_reloads_p = false;
39553955
goal_alt_number = -1;
39563956
change_p = sec_mem_p = false;
3957-
/* JUMP_INSNs and CALL_INSNs are not allowed to have any output
3958-
reloads; neither are insns that SET cc0. Insns that use CC0 are
3959-
not allowed to have any input reloads. */
3960-
if (JUMP_P (curr_insn) || CALL_P (curr_insn))
3957+
/* CALL_INSNs are not allowed to have any output reloads; neither
3958+
are insns that SET cc0. Insns that use CC0 are not allowed to
3959+
have any input reloads. */
3960+
if (CALL_P (curr_insn))
39613961
no_output_reloads_p = true;
39623962

39633963
if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn)))

gcc/lra-spills.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,14 @@ lra_final_code_change (void)
788788
{
789789
rtx pat = PATTERN (insn);
790790

791+
if (GET_CODE (pat) == USE && XEXP (pat, 0) == const1_rtx)
792+
{
793+
/* Remove markers to eliminate critical edges for jump insn
794+
output reloads (see code in ira.c::ira). */
795+
lra_invalidate_insn_data (insn);
796+
delete_insn (insn);
797+
continue;
798+
}
791799
if (GET_CODE (pat) == CLOBBER && LRA_TEMP_CLOBBER_P (pat))
792800
{
793801
/* Remove clobbers temporarily created in LRA. We don't

0 commit comments

Comments
 (0)