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]

PATCH: Altivec context-sensitive keywords


This patch is a revised attempt to implement context-sensitive keywords
for the PowerPC port.  There are some libcpp changes, some rs6000
backend changes, and some minor testsuite changes.

To overcome many of the concerns about the interaction of
context-sensitive keywords with ISO C compliance, the feature is now
controlled by !flag_iso.  When compiling with -maltivec, the
context-sensitive keyword support is enabled (and the compiler defines
__APPLE_ALTIVEC__, as required by the PIM).  When _APPLE_ALTIVEC__ is
defined, <altivec.h> will suppress the macros that "implement" these
keywords.

With -maltivec -ansi, the context-sensitive keywords are disabled and to
use the Altivec keywords, you must resort to #including <altivec.h> (the
predefine method).

The two testsuite changes in gcc.dg/vmx are made due to the reasoning
stated here:
  http://gcc.gnu.org/ml/gcc-patches/2008-04/msg01616.html

Rather than remove the use of bool variables from this test, the tests
are now compiled with -ansi to ensure that the predefine method is used.

Tested with a bootstrap on powerpc64-linux and a regression testsuite
run on powerpc-linux and powerpc64-linux.  Okay for mainline?

Cheers, Ben

gcc/
        * coretypes.h (struct cpp_token): Forward declare.
        * doc/extend.texi (PowerPC AltiVec Built-in Functions): Document
        the context-sensitive keyword method.
        * config/rs6000/rs6000-c.c (__vector_keyword, vector_keyword,
        __pixel_keyword, pixel_keyword, __bool_keyword, bool_keyword,
        expand_bool_pixel): New cpp_hashnodes.
        (altivec_categorize_keyword): New function.
        (DSC): Convenience macro, borrowed from libcpp.
        (init_vector_keywords): New function.
        (rs6000_macro_to_expand): Likewise.
        (rs6000_cpu_cpp_builtins): Enable context-sensitive macros if not
        compiling an ISO C dialect.

gcc/testsuite/
        * gcc.target/powerpc/altivec-macros.c: New test.
        * gcc.target/powerpc/altviec-26.c: Likewise.
        * gcc.dg/vmx/1b-06.c: Pass -ansi -maltivec options.
        * gcc.dg/vmx/1b-07.c: Likewise.

libcpp/
        * include/cpplib.h (NODE_CONDITIONAL): New.
        (struct cpp_callbacks): New macro_to_expand field.
        (struct cpp_hashnode): Increase CPP flags from char to int.
        (_cpp_peek_token, _cpp_backup_tokens_direct): Prototype.
        lex.c (_cpp_peek_token): New function.
        (_cpp_temp_token): Protect pre-existing lookaheads.
        * macro.c (cpp_get_token): Expand any conditional macros.
        (_cpp_backup_tokens_direct): New.
        (_cpp_backup_tokens): Call _cpp_backup_tokens_direct.
        (warn_of_redefinition): Silently allow redefined conditional
        macros.
        (_cpp_create_definition): Remove the conditional flag when a user
        defines one of the conditional macros.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 137138)
+++ gcc/doc/extend.texi	(working copy)
@@ -9117,9 +9117,10 @@ always specify the signedness.
 
 @item
 Compiling with @option{-maltivec} adds keywords @code{__vector},
-@code{__pixel}, and @code{__bool}.  Macros @option{vector},
-@code{pixel}, and @code{bool} are defined in @code{<altivec.h>} and can
-be undefined.
+@code{vector}, @code{__pixel}, @code{pixel}, @code{__bool} and
+@code{bool}.  When compiling ISO C, the context-sensitive substitution
+of the keywords @code{vector}, @code{pixel} and @code{bool} is
+disabled.  To use them, you must include @code{<altivec.h>} instead.
 
 @item
 GCC allows using a @code{typedef} name as the type specifier for a
Index: gcc/testsuite/gcc.target/powerpc/altivec-macros.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/altivec-macros.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/altivec-macros.c	(revision 0)
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-maltivec" } */
+
+/* Redefinition of conditional macros.  */
+/* No warning should be generated.  */
+
+#define __vector __new_vector
+#define __pixel __new_pixel
+#define __bool __new_bool
+#define vector new_vector
+#define pixel new_pixel
+#define bool new_bool
+
+/* Definition of conditional macros.  */
+/* No warning should be generated.  */
+
+#undef __vector
+#define __vector __new_vector
+
+#undef __pixel
+#define __pixel __new_pixel
+
+#undef __bool
+#define __bool __new_bool
+
+#undef vector
+#define vector new_vector
+
+#undef pixel
+#define pixel new_pixel
+
+#undef bool
+#define bool new_bool
+
+/* Re-definition of "unconditional" macros.  */
+/* Warnings should be generated as usual.  */
+
+#define __vector	__newer_vector
+#define __pixel		__newer_pixel
+#define __bool		__newer_bool
+#define vector		newer_vector
+#define pixel		newer_pixel
+#define bool		newer_bool
+
+/* { dg-warning "redefined" "__vector redefined"  { target *-*-* } 40 } */
+/* { dg-warning "redefined" "__pixel redefined"   { target *-*-* } 41 } */
+/* { dg-warning "redefined" "__bool redefined"    { target *-*-* } 42 } */
+/* { dg-warning "redefined" "vector redefined"    { target *-*-* } 43 } */
+/* { dg-warning "redefined" "pixel redefined"     { target *-*-* } 44 } */
+/* { dg-warning "redefined" "bool redefined"      { target *-*-* } 45 } */
+
+/* { dg-warning "previous"  "prev __vector defn"  { target *-*-* } 20 } */
+/* { dg-warning "previous"  "prev __pixel defn"   { target *-*-* } 23 } */
+/* { dg-warning "previous"  "prev __bool defn"    { target *-*-* } 26 } */
+/* { dg-warning "previous"  "prev vector defn"    { target *-*-* } 29 } */
+/* { dg-warning "previous"  "prev pixel defn"     { target *-*-* } 32 } */
+/* { dg-warning "previous"  "prev bool defn"      { target *-*-* } 35 } */
Index: gcc/testsuite/gcc.target/powerpc/altivec-26.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/altivec-26.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/altivec-26.c	(revision 0)
@@ -0,0 +1,11 @@
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec" } */
+
+/* A compiler implementing context-sensitive keywords must define this
+   preprocessor macro so that altivec.h does not provide the vector,
+   pixel, etc. macros.  */
+
+#ifndef __APPLE_ALTIVEC__
+#error __APPLE_ALTIVEC__ not pre-defined
+#endif
Index: gcc/testsuite/gcc.dg/vmx/1b-07.c
===================================================================
--- gcc/testsuite/gcc.dg/vmx/1b-07.c	(revision 137138)
+++ gcc/testsuite/gcc.dg/vmx/1b-07.c	(working copy)
@@ -1,4 +1,6 @@
 /* { dg-do compile } */
+/* { dg-options "-ansi -maltivec" } */
+
 #include <altivec.h>
 vector char bool _0 ;
 vector bool char _8 ;
Index: gcc/testsuite/gcc.dg/vmx/1b-06.c
===================================================================
--- gcc/testsuite/gcc.dg/vmx/1b-06.c	(revision 137138)
+++ gcc/testsuite/gcc.dg/vmx/1b-06.c	(working copy)
@@ -1,4 +1,6 @@
 /* { dg-do compile } */
+/* { dg-options "-ansi -maltivec" } */
+
 #include <altivec.h>
 vector char bool _4 ;
 vector char unsigned _31 ;
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	(revision 137138)
+++ gcc/coretypes.h	(working copy)
@@ -60,9 +60,11 @@ enum ir_type {
 
 /* Provide forward struct declaration so that we don't have to include
    all of cpplib.h whenever a random prototype includes a pointer.
-   Note that the cpp_reader typedef remains part of cpplib.h.  */
+   Note that the cpp_reader and cpp_token typedefs remain part of
+   cpplib.h.  */
 
 struct cpp_reader;
+struct cpp_token;
 
 /* The thread-local storage model associated with a given VAR_DECL
    or SYMBOL_REF.  This isn't used much, but both trees and RTL refer
Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c	(revision 137138)
+++ gcc/config/rs6000/rs6000-c.c	(working copy)
@@ -84,6 +84,142 @@ rs6000_pragma_longcall (cpp_reader *pfil
 #define builtin_define(TXT) cpp_define (pfile, TXT)
 #define builtin_assert(TXT) cpp_assert (pfile, TXT)
 
+/* Keep the AltiVec keywords handy for fast comparisons.  */
+static GTY(()) cpp_hashnode *__vector_keyword;
+static GTY(()) cpp_hashnode *vector_keyword;
+static GTY(()) cpp_hashnode *__pixel_keyword;
+static GTY(()) cpp_hashnode *pixel_keyword;
+static GTY(()) cpp_hashnode *__bool_keyword;
+static GTY(()) cpp_hashnode *bool_keyword;
+
+static GTY(()) cpp_hashnode *expand_bool_pixel;  /* Preserved across calls.  */
+
+static cpp_hashnode *
+altivec_categorize_keyword (const cpp_token *tok)
+{
+  if (tok->type == CPP_NAME)
+    {
+      cpp_hashnode *ident = tok->val.node;
+
+      if (ident == vector_keyword || ident == __vector_keyword)
+	return __vector_keyword;
+
+      if (ident == pixel_keyword || ident ==  __pixel_keyword)
+	return __pixel_keyword;
+
+      if (ident == bool_keyword || ident == __bool_keyword)
+	return __bool_keyword;
+
+      return ident;
+    }
+
+  return 0;
+}
+
+/*  From libcpp.  */
+#define DSC(str) (const unsigned char *)str, sizeof str - 1
+
+static void
+init_vector_keywords (cpp_reader *pfile)
+{
+  /* Keywords without two leading underscores are context-sensitive,
+     and hence implemented as conditional macros, controlled by the
+     rs6000_macro_to_expand() function above.  */
+
+  __vector_keyword = cpp_lookup (pfile, DSC ("__vector"));
+  __vector_keyword->flags |= NODE_CONDITIONAL;
+
+  __pixel_keyword = cpp_lookup (pfile, DSC ("__pixel"));
+  __pixel_keyword->flags |= NODE_CONDITIONAL;
+
+  __bool_keyword = cpp_lookup (pfile, DSC ("__bool"));
+  __bool_keyword->flags |= NODE_CONDITIONAL;
+
+  vector_keyword = cpp_lookup (pfile, DSC ("vector"));
+  vector_keyword->flags |= NODE_CONDITIONAL;
+
+  pixel_keyword = cpp_lookup (pfile, DSC ("pixel"));
+  pixel_keyword->flags |= NODE_CONDITIONAL;
+
+  bool_keyword = cpp_lookup (pfile, DSC ("bool"));
+  bool_keyword->flags |= NODE_CONDITIONAL;
+}
+
+/* Called to decide whether a conditional macro should be expanded.
+   Since we have exactly one such macro (i.e, 'vector'), we do not
+   need to examine the 'tok' parameter.  */
+
+static cpp_hashnode *
+rs6000_macro_to_expand (cpp_reader *pfile, const cpp_token *tok)
+{
+  static bool vector_keywords_init = false;
+  cpp_hashnode *expand_this = tok->val.node;
+  cpp_hashnode *ident;
+
+  if (!vector_keywords_init)
+    {
+      init_vector_keywords (pfile);
+      vector_keywords_init = true;
+    }
+
+  ident = altivec_categorize_keyword (tok);
+
+  if (ident == __vector_keyword)
+    {
+      tok = _cpp_peek_token (pfile, 0);
+      ident = altivec_categorize_keyword (tok);
+
+      if (ident ==  __pixel_keyword || ident == __bool_keyword)
+	{
+	  expand_this = __vector_keyword;
+	  expand_bool_pixel = ident;
+	}
+      else if (ident)
+	{
+	  enum rid rid_code = (enum rid)(ident->rid_code);
+	  if (ident->type == NT_MACRO)
+	    {
+	      (void)cpp_get_token (pfile);
+	      tok = _cpp_peek_token (pfile, 0);
+	      ident = altivec_categorize_keyword (tok);
+	      if (ident)
+		rid_code = (enum rid)(ident->rid_code);
+	    }
+
+	  if (rid_code == RID_UNSIGNED || rid_code == RID_LONG
+	      || rid_code == RID_SHORT || rid_code == RID_SIGNED
+	      || rid_code == RID_INT || rid_code == RID_CHAR
+	      || rid_code == RID_FLOAT)
+	    {
+	      expand_this = __vector_keyword;
+	      /* If the next keyword is bool or pixel, it
+		 will need to be expanded as well.  */
+	      tok = _cpp_peek_token (pfile, 1);
+	      ident = altivec_categorize_keyword (tok);
+
+	      if (ident ==  __pixel_keyword || ident == __bool_keyword)
+		expand_bool_pixel = ident;
+	      else
+		{
+		  /* Try two tokens down, too.  */
+		  tok = _cpp_peek_token (pfile, 2);
+		  ident = altivec_categorize_keyword (tok);
+		  if (ident ==  __pixel_keyword || ident == __bool_keyword)
+		    expand_bool_pixel = ident;
+		}
+	    }
+	}
+    }
+  else if (expand_bool_pixel
+	   && (ident ==  __pixel_keyword || ident == __bool_keyword))
+    {
+      expand_this = expand_bool_pixel;
+      expand_bool_pixel = 0;
+    }
+
+  return expand_this;
+}
+
 void
 rs6000_cpu_cpp_builtins (cpp_reader *pfile)
 {
@@ -120,6 +256,20 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
       builtin_define ("__vector=__attribute__((altivec(vector__)))");
       builtin_define ("__pixel=__attribute__((altivec(pixel__))) unsigned short");
       builtin_define ("__bool=__attribute__((altivec(bool__))) unsigned");
+
+      if (!flag_iso)
+	{
+	  /* Define this when supporting context-sensitive keywords.  */
+	  builtin_define ("__APPLE_ALTIVEC__");
+	  
+	  builtin_define ("vector=vector");
+	  builtin_define ("pixel=pixel");
+	  builtin_define ("bool=bool");
+	  init_vector_keywords (pfile);
+
+	  /* Enable context-sensitive macros.  */
+	  cpp_get_callbacks (pfile)->macro_to_expand = rs6000_macro_to_expand;
+	}
     }
   if (TARGET_SPE)
     builtin_define ("__SPE__");
Index: libcpp/macro.c
===================================================================
--- libcpp/macro.c	(revision 137138)
+++ libcpp/macro.c	(working copy)
@@ -1240,16 +1240,21 @@ cpp_get_token (cpp_reader *pfile)
 
       if (!(node->flags & NODE_DISABLED))
 	{
-	  int ret;
+	  int ret = 0;
 	  /* If not in a macro context, and we're going to start an
 	     expansion, record the location.  */
 	  if (can_set && !context->macro)
 	    pfile->invocation_location = result->src_loc;
 	  if (pfile->state.prevent_expansion)
 	    break;
-	  ret = enter_macro_context (pfile, node, result);
-	  if (ret)
-	    {
+
+	  /* Conditional macros require that a predicate be evaluated
+	     first.  */
+	  if (((!(node->flags & NODE_CONDITIONAL))
+	       || (pfile->cb.macro_to_expand
+		   && (node = pfile->cb.macro_to_expand (pfile, result))))
+	      && (ret = enter_macro_context (pfile, node, result)))
+ 	    {
 	      if (pfile->state.in_directive || ret == 2)
 		continue;
 	      return padding_token (pfile, result);
@@ -1327,26 +1332,31 @@ cpp_scan_nooutput (cpp_reader *pfile)
   pfile->state.prevent_expansion--;
 }
 
+/* Step back one or more tokens obtained from the lexer.  */
+void
+_cpp_backup_tokens_direct (cpp_reader *pfile, unsigned int count)
+{
+  pfile->lookaheads += count;
+  while (count--)
+    {
+      pfile->cur_token--;
+      if (pfile->cur_token == pfile->cur_run->base
+          /* Possible with -fpreprocessed and no leading #line.  */
+          && pfile->cur_run->prev != NULL)
+        {
+          pfile->cur_run = pfile->cur_run->prev;
+          pfile->cur_token = pfile->cur_run->limit;
+        }
+    }
+}
+
 /* Step back one (or more) tokens.  Can only step back more than 1 if
    they are from the lexer, and not from macro expansion.  */
 void
 _cpp_backup_tokens (cpp_reader *pfile, unsigned int count)
 {
   if (pfile->context->prev == NULL)
-    {
-      pfile->lookaheads += count;
-      while (count--)
-	{
-	  pfile->cur_token--;
-	  if (pfile->cur_token == pfile->cur_run->base
-	      /* Possible with -fpreprocessed and no leading #line.  */
-	      && pfile->cur_run->prev != NULL)
-	    {
-	      pfile->cur_run = pfile->cur_run->prev;
-	      pfile->cur_token = pfile->cur_run->limit;
-	    }
-	}
-    }
+    _cpp_backup_tokens_direct (pfile, count);
   else
     {
       if (count != 1)
@@ -1372,6 +1382,11 @@ warn_of_redefinition (cpp_reader *pfile,
   if (node->flags & NODE_WARN)
     return true;
 
+  /* Redefinitions of conditional (context-sensitive) macros, on
+     the other hand, must be allowed silently.  */
+  if (node->flags & NODE_CONDITIONAL)
+    return false;
+
   /* Redefinition of a macro is allowed if and only if the old and new
      definitions are the same.  (6.10.3 paragraph 2).  */
   macro1 = node->value.macro;
@@ -1804,6 +1819,10 @@ _cpp_create_definition (cpp_reader *pfil
       && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_CONSTANT_MACROS"))
     node->flags |= NODE_WARN;
 
+  /* If user defines one of the conditional macros, remove the
+     conditional flag */
+  node->flags &= ~NODE_CONDITIONAL;
+
   return ok;
 }
 
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 137138)
+++ libcpp/include/cpplib.h	(working copy)
@@ -484,6 +484,10 @@ struct cpp_callbacks
   void (*read_pch) (cpp_reader *, const char *, int, const char *);
   missing_header_cb missing_header;
 
+  /* Context-sensitive macro support.  Returns macro (if any) that should
+     be expanded.  */
+  cpp_hashnode * (*macro_to_expand) (cpp_reader *, const cpp_token *);
+
   /* Called to emit a diagnostic if client_diagnostic option is true.
      This callback receives the translated message.  */
   void (*error) (cpp_reader *, int, const char *, va_list *)
@@ -558,6 +562,7 @@ extern const char *progname;
 #define NODE_DISABLED	(1 << 5)	/* A disabled macro.  */
 #define NODE_MACRO_ARG	(1 << 6)	/* Used during #define processing.  */
 #define NODE_USED	(1 << 7)	/* Dumped with -dU.  */
+#define NODE_CONDITIONAL (1 << 8)	/* Conditional macro */
 
 /* Different flavors of hash node.  */
 enum node_type
@@ -630,7 +635,7 @@ struct cpp_hashnode GTY(())
 					   Otherwise, a NODE_OPERATOR.  */
   unsigned char rid_code;		/* Rid code - for front ends.  */
   ENUM_BITFIELD(node_type) type : 8;	/* CPP node type.  */
-  unsigned char flags;			/* CPP flags.  */
+  unsigned int flags;			/* CPP flags.  */
 
   union _cpp_hashnode_value GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value;
 };
@@ -717,6 +722,8 @@ extern const cpp_token *cpp_get_token_wi
 extern const unsigned char *cpp_macro_definition (cpp_reader *,
 						  const cpp_hashnode *);
 extern void _cpp_backup_tokens (cpp_reader *, unsigned int);
+extern const cpp_token *_cpp_peek_token (cpp_reader *, int);
+extern void _cpp_backup_tokens_direct (cpp_reader *, unsigned int);
 
 /* Evaluate a CPP_CHAR or CPP_WCHAR token.  */
 extern cppchar_t cpp_interpret_charconst (cpp_reader *, const cpp_token *,
Index: libcpp/lex.c
===================================================================
--- libcpp/lex.c	(revision 137138)
+++ libcpp/lex.c	(working copy)
@@ -734,6 +734,45 @@ next_tokenrun (tokenrun *run)
   return run->next;
 }
 
+/* Look ahead in the input stream.  */
+const cpp_token *
+_cpp_peek_token (cpp_reader *pfile, int index)
+{
+  cpp_context *context = pfile->context;
+  const cpp_token *peektok;
+  int count;
+
+  /* First, scan through any pending cpp_context objects.  */
+  while (context->prev)
+    {
+      ptrdiff_t sz = (context->direct_p
+                      ? LAST (context).token - FIRST (context).token
+                      : LAST (context).ptoken - FIRST (context).ptoken);
+
+      if (index < (int) sz)
+        return (context->direct_p
+                ? FIRST (context).token + index
+                : *(FIRST (context).ptoken + index));
+
+      index -= (int) sz;
+      context = context->prev;
+    }
+
+  /* We will have to read some new tokens after all (and do so
+     without invalidating preceding tokens).  */
+  count = index;
+  pfile->keep_tokens++;
+
+  do
+    peektok = _cpp_lex_token (pfile);
+  while (index--);
+
+  _cpp_backup_tokens_direct (pfile, count + 1);
+  pfile->keep_tokens--;
+
+  return peektok;
+}
+
 /* Allocate a single token that is invalidated at the same time as the
    rest of the tokens on the line.  Has its line and col set to the
    same as the last lexed token, so that diagnostics appear in the
@@ -742,9 +781,30 @@ cpp_token *
 _cpp_temp_token (cpp_reader *pfile)
 {
   cpp_token *old, *result;
+  ptrdiff_t sz = pfile->cur_run->limit - pfile->cur_token;
+  ptrdiff_t la = (ptrdiff_t) pfile->lookaheads;
 
   old = pfile->cur_token - 1;
-  if (pfile->cur_token == pfile->cur_run->limit)
+  /* Any pre-existing lookaheads must not be clobbered.  */
+  if (la)
+    {
+      if (sz <= la)
+        {
+          tokenrun *next = next_tokenrun (pfile->cur_run);
+
+          if (sz < la)
+            memmove (next->base + 1, next->base,
+                     (la - sz) * sizeof (cpp_token));
+
+          next->base[0] = pfile->cur_run->limit[-1];
+        }
+
+      if (sz > 1)
+        memmove (pfile->cur_token + 1, pfile->cur_token,
+                 MIN (la, sz - 1) * sizeof (cpp_token));
+    }
+
+  if (!sz && pfile->cur_token == pfile->cur_run->limit)
     {
       pfile->cur_run = next_tokenrun (pfile->cur_run);
       pfile->cur_token = pfile->cur_run->base;



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