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]

RS/6000 patch adding some features for PPC compiler



Hello.


First of all I would like to introduce myself. I am one of AROS developers, working on AmigaOS compatible operating system. Currently my interests are to port our OS to PPC based platform (PReP and CHRP machines).

In order to do that (and to simplify porting issues), together with Fabio Alemagna (one of AROS developers) I have patched gcc so that it understands "stackparm" attribute in functions. Function defined with stackparm doesn not create the parameters frame used by __builtin_va* functions but instead pushes all the parameters on the stack (function_arg() returns always NULL_RTX);

The second part of the patch is related with compatibility issues. Since on original AmigaOS parameters to system functions were passed in registers, I wanted to follow this tradition on PPC architectures too. First of all standard ABI allows only up to 8 parameters to be passed in registers (some library functions take even 12!), secondly, this way it would be easier to implement M68K emulation into the system (there would be no need to trace how and where parameters should be passed, just simple mapping, eg. D0-D7 => R16-R23, A0-A7 => R24-R31).

In order to do that, I have added "regarg" attribute. It requires one parameter which is the register name where argument is supposed to be. the function may look like this:

int foo(int arg __attribute__((regarg("r16"))))
{
	[...]
}

The attached patch is for gcc-3.2.3.

I have two problems with that:

1) If the vararg function (without stackparm) is called from function with registerized parameter, it does not work. I have no clue why especially that I haven't change anything within vararg handling part of rs6000.c file

2) By strong optimisations (-O2, -O3) gcc "forgets" somehow that it should initialize all registers with given parameters. Looking at asm output I see the initialization (some of them even 100 instructions before the call), but then the content of given registers is overwritten. Is it my fault or gcc's?

I hope there is someone who could help me.

PS. Yes, I have read the gccint docs, but they couldn't help me solving my problems.

with best regards,

--
Michal Schulz
Institut für Metallurgie
TU Clausthal
Robert-Koch-Straße 42
38678 Clausthal-Zellerfeld


diff -Naur gcc-3.2.3-org/gcc/config/rs6000/rs6000.c gcc-3.2.3/gcc/config/rs6000/rs6000.c
--- gcc-3.2.3-org/gcc/config/rs6000/rs6000.c	2003-04-08 22:03:23.000000000 +0000
+++ gcc-3.2.3/gcc/config/rs6000/rs6000.c	2003-05-29 23:07:00.000000000 +0000
@@ -141,6 +141,7 @@
 static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));
 static int rs6000_ra_ever_killed PARAMS ((void));
 static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree rs6000_handle_register_attribute PARAMS ((tree *, tree, tree, int, bool *));
 const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
 static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
@@ -2510,6 +2511,13 @@
   if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
     cum->call_cookie = CALL_LONG;
 
+  cum->int_regmask = 0x00003fff;	/* r14 - r31 are free for use */
+  cum->fp_regmask =  0x00003fff;	/* f14 - f31 are free for use */
+  cum->altivec_regmask = 0;		/* all altivec regs free */
+
+  cum->stackparm = fntype && lookup_attribute("stackparm",
+					      TYPE_ATTRIBUTES(fntype));
+
   if (TARGET_DEBUG_ARG)
     {
       fprintf (stderr, "\ninit_cumulative_args:");
@@ -2585,8 +2593,49 @@
      tree type;
      int named;
 {
+  tree regarg = lookup_attribute("regarg", TYPE_ATTRIBUTES(type));
+
   cum->nargs_prototype--;
 
+  /*
+    If regarg attribute is defined and we are within function prototype,
+    allocate space for given reg.
+  */
+  if (regarg && cum->prototype)
+  {
+    int reg = decode_reg_name(TREE_STRING_POINTER(TREE_VALUE(TREE_VALUE(regarg))));
+    int *mask = NULL;
+    int size = 0;
+    
+    if (INT_REGNO_P(reg))
+    {
+	mask = &cum->int_regmask;
+	size = RS6000_ARG_SIZE(mode, type);
+    }
+    else if (FP_REGNO_P(reg))
+    {
+	mask = &cum->fp_regmask;
+	reg -= 32;
+    }
+    else if (ALTIVEC_REGNO_P(reg))
+    {
+	mask = &cum->altivec_regmask;
+	reg -= FIRST_ALTIVEC_REGNO;
+    }
+    
+    if ((*mask & (1 << reg)) || ((size == 2) && (*mask & (3 << (reg)))))
+    {
+      error("Register %s used twice in function call",
+        TREE_STRING_POINTER(TREE_VALUE(TREE_VALUE(regarg))));
+    }
+    
+    if (size == 2)
+	*mask |= (3 << (reg));
+    else
+	*mask |= (1 << reg);
+  } 
+  else
+
   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
       if (cum->vregno <= ALTIVEC_ARG_MAX_REG && cum->nargs_prototype >= 0)
@@ -2702,6 +2751,9 @@
 {
   enum rs6000_abi abi = DEFAULT_ABI;
 
+  tree regarg;
+  
+
   /* Return a marker to indicate whether CR1 needs to set or clear the
      bit that V.4 uses to say fp args were passed in registers.
      Assume that we don't need the marker for software floating point,
@@ -2722,6 +2774,35 @@
       return GEN_INT (cum->call_cookie);
     }
 
+  /*
+    Test whether there is "regarg" attribute defined for this parameter.
+    if we are called as prototype, rework it to register format, ignore it
+    otherwise.
+  */
+    regarg = lookup_attribute("regarg", TYPE_ATTRIBUTES(type));
+  if (regarg) // && cum->prototype)
+  {
+    int reg = decode_reg_name(TREE_STRING_POINTER(TREE_VALUE(TREE_VALUE(regarg))));
+
+    if (reg < 0)
+    {
+      error("Invalid register name '%s'", 
+    	    TREE_STRING_POINTER(TREE_VALUE(TREE_VALUE(regarg))));
+      return NULL_RTX;
+    }
+    else if (!HARD_REGNO_MODE_OK(reg, mode))
+    {
+      error("Invalid register '%s' for argument", 
+    	    TREE_STRING_POINTER(TREE_VALUE(TREE_VALUE(regarg))));
+      return NULL_RTX;
+    }
+
+    return gen_rtx_REG(mode, reg);
+  }
+
+    if (cum->stackparm)
+	return NULL_RTX;
+
   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
       if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
@@ -2902,6 +2983,9 @@
   tree fntype;
   int stdarg_p;
 
+  if (cum->stackparm)
+    return;
+
   fntype = TREE_TYPE (current_function_decl);
   stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
 	      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -10740,6 +10824,8 @@
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
   { "longcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
+  { "stackparm",0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
+  { "regarg",   1, 1, false, false, false, rs6000_handle_register_attribute },
   { NULL,       0, 0, false, false, false, NULL }
 };
 
@@ -10766,6 +10852,78 @@
   return NULL_TREE;
 }
 
+static tree
+rs6000_handle_register_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+    if (TREE_CODE (*node) != PARM_DECL)
+    {
+       warning ("`%s' attribute only applies to function parameters",
+                IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else
+     {
+       tree cst;
+ 
+       cst = TREE_VALUE (args);
+       if (TREE_CODE (cst) != STRING_CST)
+         {
+           error ("`%s' attribute requires a string constant argument specifying a register name",
+                    IDENTIFIER_POINTER (name));
+ 
+           *no_add_attrs = true;
+         }
+       else
+         {
+           /* Ok, this is a PARM_DECL which has a register attribute
+              with the proper argument. However, we need to set the attribute
+              to the DECL's TYPE, rather than to the DECL itself, because
+              the TYPE is what we deal with in function_arg(). The framework
+              doesn't seem to allow for this or, rather, it allows to transfer
+              a DECL's attribute to its TYPE, but the way it does it doesn't let
+              this function know to which DECL that TYPE belongs, and since we
+              only allow "regarg" to be specified for PARM_DECL's, that's not
+              good.
+ 
+              So here we do the same work that decl_attributes() in attribs.c
+              does, only we do it the right way.  */
+ 
+           tree old_attrs;
+           tree a;
+ 
+           old_attrs = TYPE_ATTRIBUTES (TREE_TYPE(*node));
+ 
+           for (a = lookup_attribute ("regarg", old_attrs);
+                a != NULL_TREE;
+                a = lookup_attribute ("regarg", TREE_CHAIN (a)))
+             {
+               if (simple_cst_equal (TREE_VALUE (a), args) == 1)
+                 break;
+             }
+ 
+           if (a == NULL_TREE)
+             {
+               /* This attribute isn't already in the list.  */
+               TREE_TYPE(*node) = build_type_attribute_variant (TREE_TYPE(*node),
+                                                           tree_cons (name, args,
+                                                                     old_attrs));
+             }
+ 
+             /* Now that the attribute has been added to the DECL's TYPE, don't
+                add it to the DECL itself.  */
+ 
+             *no_add_attrs = true;
+         }
+      }
+  
+    return NULL_TREE;
+}
+
 /* Return a reference suitable for calling a function with the
    longcall attribute.  */
 
diff -Naur gcc-3.2.3-org/gcc/config/rs6000/rs6000.h gcc-3.2.3/gcc/config/rs6000/rs6000.h
--- gcc-3.2.3-org/gcc/config/rs6000/rs6000.h	2003-03-29 12:39:20.000000000 +0000
+++ gcc-3.2.3/gcc/config/rs6000/rs6000.h	2003-05-29 21:15:07.000000000 +0000
@@ -1594,6 +1594,10 @@
   int nargs_prototype;		/* # args left in the current prototype */
   int orig_nargs;		/* Original value of nargs_prototype */
   int prototype;		/* Whether a prototype was defined */
+  int stackparm;
+  int int_regmask;
+  int fp_regmask;
+  int altivec_regmask;
   int call_cookie;		/* Do special things for this call */
   int sysv_gregno;		/* next available GP register */
 } CUMULATIVE_ARGS;

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