This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Altivec context-sensitive keywords
- From: Ben Elliston <bje at au1 dot ibm dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Cc: David Edelsohn <dje at watson dot ibm dot com>, janis187 <janis187 at us dot ibm dot com>, Tom Tromey <tromey at redhat dot com>
- Date: Thu, 26 Jun 2008 21:04:14 +1000
- Subject: 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;