Hi!

this patch is inspired by recent discussion about basic asm:

Currently a basic asm is an instruction scheduling barrier,
but not a memory barrier, and most surprising, basic asm
does _not_ implicitly clobber CC on targets where
extended asm always implicitly clobbers CC, even if
nothing is in the clobber section.

This patch makes basic asm implicitly clobber CC on certain
targets, and makes the basic asm implicitly clobber memory,
but no general registers, which is what could be expected.

This is however only done for basic asm with non-empty
assembler string, which is in sync with David's proposed
basic asm warnings patch.

Due to the change in the tree representation, where
ASM_INPUT can now be the first element of a
PARALLEL block with the implicit clobber elements,
there are some changes necessary.

Most of the changes in the middle end, were necessary
because extract_asm_operands can not be used to find out
if a PARALLEL block is an asm statement, but in most cases
asm_noperands can be used instead.

There are also changes necessary in two targets: pa, and ia64.
I have successfully built cross-compilers for these targets.

Boot-strapped and reg-tested on x86_64-pc-linux-gnu
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)
@@ -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))

Reply via email to