This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fix inline-asm/15740


Marks memory-only operands TREE_ADDRESSABLE early, plus shifts some
other constraint error detection earlier in compilation.

Tested on i686-linux.


r~


        * gimplify.c (gimplify_asm_expr): Move resolve asm names ...
        * c-typeck.c (build_asm_expr): ... here.  Validate input
        constraints.  Mark memory inputs addressable.

        * semantics.c (finish_asm_stmt): Resolve asm names.  Validate input
        constraints.  Mark memory inputs addressable.

Index: gcc/testsuite/g++.dg/opt/asm2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/opt/asm2.C
diff -N gcc/testsuite/g++.dg/opt/asm2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/opt/asm2.C	29 Dec 2004 01:17:32 -0000
***************
*** 0 ****
--- 1,11 ----
+ /* PR inline-asm/15740 */
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void foo(void)
+ {
+   int a, b;
+   a = 1;
+   b = a + 1;
+   asm ("" : : "m" (a));
+ }
Index: gcc/testsuite/gcc.dg/asm-9.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/asm-9.c
diff -N gcc/testsuite/gcc.dg/asm-9.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/gcc.dg/asm-9.c	29 Dec 2004 01:17:32 -0000
***************
*** 0 ****
--- 1,11 ----
+ /* PR inline-asm/15740 */
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void foo(void)
+ {
+   int a, b;
+   a = 1;
+   b = a + 1;
+   asm ("" : : "m" (a));
+ }
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.405
diff -c -p -d -r1.405 c-typeck.c
*** gcc/c-typeck.c	21 Dec 2004 17:00:58 -0000	1.405
--- gcc/c-typeck.c	29 Dec 2004 01:17:33 -0000
*************** build_asm_expr (tree string, tree output
*** 6287,6333 ****
    tree args;
    int i;
    const char *constraint;
    bool allows_mem, allows_reg, is_inout;
!   int ninputs;
!   int noutputs;
  
    ninputs = list_length (inputs);
    noutputs = list_length (outputs);
  
    /* Remove output conversions that change the type but not the mode.  */
    for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
      {
        tree output = TREE_VALUE (tail);
        STRIP_NOPS (output);
!       TREE_VALUE (tail) = output;
!       lvalue_or_else (output, lv_asm);
  
        constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
  
!       if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
!                                     &allows_mem, &allows_reg, &is_inout))
!         {
!           /* By marking this operand as erroneous, we will not try
!           to process this operand again in expand_asm_operands.  */
!           TREE_VALUE (tail) = error_mark_node;
!           continue;
!         }
  
!       /* If the operand is a DECL that is going to end up in
!         memory, assume it is addressable.  This is a bit more
!         conservative than it would ideally be; the exact test is
!         buried deep in expand_asm_operands and depends on the
!         DECL_RTL for the OPERAND -- which we don't have at this
!         point.  */
!       if (!allows_reg && DECL_P (output))
!         c_mark_addressable (output);
      }
  
    /* Perform default conversions on array and function inputs.
       Don't do this for other types as it would screw up operands
       expected to be in memory.  */
!   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
!     TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
  
    args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
  
--- 6287,6360 ----
    tree args;
    int i;
    const char *constraint;
+   const char **oconstraints;
    bool allows_mem, allows_reg, is_inout;
!   int ninputs, noutputs;
  
    ninputs = list_length (inputs);
    noutputs = list_length (outputs);
+   oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
+ 
+   string = resolve_asm_operand_names (string, outputs, inputs);
  
    /* Remove output conversions that change the type but not the mode.  */
    for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
      {
        tree output = TREE_VALUE (tail);
+ 
+       /* ??? Really, this should not be here.  Users should be using a
+ 	 proper lvalue, dammit.  But there's a long history of using casts
+ 	 in the output operands.  In cases like longlong.h, this becomes a
+ 	 primitive form of typechecking -- if the cast can be removed, then
+ 	 the output operand had a type of the proper width; otherwise we'll
+ 	 get an error.  Gross, but ...  */
        STRIP_NOPS (output);
! 
!       if (!lvalue_or_else (output, lv_asm))
! 	output = error_mark_node;
  
        constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+       oconstraints[i] = constraint;
  
!       if (parse_output_constraint (&constraint, i, ninputs, noutputs,
! 				   &allows_mem, &allows_reg, &is_inout))
! 	{
! 	  /* If the operand is going to end up in memory,
! 	     mark it addressable.  */
! 	  if (!allows_reg && !c_mark_addressable (output))
! 	    output = error_mark_node;
! 	}
!       else
!         output = error_mark_node;
  
!       TREE_VALUE (tail) = output;
      }
  
    /* Perform default conversions on array and function inputs.
       Don't do this for other types as it would screw up operands
       expected to be in memory.  */
!   for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
!     {
!       tree input;
! 
!       constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
!       input = TREE_VALUE (tail);
! 
!       input = default_function_array_conversion (input);
! 
!       if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
! 				  oconstraints, &allows_mem, &allows_reg))
! 	{
! 	  /* If the operand is going to end up in memory,
! 	     mark it addressable.  */
! 	  if (!allows_reg && allows_mem && !c_mark_addressable (input))
! 	    input = error_mark_node;
! 	}
!       else
! 	input = error_mark_node;
! 
!       TREE_VALUE (tail) = input;
!     }
  
    args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
  
*************** build_asm_expr (tree string, tree output
*** 6337,6342 ****
--- 6364,6370 ----
        ASM_VOLATILE_P (args) = 1;
        ASM_INPUT_P (args) = 1;
      }
+ 
    return args;
  }
  
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.99
diff -c -p -d -r2.99 gimplify.c
*** gcc/gimplify.c	27 Dec 2004 16:06:13 -0000	2.99
--- gcc/gimplify.c	29 Dec 2004 01:17:34 -0000
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3262,3271 ****
    bool allows_mem, allows_reg, is_inout;
    enum gimplify_status ret, tret;
  
-   ASM_STRING (expr)
-     = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
- 				 ASM_INPUTS (expr));
- 
    ret = GS_ALL_DONE;
    for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
      {
--- 3262,3267 ----
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.454
diff -c -p -d -r1.454 semantics.c
*** gcc/cp/semantics.c	21 Dec 2004 17:54:24 -0000	1.454
--- gcc/cp/semantics.c	29 Dec 2004 01:17:35 -0000
*************** finish_asm_stmt (int volatile_p, tree st
*** 1139,1200 ****
  
    if (!processing_template_decl)
      {
        int i;
-       int ninputs;
-       int noutputs;
  
!       for (t = input_operands; t; t = TREE_CHAIN (t))
  	{
! 	  tree converted_operand 
! 	    = decay_conversion (TREE_VALUE (t)); 
! 	  
  	  /* If the type of the operand hasn't been determined (e.g.,
  	     because it involves an overloaded function), then issue
  	     an error message.  There's no context available to
  	     resolve the overloading.  */
! 	  if (TREE_TYPE (converted_operand) == unknown_type_node)
  	    {
  	      error ("type of asm operand %qE could not be determined", 
                       TREE_VALUE (t));
! 	      converted_operand = error_mark_node;
  	    }
- 	  TREE_VALUE (t) = converted_operand;
- 	}
- 
-       ninputs = list_length (input_operands);
-       noutputs = list_length (output_operands);
  
!       for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
! 	{
! 	  bool allows_mem;
! 	  bool allows_reg;
! 	  bool is_inout;
! 	  const char *constraint;
! 	  tree operand;
! 
! 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
! 	  operand = TREE_VALUE (t);
! 
! 	  if (!parse_output_constraint (&constraint,
! 					i, ninputs, noutputs,
! 					&allows_mem,
! 					&allows_reg,
! 					&is_inout))
  	    {
! 	      /* By marking this operand as erroneous, we will not try
! 		 to process this operand again in expand_asm_operands.  */
! 	      TREE_VALUE (t) = error_mark_node;
! 	      continue;
  	    }
  
! 	  /* If the operand is a DECL that is going to end up in
! 	     memory, assume it is addressable.  This is a bit more
! 	     conservative than it would ideally be; the exact test is
! 	     buried deep in expand_asm_operands and depends on the
! 	     DECL_RTL for the OPERAND -- which we don't have at this
! 	     point.  */
! 	  if (!allows_reg && DECL_P (operand))
! 	    cxx_mark_addressable (operand);
  	}
      }
  
--- 1139,1218 ----
  
    if (!processing_template_decl)
      {
+       int ninputs, noutputs;
+       const char *constraint;
+       const char **oconstraints;
+       bool allows_mem, allows_reg, is_inout;
+       tree operand;
        int i;
  
!       ninputs = list_length (input_operands);
!       noutputs = list_length (output_operands);
!       oconstraints = (const char **) alloca (noutputs * sizeof (char *));
! 
!       string = resolve_asm_operand_names (string, output_operands,
! 					  input_operands);
! 
!       for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
  	{
! 	  operand = TREE_VALUE (t);
! 
! 	  /* ??? Really, this should not be here.  Users should be using a
! 	     proper lvalue, dammit.  But there's a long history of using
! 	     casts in the output operands.  In cases like longlong.h, this
! 	     becomes a primitive form of typechecking -- if the cast can be
! 	     removed, then the output operand had a type of the proper width;
! 	     otherwise we'll get an error.  Gross, but ...  */
! 	  STRIP_NOPS (operand);
! 
! 	  if (!lvalue_or_else (operand, lv_asm))
! 	    operand = error_mark_node;
! 
! 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
! 	  oconstraints[i] = constraint;
! 
! 	  if (parse_output_constraint (&constraint, i, ninputs, noutputs,
! 				       &allows_mem, &allows_reg, &is_inout))
! 	    {
! 	      /* If the operand is going to end up in memory,
! 		 mark it addressable.  */
! 	      if (!allows_reg && !cxx_mark_addressable (operand))
! 		operand = error_mark_node;
! 	    }
! 	  else
! 	    operand = error_mark_node;
! 
! 	  TREE_VALUE (t) = operand;
! 	}
! 
!       for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
! 	{
! 	  constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
! 	  operand = decay_conversion (TREE_VALUE (t)); 
! 
  	  /* If the type of the operand hasn't been determined (e.g.,
  	     because it involves an overloaded function), then issue
  	     an error message.  There's no context available to
  	     resolve the overloading.  */
! 	  if (TREE_TYPE (operand) == unknown_type_node)
  	    {
  	      error ("type of asm operand %qE could not be determined", 
                       TREE_VALUE (t));
! 	      operand = error_mark_node;
  	    }
  
! 	  if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
! 				      oconstraints, &allows_mem, &allows_reg))
  	    {
! 	      /* If the operand is going to end up in memory,
! 		 mark it addressable.  */
! 	      if (!allows_reg && allows_mem && !cxx_mark_addressable (operand))
! 		operand = error_mark_node;
  	    }
+ 	  else
+ 	    operand = error_mark_node;
  
! 	  TREE_VALUE (t) = operand;
  	}
      }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]