6771309: debugging AD files is difficult without #line directives in generated code
authorjrose
Tue, 09 Dec 2008 12:41:26 -0800
changeset 1662 76a93a5fb765
parent 1661 7cb0f0d385f3
child 1663 e4de17987e7d
6771309: debugging AD files is difficult without #line directives in generated code Summary: more and better #line and #define directives in the generated code; ADLC itself accepts #line directives Reviewed-by: never, kvn
hotspot/make/linux/adlc_updater
hotspot/make/linux/makefiles/adlc.make
hotspot/make/solaris/adlc_updater
hotspot/make/solaris/makefiles/adlc.make
hotspot/src/share/vm/adlc/adlparse.cpp
hotspot/src/share/vm/adlc/adlparse.hpp
hotspot/src/share/vm/adlc/archDesc.cpp
hotspot/src/share/vm/adlc/dfa.cpp
hotspot/src/share/vm/adlc/filebuff.hpp
hotspot/src/share/vm/adlc/formssel.cpp
--- a/hotspot/make/linux/adlc_updater	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/make/linux/adlc_updater	Tue Dec 09 12:41:26 2008 -0800
@@ -7,5 +7,13 @@
 #
 # adlc-updater <file> <source-dir> <target-dir>
 #
-[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
-( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
+fix_lines() {
+  # repair bare #line directives in $1 to refer to $2
+  awk < $1 > $1+ '
+    /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
+    {print}
+  ' F2=$2
+  mv $1+ $1
+}
+[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \
+( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/linux/makefiles/adlc.make	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/make/linux/makefiles/adlc.make	Tue Dec 09 12:41:26 2008 -0800
@@ -54,9 +54,11 @@
 Src_Dirs_I = ${Src_Dirs} $(GENERATED)
 INCLUDES += $(Src_Dirs_I:%=-I%)
 
+# set flags for adlc compilation
+CPPFLAGS = $(SYSDEFS) $(INCLUDES)
+
 # Force assertions on.
-SYSDEFS += -DASSERT
-CPPFLAGS = $(SYSDEFS) $(INCLUDES)
+CPPFLAGS += -DASSERT
 
 # CFLAGS_WARN holds compiler options to suppress/enable warnings.
 # Suppress warnings (for now)
@@ -125,7 +127,15 @@
 # Note that product files are updated via "mv", which is atomic.
 TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$)
 
-ADLCFLAGS = -q -T
+# Pass -D flags into ADLC.
+ADLCFLAGS += $(SYSDEFS)
+
+# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO.
+ADLCFLAGS += -q -T
+
+# Normally, debugging is done directly on the ad_<arch>*.cpp files.
+# But -g will put #line directives in those files pointing back to <arch>.ad.
+#ADLCFLAGS += -g
 
 ifdef LP64
 ADLCFLAGS += -D_LP64
@@ -140,6 +150,8 @@
 #
 ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS)
 ADLC_UPDATER = adlc_updater
+$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER)
+	$(QUIETLY) cp $< $@; chmod +x $@
 
 # This action refreshes all generated adlc files simultaneously.
 # The way it works is this:
@@ -149,9 +161,8 @@
 # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files.
 # 5) If we actually updated any files, echo a notice.
 #
-refresh_adfiles: $(EXEC) $(SOURCE.AD)
+refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER)
 	@rm -rf $(TEMPDIR); mkdir $(TEMPDIR)
-	$(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) )
 	$(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \
  -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \
 	    || { rm -rf $(TEMPDIR); exit 1; }
@@ -174,7 +185,15 @@
 # #########################################################################
 
 $(SOURCE.AD): $(SOURCES.AD)
-	$(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD)
+	$(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD)
+
+#PROCESS_AD_FILES = cat
+# Pass through #line directives, in case user enables -g option above:
+PROCESS_AD_FILES = awk '{ \
+    if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \
+    if (need_lineno && $$0 !~ /\/\//) \
+      { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \
+    print }'
 
 $(OUTDIR)/%.o: %.cpp
 	@echo Compiling $<
--- a/hotspot/make/solaris/adlc_updater	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/make/solaris/adlc_updater	Tue Dec 09 12:41:26 2008 -0800
@@ -7,5 +7,13 @@
 #
 # adlc-updater <file> <source-dir> <target-dir>
 #
-[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
-( [ -f $3/$1 ]; echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
+fix_lines() {
+  # repair bare #line directives in $1 to refer to $2
+  awk < $1 > $1+ '
+    /^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
+    {print}
+  ' F2=$2
+  mv $1+ $1
+}
+[ -f $3/$1 ] && (fix_lines $2/$1 $3/$1; cmp -s $2/$1 $3/$1) || \
+( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/solaris/makefiles/adlc.make	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/make/solaris/makefiles/adlc.make	Tue Dec 09 12:41:26 2008 -0800
@@ -54,9 +54,11 @@
 Src_Dirs_I = ${Src_Dirs} $(GENERATED)
 INCLUDES += $(Src_Dirs_I:%=-I%)
 
+# set flags for adlc compilation
+CPPFLAGS = $(SYSDEFS) $(INCLUDES)
+
 # Force assertions on.
-SYSDEFS += -DASSERT
-CPPFLAGS = $(SYSDEFS) $(INCLUDES)
+CPPFLAGS += -DASSERT
 
 ifndef USE_GCC
   # We need libCstd.so for adlc 
@@ -141,7 +143,15 @@
 # Note that product files are updated via "mv", which is atomic.
 TEMPDIR := $(OUTDIR)/mktmp$(shell echo $$$$)
 
-ADLCFLAGS = -q -T
+# Pass -D flags into ADLC.
+ADLCFLAGS += $(SYSDEFS)
+
+# Note "+="; it is a hook so flags.make can add more flags, like -g or -DFOO.
+ADLCFLAGS += -q -T
+
+# Normally, debugging is done directly on the ad_<arch>*.cpp files.
+# But -g will put #line directives in those files pointing back to <arch>.ad.
+#ADLCFLAGS += -g
 
 ifdef LP64
 ADLCFLAGS += -D_LP64
@@ -156,6 +166,8 @@
 #
 ADLC_UPDATER_DIRECTORY = $(GAMMADIR)/make/$(OS)
 ADLC_UPDATER = adlc_updater
+$(ADLC_UPDATER): $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER)
+	$(QUIETLY) cp $< $@; chmod +x $@
 
 # This action refreshes all generated adlc files simultaneously.
 # The way it works is this:
@@ -165,9 +177,8 @@
 # 4) call $(ADLC_UPDATER) on each generated adlc file. It will selectively update changed or missing files.
 # 5) If we actually updated any files, echo a notice.
 #
-refresh_adfiles: $(EXEC) $(SOURCE.AD)
+refresh_adfiles: $(EXEC) $(SOURCE.AD) $(ADLC_UPDATER)
 	@rm -rf $(TEMPDIR); mkdir $(TEMPDIR)
-	$(QUIETLY) [ -f $(ADLC_UPDATER) ] || ( cp $(ADLC_UPDATER_DIRECTORY)/$(ADLC_UPDATER) . ; chmod +x $(ADLC_UPDATER) )
 	$(QUIETLY) $(EXEC) $(ADLCFLAGS) $(SOURCE.AD) \
  -c$(TEMPDIR)/ad_$(Platform_arch_model).cpp -h$(TEMPDIR)/ad_$(Platform_arch_model).hpp -a$(TEMPDIR)/dfa_$(Platform_arch_model).cpp -v$(TEMPDIR)/adGlobals_$(Platform_arch_model).hpp \
 	    || { rm -rf $(TEMPDIR); exit 1; }
@@ -190,7 +201,15 @@
 # #########################################################################
 
 $(SOURCE.AD): $(SOURCES.AD)
-	$(QUIETLY) cat $(SOURCES.AD) > $(SOURCE.AD)
+	$(QUIETLY) $(PROCESS_AD_FILES) $(SOURCES.AD) > $(SOURCE.AD)
+
+#PROCESS_AD_FILES = cat
+# Pass through #line directives, in case user enables -g option above:
+PROCESS_AD_FILES = awk '{ \
+    if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \
+    if (need_lineno && $$0 !~ /\/\//) \
+      { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \
+    print }'
 
 $(OUTDIR)/%.o: %.cpp
 	@echo Compiling $<
--- a/hotspot/src/share/vm/adlc/adlparse.cpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/adlparse.cpp	Tue Dec 09 12:41:26 2008 -0800
@@ -108,6 +108,7 @@
     else if (!strcmp(ident, "pipeline"))   pipe_parse();
     else if (!strcmp(ident, "definitions")) definitions_parse();
     else if (!strcmp(ident, "peephole"))   peep_parse();
+    else if (!strcmp(ident, "#line"))      preproc_line();
     else if (!strcmp(ident, "#define"))    preproc_define();
     else if (!strcmp(ident, "#undef"))     preproc_undef();
     else {
@@ -786,9 +787,11 @@
         parse_err(SYNERR, "missing identifier inside register block.\n");
         return;
       }
-      if (strcmp(token,"reg_def")==0)     { reg_def_parse(); }
-      if (strcmp(token,"reg_class")==0)   { reg_class_parse(); }
-      if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); }
+      if (strcmp(token,"reg_def")==0)          { reg_def_parse(); }
+      else if (strcmp(token,"reg_class")==0)   { reg_class_parse(); }
+      else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); }
+      else if (strcmp(token,"#define")==0)     { preproc_define(); }
+      else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; }
       skipws();
     }
   }
@@ -903,11 +906,7 @@
   skipws_no_preproc();              // Skip leading whitespace
   // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
   if (_AD._adlocation_debug) {
-    const char* file     = _AD._ADL_file._name;
-    int         line     = linenum();
-    char*       location = (char *)malloc(strlen(file) + 100);
-    sprintf(location, "#line %d \"%s\"\n", line, file);
-    encoding->add_code(location);
+    encoding->add_code(get_line_string());
   }
 
   // Collect the parts of the encode description
@@ -948,6 +947,10 @@
 
   skipws();
 
+  if (_AD._adlocation_debug) {
+    encoding->add_code(end_line_marker());
+  }
+
   // Debug Stuff
   if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name);
 }
@@ -2349,7 +2352,11 @@
         return;
       }
       RegDef *regDef = _AD._register->getRegDef(rname);
-      reg_class->addReg(regDef);     // add regDef to regClass
+      if (!regDef) {
+        parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname);
+      } else {
+        reg_class->addReg(regDef); // add regDef to regClass
+      }
 
       // Check for ',' and position to next token.
       skipws();
@@ -2746,7 +2753,8 @@
   char      *rule = NULL;         // String representation of predicate
 
   skipws();                       // Skip leading whitespace
-  if ( (rule = get_paren_expr("pred expression")) == NULL ) {
+  int line = linenum();
+  if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {
     parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");
     return NULL;
   }
@@ -3407,7 +3415,12 @@
         // Check if there is a string to pass through to output
         char *start = _ptr;       // Record start of the next string
         while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
-          if (_curchar == '\\')  next_char();  // superquote
+          if (_curchar == '\\') {
+            next_char();  // superquote
+            if ((_curchar == '$') || (_curchar == '%'))
+              // hack to avoid % escapes and warnings about undefined \ escapes
+              *(_ptr-1) = _curchar;
+          }
           if (_curchar == '\n')  parse_err(SYNERR, "newline in string");  // unimplemented!
           next_char();
         }
@@ -3942,8 +3955,7 @@
     next_char();                  // Skip block delimiter
     skipws_no_preproc();          // Skip leading whitespace
     cppBlock = _ptr;              // Point to start of expression
-    const char* file = _AD._ADL_file._name;
-    int         line = linenum();
+    int line = linenum();
     next = _ptr + 1;
     while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) {
       next_char_or_line();
@@ -3958,15 +3970,16 @@
     _curchar = *_ptr;             // Maintain invariant
 
     // Prepend location descriptor, for debugging.
-    char* location = (char *)malloc(strlen(file) + 100);
-    *location = '\0';
-    if (_AD._adlocation_debug)
-      sprintf(location, "#line %d \"%s\"\n", line, file);
-    char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + 1);
-    strcpy(result, location);
-    strcat(result, cppBlock);
-    cppBlock = result;
-    free(location);
+    if (_AD._adlocation_debug) {
+      char* location = get_line_string(line);
+      char* end_loc  = end_line_marker();
+      char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1);
+      strcpy(result, location);
+      strcat(result, cppBlock);
+      strcat(result, end_loc);
+      cppBlock = result;
+      free(location);
+    }
   }
 
   return cppBlock;
@@ -4036,13 +4049,26 @@
 
 // Helper function around get_expr
 // Sets _curchar to '(' so that get_paren_expr will search for a matching ')'
-char *ADLParser::get_paren_expr(const char *description) {
+char *ADLParser::get_paren_expr(const char *description, bool include_location) {
+  int line = linenum();
   if (_curchar != '(')            // Escape if not valid starting position
     return NULL;
   next_char();                    // Skip the required initial paren.
   char *token2 = get_expr(description, ")");
   if (_curchar == ')')
     next_char();                  // Skip required final paren.
+  int junk = 0;
+  if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) {
+    // Prepend location descriptor, for debugging.
+    char* location = get_line_string(line);
+    char* end_loc  = end_line_marker();
+    char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1);
+    strcpy(result, location);
+    strcat(result, token2);
+    strcat(result, end_loc);
+    token2 = result;
+    free(location);
+  }
   return token2;
 }
 
@@ -4082,10 +4108,16 @@
   if (do_preproc && start != NULL) {
     const char* def = _AD.get_preproc_def(start);
     if (def != NULL && strcmp(def, start)) {
-      const char* def2 = _AD.get_preproc_def(def);
-      if (def2 != NULL && strcmp(def2, def)) {
-        parse_err(SYNERR, "unimplemented: using %s defined as %s => %s",
-                  start, def, def2);
+      const char* def1 = def;
+      const char* def2 = _AD.get_preproc_def(def1);
+      // implement up to 2 levels of #define
+      if (def2 != NULL && strcmp(def2, def1)) {
+        def = def2;
+        const char* def3 = _AD.get_preproc_def(def2);
+        if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {
+          parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s",
+                    start, def1, def2, def3);
+        }
       }
       start = strdup(def);
     }
@@ -4431,6 +4463,35 @@
 }
 
 
+//-------------------------------preproc_line----------------------------------
+// A "#line" keyword has been seen, so parse the rest of the line.
+void ADLParser::preproc_line(void) {
+  int line = get_int();
+  skipws_no_preproc();
+  const char* file = NULL;
+  if (_curchar == '"') {
+    next_char();              // Move past the initial '"'
+    file = _ptr;
+    while (true) {
+      if (_curchar == '\n') {
+        parse_err(SYNERR, "missing '\"' at end of #line directive");
+        return;
+      }
+      if (_curchar == '"') {
+        *_ptr  = '\0';          // Terminate the string
+        next_char();
+        skipws_no_preproc();
+        break;
+      }
+      next_char();
+    }
+  }
+  ensure_end_of_line();
+  if (file != NULL)
+    _AD._ADL_file._name = file;
+  _buf.set_linenum(line);
+}
+
 //------------------------------preproc_define---------------------------------
 // A "#define" keyword has been seen, so parse the rest of the line.
 void ADLParser::preproc_define(void) {
@@ -4494,6 +4555,7 @@
 // A preprocessor directive has been encountered.  Be sure it has fallen at
 // the begining of a line, or else report an error.
 void ADLParser::ensure_start_of_line(void) {
+  if (_curchar == '\n') { next_line(); return; }
   assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),
           "Must be able to find which line we are in" );
 
@@ -4662,6 +4724,7 @@
 
 //---------------------------next_char-----------------------------------------
 void ADLParser::next_char() {
+  if (_curchar == '\n')  parse_err(WARN, "must call next_line!");
   _curchar = *++_ptr;
   // if ( _curchar == '\n' ) {
   //   next_line();
@@ -4682,6 +4745,18 @@
 //---------------------------next_line-----------------------------------------
 void ADLParser::next_line() {
   _curline = _buf.get_line();
+  _curchar = ' ';
+}
+
+//------------------------get_line_string--------------------------------------
+// Prepended location descriptor, for debugging.
+// Must return a malloced string (that can be freed if desired).
+char* ADLParser::get_line_string(int linenum) {
+  const char* file = _AD._ADL_file._name;
+  int         line = linenum ? linenum : this->linenum();
+  char* location = (char *)malloc(strlen(file) + 100);
+  sprintf(location, "\n#line %d \"%s\"\n", line, file);
+  return location;
 }
 
 //-------------------------is_literal_constant---------------------------------
@@ -4722,6 +4797,66 @@
   return true;
 }
 
+static const char* skip_expr_ws(const char* str) {
+  const char * cp = str;
+  while (cp[0]) {
+    if (cp[0] <= ' ') {
+      ++cp;
+    } else if (cp[0] == '#') {
+      ++cp;
+      while (cp[0] == ' ')  ++cp;
+      assert(0 == strncmp(cp, "line", 4), "must be a #line directive");
+      const char* eol = strchr(cp, '\n');
+      assert(eol != NULL, "must find end of line");
+      if (eol == NULL)  eol = cp + strlen(cp);
+      cp = eol;
+    } else {
+      break;
+    }
+  }
+  return cp;
+}
+
+//-----------------------equivalent_expressions--------------------------------
+bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {
+  if (str1 == str2)
+    return true;
+  else if (str1 == NULL || str2 == NULL)
+    return false;
+  const char* cp1 = str1;
+  const char* cp2 = str2;
+  char in_quote = '\0';
+  while (cp1[0] && cp2[0]) {
+    if (!in_quote) {
+      // skip spaces and/or cpp directives
+      const char* cp1a = skip_expr_ws(cp1);
+      const char* cp2a = skip_expr_ws(cp2);
+      if (cp1a > cp1 && cp2a > cp2) {
+        cp1 = cp1a; cp2 = cp2a;
+        continue;
+      }
+      if (cp1a > cp1 || cp2a > cp2)  break; // fail
+    }
+    // match one non-space char
+    if (cp1[0] != cp2[0])  break; // fail
+    char ch = cp1[0];
+    cp1++; cp2++;
+    // watch for quotes
+    if (in_quote && ch == '\\') {
+      if (cp1[0] != cp2[0])  break; // fail
+      if (!cp1[0])  break;
+      cp1++; cp2++;
+    }
+    if (in_quote && ch == in_quote) {
+      in_quote = '\0';
+    } else if (!in_quote && (ch == '"' || ch == '\'')) {
+      in_quote = ch;
+    }
+  }
+  return (!cp1[0] && !cp2[0]);
+}
+
+
 //-------------------------------trim------------------------------------------
 void ADLParser::trim(char* &token) {
   while (*token <= ' ')  token++;
--- a/hotspot/src/share/vm/adlc/adlparse.hpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/adlparse.hpp	Tue Dec 09 12:41:26 2008 -0800
@@ -93,6 +93,7 @@
   void pipe_parse(void);        // Parse pipeline section
   void definitions_parse(void); // Parse definitions section
   void peep_parse(void);        // Parse peephole rule definitions
+  void preproc_line(void);      // Parse a #line statement
   void preproc_define(void);    // Parse a #define statement
   void preproc_undef(void);     // Parse an #undef statement
 
@@ -226,7 +227,7 @@
   void  get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs
   // Return the contents of a parenthesized expression.
   // Requires initial '(' and consumes final ')', which is replaced by '\0'.
-  char *get_paren_expr(const char *description);
+  char *get_paren_expr(const char *description, bool include_location = false);
   // Return expression up to next stop-char, which terminator replaces.
   // Does not require initial '('.  Does not consume final stop-char.
   // Final stop-char is left in _curchar, but is also is replaced by '\0'.
@@ -234,6 +235,11 @@
   char *find_cpp_block(const char *description); // Parse a C++ code block
   // Issue parser error message & go to EOL
   void parse_err(int flag, const char *fmt, ...);
+  // Create a location marker for this file and line.
+  char *get_line_string(int linenum = 0);
+  // Return a location marker which tells the C preprocessor to
+  // forget the previous location marker.  (Requires awk postprocessing.)
+  char *end_line_marker() { return (char*)"\n#line 999999\n"; }
 
   // Return pointer to current character
   inline char  cur_char(void);
@@ -268,5 +274,6 @@
   static bool is_literal_constant(const char *hex_string);
   static bool is_hex_digit(char digit);
   static bool is_int_token(const char* token, int& intval);
+  static bool equivalent_expressions(const char* str1, const char* str2);
   static void trim(char* &token);  // trim leading & trailing spaces
 };
--- a/hotspot/src/share/vm/adlc/archDesc.cpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/archDesc.cpp	Tue Dec 09 12:41:26 2008 -0800
@@ -140,7 +140,7 @@
       if ((rch == _rchild) || (rch && _rchild && !strcmp(rch, _rchild))) {
         char * predStr = get_pred();
         char * prStr = pr?pr->_pred:NULL;
-        if ((prStr == predStr) || (prStr && predStr && !strcmp(prStr, predStr))) {
+        if (ADLParser::equivalent_expressions(prStr, predStr)) {
           return true;
         }
       }
--- a/hotspot/src/share/vm/adlc/dfa.cpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/dfa.cpp	Tue Dec 09 12:41:26 2008 -0800
@@ -458,7 +458,7 @@
 
 
 class dfa_shared_preds {
-  enum { count = 2 };
+  enum { count = 4 };
 
   static bool        _found[count];
   static const char* _type [count];
@@ -479,12 +479,15 @@
     char c  = *prev;
     switch( c ) {
     case ' ':
+    case '\n':
       return dfa_shared_preds::valid_loc(pred, prev);
     case '!':
     case '(':
     case '<':
     case '=':
       return true;
+    case '"':  // such as: #line 10 "myfile.ad"\n mypredicate
+      return true;
     case '|':
       if( prev != pred && *(prev-1) == '|' ) return true;
     case '&':
@@ -564,10 +567,14 @@
   }
 };
 // shared predicates, _var and _pred entry should be the same length
-bool         dfa_shared_preds::_found[dfa_shared_preds::count] = { false, false };
-const char*  dfa_shared_preds::_type[dfa_shared_preds::count]  = { "int", "bool" };
-const char*  dfa_shared_preds::_var [dfa_shared_preds::count]  = { "_n_get_int__", "Compile__current____select_24_bit_instr__" };
-const char*  dfa_shared_preds::_pred[dfa_shared_preds::count]  = { "n->get_int()", "Compile::current()->select_24_bit_instr()" };
+bool         dfa_shared_preds::_found[dfa_shared_preds::count]
+  = { false, false, false, false };
+const char*  dfa_shared_preds::_type[dfa_shared_preds::count]
+  = { "int", "jlong", "intptr_t", "bool" };
+const char*  dfa_shared_preds::_var [dfa_shared_preds::count]
+  = { "_n_get_int__", "_n_get_long__", "_n_get_intptr_t__", "Compile__current____select_24_bit_instr__" };
+const char*  dfa_shared_preds::_pred[dfa_shared_preds::count]
+  = { "n->get_int()", "n->get_long()", "n->get_intptr_t()", "Compile::current()->select_24_bit_instr()" };
 
 
 void ArchDesc::gen_dfa_state_body(FILE* fp, Dict &minimize, ProductionState &status, Dict &operands_chained_from, int i) {
--- a/hotspot/src/share/vm/adlc/filebuff.hpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/filebuff.hpp	Tue Dec 09 12:41:26 2008 -0800
@@ -68,6 +68,7 @@
   // and increments bufeol and filepos to point at the end of that line.
   char *get_line(void);
   int linenum() const { return _linenum; }
+  void set_linenum(int line) { _linenum = line; }
 
   // This converts a pointer into the buffer to a file offset.  It only works
   // when the pointer is valid (i.e. just obtained from getline()).
--- a/hotspot/src/share/vm/adlc/formssel.cpp	Mon Dec 08 17:15:02 2008 -0800
+++ b/hotspot/src/share/vm/adlc/formssel.cpp	Tue Dec 09 12:41:26 2008 -0800
@@ -1102,10 +1102,7 @@
   }
   if( pred1 != NULL && pred2 != NULL ) {
     // compare the predicates
-    const char *str1 = pred1->_pred;
-    const char *str2 = pred2->_pred;
-    if( (str1 == NULL && str2 == NULL)
-        || (str1 != NULL && str2 != NULL && strcmp(str1,str2) == 0) ) {
+    if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) {
       return true;
     }
   }