Patch: gcj optimizations

Tom Tromey tromey@redhat.com
Tue Nov 20 16:21:00 GMT 2001


This patch changes gcj so that it recognizes certain library calls and
instead changes them into inline code.

Right now the patch only does this for Math.min, Math.max, and
Math.abs, but I think we're free to do it for any static or final
method whose semantics are fixed by the spec.

I initially wrote this with the intent of handling System.arraycopy,
but ran aground before doing so.  I can remove these pieces of the
code if you like.  For arraycopy, I've noticed that nearly half of all
calls in the library use `0' for both offset arguments.  In cases like
this we can eliminate some of the checking; my guess is if we inline
too many checks it will outweigh the benefits.

We could also inline things like Math.sin, Math.cos, etc.  Doing that
would require figuring out how to connect gcj to the builtin function
infrastructure in gcc.  This might be tricky; for instance I think
we'd want to fall back on calling `java.lang.Math.cos' instead of
calling plain `cos' if the builtin is disabled.  (arraycopy suffers
from this problem too, since we need __builtin_memcpy.)

Another set of methods worth dealing with, maybe, are the Arrays.fill
family.

Perhaps there are more; I haven't done a real survey.

I rebuilt libgcj with this patch.  I re-ran the test suite with no
regressions.  Is this ok to check in?

Tom

Index: gcc/java/ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* parse.y (patch_invoke): Use build_call_or_builtin.
	* java-tree.h (java_tree_index) [JTI_JAVA_LANG_MATH_TYPE_NODE,
	JTI_JAVA_LANG_SYSTEM_TYPE_NODE, JTI_MIN_IDENTIFIER_NODE,
	JTI_MAX_IDENTIFIER_NODE, JTI_ABS_IDENTIFIER_NODE,
	JTI_ARRAYCOPY_IDENTIFIER_NODE]: New values.
	(java_lang_Math_type_node): New define.
	(java_lang_System_type_node): Likewise.
	(min_identifier_node): Likewise.
	(max_identifier_node): Likewise.
	(abs_identifier_node): Likewise.
	(arraycopy_identifier_node): Likewise.
	(PREDEF_FILENAMES_SIZE): Updated.
	(build_call_or_builtin): Declare.
	* expr.c (build_call_or_builtin): New function.
	(expand_invoke): Use it.
	* decl.c (java_init_decl_processing): Initialize
	java_lang_Math_type_node, java_lang_System_type_node,
	min_identifier_node, max_identifier_node,
	arraycopy_identifier_node.

Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.110
diff -u -r1.110 decl.c
--- gcc/java/decl.c 2001/11/15 10:01:06 1.110
+++ gcc/java/decl.c 2001/11/30 15:11:11
@@ -550,9 +550,12 @@
     lookup_class (get_identifier ("java.lang.ClassNotFoundException"));
   no_class_def_found_type_node = 
     lookup_class (get_identifier ("java.lang.NoClassDefFoundError"));
-
   rawdata_ptr_type_node
     = promote_type (lookup_class (get_identifier ("gnu.gcj.RawData")));
+  java_lang_Math_type_node =
+    lookup_class (get_identifier ("java.lang.Math"));
+  java_lang_System_type_node =
+    lookup_class (get_identifier ("java.lang.System"));
 
   /* If you add to this section, don't forget to increase
      PREDEF_FILENAMES_SIZE.  */
@@ -568,6 +571,9 @@
     get_identifier ("java/lang/ClassNotFoundException.java");
   predef_filenames [9] =
     get_identifier ("java/lang/NoClassDefFoundError.java");
+  predef_filenames [10] = get_identifier ("gnu/gcj/RawData.java");
+  predef_filenames [11] = get_identifier ("java/lang/Math.java");
+  predef_filenames [12] = get_identifier ("java/lang/System.java");
 
   methodtable_type = make_node (RECORD_TYPE);
   layout_type (methodtable_type);
@@ -591,6 +597,11 @@
   continue_identifier_node = get_identifier ("continue");
   access0_identifier_node = get_identifier ("access$0");
   classdollar_identifier_node = get_identifier ("class$");
+
+  min_identifier_node = get_identifier ("min");
+  max_identifier_node = get_identifier ("max");
+  abs_identifier_node = get_identifier ("abs");
+  arraycopy_identifier_node = get_identifier ("arraycopy");
 
   /* for lack of a better place to put this stub call */
   init_expr_processing();
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.118
diff -u -r1.118 expr.c
--- gcc/java/expr.c 2001/10/26 01:53:55 1.118
+++ gcc/java/expr.c 2001/11/30 15:11:14
@@ -1752,8 +1752,57 @@
   return init;
 }
 
+/* Generate a method call.  If the call matches a builtin, return the
+   appropriate builtin expression instead.  */
 tree
-build_known_method_ref (method, method_type, self_type, method_signature, arg_list)
+build_call_or_builtin (method, func, method_arguments)
+     tree method, func, method_arguments;
+{
+  tree method_class = DECL_CONTEXT (method);
+  tree method_name = DECL_NAME (method);
+  tree method_return_type = TREE_TYPE (TREE_TYPE (method));
+  tree call;
+
+  if (flag_emit_class_files || ! optimize)
+    {
+      /* If we're generating bytecode, or not optimizing, just return
+         the call.  */
+    }
+  else if (method_class == java_lang_Math_type_node)
+    {
+      if (method_name == min_identifier_node)
+	return build (MIN_EXPR, method_return_type,
+		      TREE_VALUE (method_arguments),
+		      TREE_VALUE (TREE_CHAIN (method_arguments)));
+      else if (method_name == max_identifier_node)
+	return build (MAX_EXPR, method_return_type,
+		      TREE_VALUE (method_arguments),
+		      TREE_VALUE (TREE_CHAIN (method_arguments)));
+      else if (method_name == abs_identifier_node)
+	return build1 (ABS_EXPR, method_return_type,
+		       TREE_VALUE (method_arguments));
+      /* We should recognize sin, cos, etc, and turn them into builtin
+	 calls.  */
+    }
+  else if (method_class == java_lang_System_type_node)
+    {
+      if (method_name == arraycopy_identifier_node)
+	{
+	  /* FIXME: in theory we could recognize some arraycopy calls
+	     and generate some bounds tests and then a memmove.  */
+	}
+    }
+
+  /* Nothing matched, so return the method call.  */
+  call = build (CALL_EXPR, method_return_type, func, method_arguments,
+		NULL_TREE);
+  TREE_SIDE_EFFECTS (call) = 1;
+  return call;
+}
+
+tree
+build_known_method_ref (method, method_type, self_type,
+			method_signature, arg_list)
      tree method, method_type ATTRIBUTE_UNUSED, self_type,
           method_signature ATTRIBUTE_UNUSED, arg_list ATTRIBUTE_UNUSED;
 {
@@ -1767,13 +1816,13 @@
     {
       /* We don't know whether the method has been (statically) compiled.
 	 Compile this code to get a reference to the method's code:
-	 
+
 	 SELF_TYPE->methods[METHOD_INDEX].ncode
-	 
+
 	 This is guaranteed to work (assuming SELF_TYPE has
 	 been initialized), since if the method is not compiled yet,
 	 its ncode points to a trampoline that forces compilation. */
-      
+
       int method_index = 0;
       tree meth;
       tree ref = build_class_ref (self_type);
@@ -2024,8 +2073,8 @@
 	func = build_invokeinterface (dtable, method);
     }
   func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
-  call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
-  TREE_SIDE_EFFECTS (call) = 1;
+
+  call = build_call_or_builtin (method, func, arg_list);
 
   if (check != NULL_TREE)
     {
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.125
diff -u -r1.125 java-tree.h
--- gcc/java/java-tree.h 2001/11/15 10:01:08 1.125
+++ gcc/java/java-tree.h 2001/11/30 15:11:15
@@ -260,6 +260,8 @@
   JTI_RAWDATA_PTR_TYPE_NODE,
   JTI_CLASS_NOT_FOUND_TYPE_NODE,
   JTI_NO_CLASS_DEF_FOUND_TYPE_NODE,
+  JTI_JAVA_LANG_MATH_TYPE_NODE,
+  JTI_JAVA_LANG_SYSTEM_TYPE_NODE,
 
   JTI_BYTE_ARRAY_TYPE_NODE,
   JTI_SHORT_ARRAY_TYPE_NODE,
@@ -293,6 +295,10 @@
   JTI_CONTINUE_IDENTIFIER_NODE,  
   JTI_ACCESS0_IDENTIFIER_NODE, 
   JTI_CLASSDOLLAR_IDENTIFIER_NODE,
+  JTI_MIN_IDENTIFIER_NODE,
+  JTI_MAX_IDENTIFIER_NODE,
+  JTI_ABS_IDENTIFIER_NODE,
+  JTI_ARRAYCOPY_IDENTIFIER_NODE,
   JTI_ONE_ELT_ARRAY_DOMAIN_TYPE,
 
   JTI_RETURN_ADDRESS_TYPE_NODE,
@@ -427,6 +433,10 @@
   java_global_trees[JTI_CLASS_NOT_FOUND_TYPE_NODE]
 #define no_class_def_found_type_node \
   java_global_trees[JTI_NO_CLASS_DEF_FOUND_TYPE_NODE]
+#define java_lang_Math_type_node \
+  java_global_trees[JTI_JAVA_LANG_MATH_TYPE_NODE]
+#define java_lang_System_type_node \
+  java_global_trees[JTI_JAVA_LANG_SYSTEM_TYPE_NODE]
 
 #define byte_array_type_node \
   java_global_trees[JTI_BYTE_ARRAY_TYPE_NODE]
@@ -492,6 +502,14 @@
   java_global_trees[JTI_ACCESS0_IDENTIFIER_NODE] /* "access$0" */
 #define classdollar_identifier_node \
   java_global_trees[JTI_CLASSDOLLAR_IDENTIFIER_NODE] /* "class$" */
+#define min_identifier_node \
+  java_global_trees[JTI_MIN_IDENTIFIER_NODE] /* "min" */
+#define max_identifier_node \
+  java_global_trees[JTI_MAX_IDENTIFIER_NODE] /* "max" */
+#define abs_identifier_node \
+  java_global_trees[JTI_ABS_IDENTIFIER_NODE] /* "abs" */
+#define arraycopy_identifier_node \
+  java_global_trees[JTI_ARRAYCOPY_IDENTIFIER_NODE] /* "arraycopy" */
 #define one_elt_array_domain_type \
   java_global_trees[JTI_ONE_ELT_ARRAY_DOMAIN_TYPE]
 /* The type of the return address of a subroutine. */
@@ -613,7 +631,7 @@
 #define nativecode_ptr_array_type_node \
   java_global_trees[JTI_NATIVECODE_PTR_ARRAY_TYPE_NODE]
 
-#define PREDEF_FILENAMES_SIZE 10
+#define PREDEF_FILENAMES_SIZE 13
 extern tree predef_filenames[PREDEF_FILENAMES_SIZE];
 
 #define nativecode_ptr_type_node ptr_type_node
@@ -1054,6 +1072,7 @@
 extern void load_class PARAMS ((tree, int));
 
 extern tree lookup_name PARAMS ((tree));
+extern tree build_call_or_builtin PARAMS ((tree, tree, tree));
 extern tree build_known_method_ref PARAMS ((tree, tree, tree, tree, tree));
 extern tree build_class_init PARAMS ((tree, tree));
 extern tree build_invokevirtual PARAMS ((tree, tree));
Index: gcc/java/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.326
diff -u -r1.326 parse.y
--- gcc/java/parse.y 2001/11/08 15:38:10 1.326
+++ gcc/java/parse.y 2001/11/30 15:11:28
@@ -10610,6 +10610,7 @@
   tree dtable, func;
   tree original_call, t, ta;
   tree check = NULL_TREE;
+  tree new_call;
 
   /* Last step for args: convert build-in types. If we're dealing with
      a new TYPE() type call, the first argument to the constructor
@@ -10633,7 +10634,6 @@
     func = method;
   else
     {
-      tree signature = build_java_signature (TREE_TYPE (method));
       switch (invocation_mode (method, CALL_USING_SUPER (patch)))
 	{
 	case INVOKE_VIRTUAL:
@@ -10658,9 +10658,12 @@
 
 	case INVOKE_SUPER:
 	case INVOKE_STATIC:
-	  func = build_known_method_ref (method, TREE_TYPE (method),
-					 DECL_CONTEXT (method),
-					 signature, args);
+	  {
+	    tree signature = build_java_signature (TREE_TYPE (method));
+	    func = build_known_method_ref (method, TREE_TYPE (method),
+					   DECL_CONTEXT (method),
+					   signature, args);
+	  }
 	  break;
 
 	case INVOKE_INTERFACE:
@@ -10676,9 +10679,18 @@
       func = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (method)), func);
     }
 
-  TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method));
-  TREE_OPERAND (patch, 0) = func;
-  TREE_OPERAND (patch, 1) = args;
+  if (TREE_CODE (patch) == CALL_EXPR
+      /* This next condition is always true; it just lets us write
+	 this `if' in a more natural way.  */
+      && (new_call = build_call_or_builtin (method, func, args)) != NULL_TREE
+      && TREE_CODE (new_call) != CALL_EXPR)
+    patch = new_call;
+  else
+    {
+      TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method));
+      TREE_OPERAND (patch, 0) = func;
+      TREE_OPERAND (patch, 1) = args;
+    }
   original_call = patch;
 
   /* We're processing a `new TYPE ()' form. New is called and its



More information about the Gcc-patches mailing list