[PATCH, libcpp, rs6000]: context-sensitive Altivec keywords

Ben Elliston bje@au1.ibm.com
Fri Dec 7 03:12:00 GMT 2007


The following patch is adapted from a similar patch on the
branches/apple/trunk branch.  It adds context-sensitive keywords via
conditional macro expansion.  The patch adds the libcpp support and the
rs6000 backend changes required to activate the keywords.

Tested with a bootstrap and regression test run on powerpc-linux.  Two
new test cases are included.

Okay for the trunk during stage 1?

Ben

libcpp/
2007-12-06  Ben Elliston  <bje@au.ibm.com>

	* include/cpplib.h (struct cpp_callbacks): Add macro_to_expand.
	(NODE_CONDITIONAL): New.
	(_cpp_peek_token): Declare.
	(_cpp_backup_tokens_direct): Likewise.
	* lex.c (_cpp_peek_token): New function.
	(_cpp_temp_token): Pre-existing lookaheads must not be
	clobbered.
	* macro.c (cpp_get_token): Handle conditional macros.
	(_cpp_backup_tokens_direct): Factor out code from ..
	(_cpp_backup_tokens): .. here. Call _cpp_backup_tokens_direct.
	(warn_of_redefinition): Silently allow redefinitions of
	context-sensitive macros. Remove NODE_CONDITIONAL flag if the user
	defines one of the conditional macros.

gcc/
2007-12-06  Ben Elliston  <bje@au.ibm.com>

	* coretypes.h (struct cpp_token): Forward declare.
	* config/rs6000/rs6000-c.c (__vector_keyword, vector_keyword,
	__pixel_keyword, pixel_keyword, __bool_keyword, bool_keyword,
	expand_bool_pixel): New cpp hashnodes.
	(altivec_categorized_keyword): New.
	(init_vector_keywords): Likewise.
	(rs6000_macro_to_expand): Likewise.
	(rs6000_cpu_cpp_builtins): Add builtins for __APPLE_ALTIVEC__,
	vector, pixel and bool.  Enable context-sensitive macros.
	* doc/extend.texi (PowerPC AltiVec Built-in Functions):
	Document that -maltivec adds all of the AltiVec keywords. Do
	not mention <altivec.h>.
	
Index: gcc-trunk/libcpp/include/cpplib.h
===================================================================
--- gcc-trunk.orig/libcpp/include/cpplib.h	2007-12-06 14:50:00.000000000 +1100
+++ gcc-trunk/libcpp/include/cpplib.h	2007-12-07 11:20:48.000000000 +1100
@@ -476,6 +476,10 @@
   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 *)
@@ -537,6 +541,7 @@
 #define NODE_WARN	(1 << 4)	/* Warn if redefined or undefined.  */
 #define NODE_DISABLED	(1 << 5)	/* A disabled macro.  */
 #define NODE_MACRO_ARG	(1 << 6)	/* Used during #define processing.  */
+#define NODE_CONDITIONAL (1 << 7)	/* Conditional macro */
 
 /* Different flavors of hash node.  */
 enum node_type
@@ -696,6 +701,8 @@
 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 *,
@@ -862,6 +869,7 @@
 extern cpp_buffer *cpp_get_buffer (cpp_reader *);
 extern struct _cpp_file *cpp_get_file (cpp_buffer *);
 extern cpp_buffer *cpp_get_prev (cpp_buffer *);
+extern void cpp_clear_file_cache (cpp_reader *);
 
 /* In cpppch.c */
 struct save_macro_data;
Index: gcc-trunk/libcpp/lex.c
===================================================================
--- gcc-trunk.orig/libcpp/lex.c	2007-12-06 14:50:00.000000000 +1100
+++ gcc-trunk/libcpp/lex.c	2007-12-06 14:53:30.000000000 +1100
@@ -730,6 +730,45 @@
   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
@@ -738,9 +777,30 @@
 _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: gcc-trunk/libcpp/macro.c
===================================================================
--- gcc-trunk.orig/libcpp/macro.c	2007-12-06 14:50:00.000000000 +1100
+++ gcc-trunk/libcpp/macro.c	2007-12-06 14:51:11.000000000 +1100
@@ -1149,6 +1149,11 @@
 	  if (can_set && !context->macro)
 	    pfile->invocation_location = result->src_loc;
 	  if (!pfile->state.prevent_expansion
+              /* Conditional macros require that a predicate be
+                 evaluated first.  */
+              && (!(node->flags & NODE_CONDITIONAL)
+                  || (pfile->cb.macro_to_expand
+                      && (node = pfile->cb.macro_to_expand (pfile, result))))
 	      && enter_macro_context (pfile, node))
 	    {
 	      if (pfile->state.in_directive)
@@ -1228,26 +1233,31 @@
   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)
@@ -1273,6 +1283,11 @@
   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;
@@ -1699,6 +1714,10 @@
       && ustrcmp (NODE_NAME (node), (const uchar *) "__STDC_FORMAT_MACROS"))
     node->flags |= NODE_WARN;
 
+  /* If user defines one of the conditional macros, remove the
+     conditional flag */
+  node->flags &= ~NODE_CONDITIONAL;
+
   return ok;
 }
 
Index: gcc-trunk/gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc-trunk.orig/gcc/config/rs6000/rs6000-c.c	2007-12-06 14:50:00.000000000 +1100
+++ gcc-trunk/gcc/config/rs6000/rs6000-c.c	2007-12-06 14:51:11.000000000 +1100
@@ -84,6 +84,134 @@
 #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 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)
 {
@@ -114,12 +242,22 @@
   if (TARGET_ALTIVEC)
     {
       builtin_define ("__ALTIVEC__");
+      /* Define this when supporting context-sensitive keywords.  */
+      builtin_define ("__APPLE_ALTIVEC__");
       builtin_define ("__VEC__=10206");
 
       /* Define the AltiVec syntactic elements.  */
       builtin_define ("__vector=__attribute__((altivec(vector__)))");
       builtin_define ("__pixel=__attribute__((altivec(pixel__))) unsigned short");
       builtin_define ("__bool=__attribute__((altivec(bool__))) unsigned");
+
+      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: gcc-trunk/gcc/testsuite/gcc.target/powerpc/altivec-25.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-trunk/gcc/testsuite/gcc.target/powerpc/altivec-25.c	2007-12-06 14:51:11.000000000 +1100
@@ -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-trunk/gcc/testsuite/gcc.target/powerpc/altivec-macros.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc-trunk/gcc/testsuite/gcc.target/powerpc/altivec-macros.c	2007-12-07 13:57:00.000000000 +1100
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-std=c99 -pedantic" } */
+
+/* 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-trunk/gcc/coretypes.h
===================================================================
--- gcc-trunk.orig/gcc/coretypes.h	2007-12-06 14:51:06.000000000 +1100
+++ gcc-trunk/gcc/coretypes.h	2007-12-06 14:51:56.000000000 +1100
@@ -60,9 +60,11 @@
 
 /* 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-trunk/gcc/doc/extend.texi
===================================================================
--- gcc-trunk.orig/gcc/doc/extend.texi	2007-12-07 13:02:32.000000000 +1100
+++ gcc-trunk/gcc/doc/extend.texi	2007-12-07 13:02:41.000000000 +1100
@@ -8844,9 +8844,8 @@
 
 @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}.
 
 @item
 GCC allows using a @code{typedef} name as the type specifier for a




More information about the Gcc-patches mailing list