Ping...
I think we all agreed on the general direction of this patch.
The patch is basically unchanged from previous version,
except one line in doc/extend.texi has been updated.
So I would like to ask if it is OK for trunk.
Thanks
Bernd.
gcc/
2016-05-05 Bernd Edlinger <bernd.edlin...@hotmail.de>
PR c/24414
* cfgexpand.c (expand_asm_loc): Remove handling for ADDR_EXPR.
Implicitly clobber memory for basic asm with non-empty assembler
string. Use targetm.md_asm_adjust also here.
* compare-emim.c (arithmetic_flags_clobber_p): Use asm_noperands here.
* final.c (final_scan_insn): Handle basic asm in PARALLEL block.
* gimple.c (gimple_asm_clobbers_memory_p): Handle basic asm with
non-empty assembler string.
* ira.c (compute_regs_asm_clobbered): Use asm_noperands here.
* recog.c (asm_noperands): Handle basic asm in PARALLEL block.
(decode_asm_operands): Handle basic asm in PARALLEL block.
(extract_insn): Handle basic asm in PARALLEL block.
* doc/extend.texi: Mention new behavior of basic asm.
* config/ia64/ia64 (rtx_needs_barrier): Handle ASM_INPUT here.
* config/pa/pa.c (branch_to_delay_slot_p, branch_needs_nop_p,
branch_needs_nop_p): Use asm_noperands.
gcc/testsuite/
2016-05-05 Bernd Edlinger <bernd.edlin...@hotmail.de>
PR c/24414
* gcc.target/i386/pr24414.c: New test.
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c (revision 231412)
+++ gcc/cfgexpand.c (working copy)
@@ -2655,9 +2655,6 @@ expand_asm_loc (tree string, int vol, location_t l
{
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);
@@ -2664,6 +2661,34 @@ expand_asm_loc (tree string, int vol, location_t l
MEM_VOLATILE_P (body) = vol;
+ /* Non-empty basic ASM implicitly clobbers memory. */
+ if (TREE_STRING_LENGTH (string) != 0)
+ {
+ rtx asm_op, clob;
+ unsigned i, nclobbers;
+ auto_vec<rtx> input_rvec, output_rvec;
+ auto_vec<const char *> constraints;
+ auto_vec<rtx> clobber_rvec;
+ HARD_REG_SET clobbered_regs;
+ CLEAR_HARD_REG_SET (clobbered_regs);
+
+ clob = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
+ clobber_rvec.safe_push (clob);
+
+ if (targetm.md_asm_adjust)
+ targetm.md_asm_adjust (output_rvec, input_rvec,
+ constraints, clobber_rvec,
+ clobbered_regs);
+
+ asm_op = body;
+ nclobbers = clobber_rvec.length ();
+ body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + nclobbers));
+
+ XVECEXP (body, 0, 0) = asm_op;
+ for (i = 0; i < nclobbers; i++)
+ XVECEXP (body, 0, i + 1) = gen_rtx_CLOBBER (VOIDmode, clobber_rvec[i]);
+ }
+
emit_insn (body);
}
Index: gcc/compare-elim.c
===================================================================
--- gcc/compare-elim.c (revision 231412)
+++ gcc/compare-elim.c (working copy)
@@ -162,7 +162,7 @@ arithmetic_flags_clobber_p (rtx_insn *insn)
if (!NONJUMP_INSN_P (insn))
return false;
pat = PATTERN (insn);
- if (extract_asm_operands (pat))
+ if (asm_noperands (pat) >= 0)
return false;
if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 231412)
+++ gcc/doc/extend.texi (working copy)
@@ -7508,7 +7508,7 @@
inside them. GCC has no visibility of symbols in the @code{asm} and may
discard them as unreferenced. It also does not know about side effects of
the assembler code, such as modifications to memory or registers. Unlike
-some compilers, GCC assumes that no changes to either memory or registers
+some compilers, GCC assumes that no changes to general purpose registers
occur. This assumption may change in a future release.
To avoid complications from future changes to the semantics and the
@@ -7442,6 +7442,10 @@ all basic @code{asm} blocks use the assembler dial
Basic @code{asm} provides no
mechanism to provide different assembler strings for different dialects.
+For basic @code{asm} with non-empty assembler string GCC assumes
+the assembler block does not change any general purpose registers,
+but it may read or write any globally accessible variable.
+
Here is an example of basic @code{asm} for i386:
@example
Index: gcc/final.c
===================================================================
--- gcc/final.c (revision 231412)
+++ gcc/final.c (working copy)
@@ -2565,6 +2565,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int o
(*debug_hooks->source_line) (last_linenum, last_filename,
last_discriminator, is_stmt);
+ if (GET_CODE (body) == PARALLEL
+ && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
+ body = XVECEXP (body, 0, 0);
+
if (GET_CODE (body) == ASM_INPUT)
{
const char *string = XSTR (body, 0);
Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c (revision 231412)
+++ gcc/gimple.c (working copy)
@@ -2567,6 +2567,10 @@ gimple_asm_clobbers_memory_p (const gasm *stmt)
return true;
}
+ /* Non-empty basic ASM implicitly clobbers memory. */
+ if (gimple_asm_input_p (stmt) && strlen (gimple_asm_string (stmt)) != 0)
+ return true;
+
return false;
}
Index: gcc/ira.c
===================================================================
--- gcc/ira.c (revision 231412)
+++ gcc/ira.c (working copy)
@@ -2229,7 +2229,7 @@ compute_regs_asm_clobbered (void)
{
df_ref def;
- if (NONDEBUG_INSN_P (insn) && extract_asm_operands (PATTERN (insn)))
+ if (NONDEBUG_INSN_P (insn) && asm_noperands (PATTERN (insn)) >= 0)
FOR_EACH_INSN_DEF (def, insn)
{
unsigned int dregno = DF_REF_REGNO (def);
Index: gcc/recog.c
===================================================================
--- gcc/recog.c (revision 231412)
+++ gcc/recog.c (working copy)
@@ -1470,6 +1470,8 @@ extract_asm_operands (rtx body)
/* If BODY is an insn body that uses ASM_OPERANDS,
return the number of operands (both input and output) in the insn.
+ If BODY is an insn body that uses ASM_INPUT with CLOBBERS in PARALLEL,
+ return 0.
Otherwise return -1. */
int
@@ -1476,16 +1478,26 @@ int
asm_noperands (const_rtx body)
{
rtx asm_op = extract_asm_operands (CONST_CAST_RTX (body));
- int n_sets = 0;
+ int i, n_sets = 0;
if (asm_op == NULL)
- return -1;
+ {
+ if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) >= 2
+ && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
+ {
+ /* body is [(asm_input ...) (clobber (reg ...))...]. */
+ for (i = XVECLEN (body, 0) - 1; i > 0; i--)
+ if (GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
+ return -1;
+ return 0;
+ }
+ return -1;
+ }
if (GET_CODE (body) == SET)
n_sets = 1;
else if (GET_CODE (body) == PARALLEL)
{
- int i;
if (GET_CODE (XVECEXP (body, 0, 0)) == SET)
{
/* Multiple output operands, or 1 output plus some clobbers:
@@ -1540,9 +1552,12 @@ asm_noperands (const_rtx body)
the locations of the operands within the insn into the vector OPERAND_LOCS,
and the constraints for the operands into CONSTRAINTS.
Write the modes of the operands into MODES.
+ Write the location info into LOC.
Return the assembler-template.
+ If BODY is an insn body that uses ASM_INPUT with CLOBBERS in PARALLEL,
+ return the basic assembly string.
- If MODES, OPERAND_LOCS, CONSTRAINTS or OPERANDS is 0,
+ If LOC, MODES, OPERAND_LOCS, CONSTRAINTS or OPERANDS is 0,
we don't store that info. */
const char *
@@ -1603,6 +1618,12 @@ decode_asm_operands (rtx body, rtx *operands, rtx
}
nbase = i;
}
+ else if (GET_CODE (asmop) == ASM_INPUT)
+ {
+ if (loc)
+ *loc = ASM_INPUT_SOURCE_LOCATION (asmop);
+ return XSTR (asmop, 0);
+ }
break;
}
@@ -2244,7 +2265,8 @@ extract_insn (rtx_insn *insn)
case PARALLEL:
if ((GET_CODE (XVECEXP (body, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) == ASM_OPERANDS)
- || GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
+ || GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS
+ || GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
goto asm_insn;
else
goto normal_insn;
Index: gcc/testsuite/gcc.target/i386/pr24414.c
===================================================================
--- gcc/testsuite/gcc.target/i386/pr24414.c (revision 0)
+++ gcc/testsuite/gcc.target/i386/pr24414.c (working copy)
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+int test;
+
+int
+main ()
+{
+ int x = test;
+ asm ("movl $1,test");
+ if (x + test != 1)
+ __builtin_trap ();
+ return 0;
+}
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c (revision 231412)
+++ gcc/config/ia64/ia64.c (working copy)
@@ -6549,6 +6549,7 @@ rtx_needs_barrier (rtx x, struct reg_flags flags,
case USE:
case CALL:
case ASM_OPERANDS:
+ case ASM_INPUT:
need_barrier |= rtx_needs_barrier (pat, flags, pred);
break;
Index: gcc/config/pa/pa.c
===================================================================
--- gcc/config/pa/pa.c (revision 231412)
+++ gcc/config/pa/pa.c (working copy)
@@ -6399,7 +6399,7 @@ branch_to_delay_slot_p (rtx_insn *insn)
the branch is followed by an asm. */
if (!insn
|| GET_CODE (PATTERN (insn)) == ASM_INPUT
- || extract_asm_operands (PATTERN (insn)) != NULL_RTX
+ || asm_noperands (PATTERN (insn)) >= 0
|| get_attr_length (insn) > 0)
break;
}
@@ -6430,7 +6430,7 @@ branch_needs_nop_p (rtx_insn *insn)
return TRUE;
if (!(GET_CODE (PATTERN (insn)) == ASM_INPUT
- || extract_asm_operands (PATTERN (insn)) != NULL_RTX)
+ || asm_noperands (PATTERN (insn)) >= 0)
&& get_attr_length (insn) > 0)
break;
}
@@ -6454,7 +6454,7 @@ use_skip_p (rtx_insn *insn)
/* We can't rely on the length of asms, so we can't skip asms. */
if (!insn
|| GET_CODE (PATTERN (insn)) == ASM_INPUT
- || extract_asm_operands (PATTERN (insn)) != NULL_RTX)
+ || asm_noperands (PATTERN (insn)) >= 0)
break;
if (get_attr_length (insn) == 4
&& jump_insn == next_active_insn (insn))