This is the mail archive of the java-discuss@sourceware.cygnus.com mailing list for the Java project.


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

[PATCH] Java: expand divide, expand conversions


This is a patch for some problems we've been having for a while.

Firstly, we don't check division by zero, and instead rely on the
run-time environment to trap when division by zero occurs.  To fix
this, I've added a new compiler option, -fuse-divide-subroutine, which
instead of generating divide insns calls a subroutine in libgcj.  This
option is not intended to be passed by the user, but in the
libgcj.spec file which is created when libgcj is installed.

An unfortunate side effect of this is that the libgcj.spec file is now
required at compile time as well as at link time.  I don't know if
this will be a problem for anyone.

Secondly, conversions from floating-point to integer were broken: they
didn't conform to the Java Language Spec.  In order to solve this and
a number of other related problems, I've added a new flag:
"-fexact-fp".  The intention is that whan this flag is enabled, gcj
will conform in every way to the Java floating-point rules, no matter
how apparently trivial.  This will result in code bloat and slow
execution.  I don't think that this is related to the "-ffast-fp"
option, so I've create this new compile-time flag.  Needless to say,
"-fexact-fp" should be turned on when testing floating-point
conformance: it is off by default.

I have not yet appplied this patch.  Comments welcome.

Andrew.


1999-07-15  Andrew Haley  <aph@cygnus.com>

        * lang-options.h: Add -fexact-fp.
        * lang.c (flag_exact_fp, flag_use_divide_subroutine): New
        variables.
        * typeck.c: (convert_ieee_real_to_integer): Bounds check
        fp-to-integer conversion.
        (convert): Call convert_ieee_real_to_integer when flag_exact_fp is
        set.

        * expr.c (build_java_soft_divmod): New function.
        (build_java_binop): Call build_java_soft_divmod if
        flag_use_divide_subroutine is set.
        * decl.c: soft_idiv_node, soft_irem_node, soft_ldiv_node, tree
        soft_lrem_node: new builtin functions.
        (init_decl_processing) Initialize the new builtins.
        * java-tree.h soft_idiv_node, soft_irem_node, soft_ldiv_node, tree
        soft_lrem_node: new builtin functions.
        (build_java_soft_divmod): New function.
        * parse.y: Call build_java_soft_divmod if
        flag_use_divide_subroutine is set.


Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/decl.c,v
retrieving revision 1.31
diff -p -2 -c -r1.31 decl.c
*** decl.c	1999/05/19 11:30:11	1.31
--- decl.c	1999/07/19 16:35:52
*************** tree soft_lookupinterfacemethod_node;
*** 366,370 ****
--- 366,375 ----
  tree soft_fmod_node;
  tree soft_exceptioninfo_call_node;
+ tree soft_idiv_node;
+ tree soft_irem_node;
+ tree soft_ldiv_node;
+ tree soft_lrem_node;
  
+ 
  /* Build (and pushdecl) a "promoted type" for all standard
     types shorter than int.  */
*************** init_decl_processing ()
*** 813,816 ****
--- 818,841 ----
  #endif
      
+   soft_idiv_node
+     = builtin_function ("_Jv_divI",
+ 			build_function_type (int_type_node, t),
+ 			NOT_BUILT_IN, NULL_PTR);
+ 
+   soft_irem_node
+     = builtin_function ("_Jv_remI",
+ 			build_function_type (int_type_node, t),
+ 			NOT_BUILT_IN, NULL_PTR);
+ 
+   soft_ldiv_node
+     = builtin_function ("_Jv_divJ",
+ 			build_function_type (long_type_node, t),
+ 			NOT_BUILT_IN, NULL_PTR);
+ 
+   soft_lrem_node
+     = builtin_function ("_Jv_remJ",
+ 			build_function_type (long_type_node, t),
+ 			NOT_BUILT_IN, NULL_PTR);
+ 
    init_class_processing ();
  }
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/expr.c,v
retrieving revision 1.40
diff -p -2 -c -r1.40 expr.c
*** expr.c	1999/07/15 05:17:08	1.40
--- expr.c	1999/07/19 16:35:53
*************** expand_iinc (local_var_index, ival, pc)
*** 1053,1057 ****
--- 1053,1104 ----
  }
  
+       
  tree
+ build_java_soft_divmod (op, type, op1, op2)
+     enum tree_code op;
+     tree type, op1, op2;
+ {
+   tree call = NULL;
+   tree arg1 = convert (type, op1);
+   tree arg2 = convert (type, op2);
+ 
+   if (type == int_type_node)
+     {	  
+       switch (op)
+ 	{
+ 	case TRUNC_DIV_EXPR:
+ 	  call = soft_idiv_node;
+ 	  break;
+ 	case TRUNC_MOD_EXPR:
+ 	  call = soft_irem_node;
+ 	  break;
+ 	}
+     }
+   else if (type == long_type_node)
+     {	  
+       switch (op)
+ 	{
+ 	case TRUNC_DIV_EXPR:
+ 	  call = soft_ldiv_node;
+ 	  break;
+ 	case TRUNC_MOD_EXPR:
+ 	  call = soft_lrem_node;
+ 	  break;
+ 	}
+     }
+ 
+   if (! call)
+     fatal ("Internal compiler error in build_java_soft_divmod");
+ 		  
+   call = build (CALL_EXPR, type,
+ 		build_address_of (call),
+ 		tree_cons (NULL_TREE, arg1,
+ 			   build_tree_list (NULL_TREE, arg2)),
+ 		NULL_TREE);
+ 	  
+   return call;
+ }
+ 
+ tree
  build_java_binop (op, type, arg1, arg2)
       enum tree_code op;
*************** build_java_binop (op, type, arg1, arg2)
*** 1101,1108 ****
  	return fold (build (COND_EXPR, int_type_node,
  			    ifexp1, integer_negative_one_node, second_compare));
!       }
! 
      case TRUNC_MOD_EXPR:
!       if (TREE_CODE (type) == REAL_TYPE)
  	{
  	  tree call;
--- 1148,1156 ----
  	return fold (build (COND_EXPR, int_type_node,
  			    ifexp1, integer_negative_one_node, second_compare));
!       }      
!     case TRUNC_DIV_EXPR:
      case TRUNC_MOD_EXPR:
!       if (TREE_CODE (type) == REAL_TYPE
! 	  && op == TRUNC_MOD_EXPR)
  	{
  	  tree call;
*************** build_java_binop (op, type, arg1, arg2)
*** 1121,1124 ****
--- 1169,1178 ----
  	  return call;
  	}
+       
+       if (TREE_CODE (type) == INTEGER_TYPE
+ 	  && flag_use_divide_subroutine
+ 	  && ! flag_syntax_only)
+ 	return build_java_soft_divmod (op, type, arg1, arg2);
+       
        break;
      default:  ;
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/java-tree.h,v
retrieving revision 1.40
diff -p -2 -c -r1.40 java-tree.h
*** java-tree.h	1999/05/13 14:33:28	1.40
--- java-tree.h	1999/07/19 16:35:53
*************** extern int flag_not_overriding;
*** 142,145 ****
--- 142,151 ----
  extern int flag_static_local_jdk1_1;
  
+ /* When non zero, follow all Java floating-point/IEEE conversion rules. */
+ extern int flag_exact_fp;
+ 
+ /* When non zero, call a library routine to do integer divisions. */
+ extern int flag_use_divide_subroutine;
+ 
  /* The Java .class file that provides main_class;  the main input file. */
  extern struct JCF *current_jcf;
*************** extern tree soft_lookupinterfacemethod_n
*** 284,287 ****
--- 290,297 ----
  extern tree soft_fmod_node;
  extern tree soft_exceptioninfo_call_node;
+ extern tree soft_idiv_node;
+ extern tree soft_irem_node;
+ extern tree soft_ldiv_node;
+ extern tree soft_lrem_node;
  
  extern tree access_flags_type_node;
*************** extern tree build_field_ref PROTO ((tree
*** 545,548 ****
--- 555,559 ----
  extern void pushdecl_force_head PROTO ((tree));
  extern tree build_java_binop PROTO ((enum tree_code, tree, tree, tree));
+ extern tree build_java_soft_divmod PROTO ((enum tree_code, tree, tree, tree));
  extern tree binary_numeric_promotion PROTO ((tree, tree, tree *, tree *));
  extern tree build_java_arrayaccess PROTO ((tree, tree, tree));
Index: gcc/java/jvspec.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/jvspec.c,v
retrieving revision 1.19
diff -p -2 -c -r1.19 jvspec.c
*** jvspec.c	1999/06/28 11:34:35	1.19
--- jvspec.c	1999/07/19 16:35:53
*************** lang_specific_driver (fn, in_argc, in_ar
*** 377,382 ****
    if (saw_g + saw_O == 0)
      num_args++;
!   if (will_link)
!     num_args++;
    arglist = (char **) xmalloc ((num_args + 1) * sizeof (char *));
  
--- 377,381 ----
    if (saw_g + saw_O == 0)
      num_args++;
!   num_args++;
    arglist = (char **) xmalloc ((num_args + 1) * sizeof (char *));
  
*************** lang_specific_driver (fn, in_argc, in_ar
*** 409,413 ****
  	}
  
!       if (will_link && spec_file == NULL && strncmp (argv[i], "-L", 2) == 0)
  	spec_file = find_spec_file (argv[i] + 2);
  
--- 408,412 ----
  	}
  
!       if (spec_file == NULL && strncmp (argv[i], "-L", 2) == 0)
  	spec_file = find_spec_file (argv[i] + 2);
  
*************** lang_specific_driver (fn, in_argc, in_ar
*** 454,461 ****
      arglist[j++] = "-g1";
  
!   /* Read the specs file corresponding to libgcj, but only if linking.
       If we didn't find the spec file on the -L path, then we hope it
       is somewhere in the standard install areas.  */
!   if (will_link)
      arglist[j++] = spec_file == NULL ? "-specs=libgcj.spec" : spec_file;
  
--- 453,460 ----
      arglist[j++] = "-g1";
  
!   /* Read the specs file corresponding to libgcj.
       If we didn't find the spec file on the -L path, then we hope it
       is somewhere in the standard install areas.  */
!   if (! saw_C)
      arglist[j++] = spec_file == NULL ? "-specs=libgcj.spec" : spec_file;
  
Index: gcc/java/lang-options.h
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/lang-options.h,v
retrieving revision 1.10
diff -p -2 -c -r1.10 lang-options.h
*** lang-options.h	1999/05/11 08:50:13	1.10
--- lang-options.h	1999/07/19 16:35:53
*************** DEFINE_LANG_NAME ("Java")
*** 44,48 ****
    { "-I", "Add directory to class path" },
    { "-foutput-class-dir", "Directory where class files should be written" },
    { "-Wredundant-modifiers", 
      "Warn if modifiers are specified when not necessary"},
!   { "-Wunsupported-jdk11", "Warn if `final' local variables are specified"},
--- 44,51 ----
    { "-I", "Add directory to class path" },
    { "-foutput-class-dir", "Directory where class files should be written" },
+   { "-fexact-fp", "Follow precise Java floating-point rules " },
+   { "-fuse-divide-subroutine", "" },
+   { "-fno-use-divide-subroutine", "Use built-in instructions for division" },
    { "-Wredundant-modifiers", 
      "Warn if modifiers are specified when not necessary"},
!   { "-Wunsupported-jdk11", "Warn if `final' local variables are specified"}
Index: gcc/java/lang.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/lang.c,v
retrieving revision 1.24
diff -p -2 -c -r1.24 lang.c
*** lang.c	1999/05/14 13:44:09	1.24
--- lang.c	1999/07/19 16:35:53
*************** int flag_not_overriding = 0;
*** 106,109 ****
--- 106,116 ----
  int flag_static_local_jdk1_1 = 0;
  
+ /* When non zero, precisely follow all Java floating-point/IEEE
+    conversion rules. */
+ int flag_exact_fp = 0;
+ 
+ /* When non zero, call a library routine to do integer divisions. */
+ int flag_use_divide_subroutine = 1;
+ 
  /* From gcc/flags.h, and indicates if exceptions are turned on or not.  */
  
*************** lang_f_options[] =
*** 124,127 ****
--- 131,136 ----
    {"emit-class-file", &flag_emit_class_files, 1},
    {"emit-class-files", &flag_emit_class_files, 1},
+   {"exact-fp", &flag_exact_fp, 1},
+   {"use-divide-subroutine", &flag_use_divide_subroutine, 1},
  };
  
Index: gcc/java/parse.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/parse.c,v
retrieving revision 1.87
diff -p -2 -c -r1.87 parse.c
*** parse.c	1999/07/07 13:10:59	1.87
--- parse.c	1999/07/19 16:35:57
*************** static const short yycheck[] = {     3,
*** 2213,2217 ****
  
  /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
! #line 3 "/usr/share/misc/bison.simple"
  
  /* Skeleton output parser for bison,
--- 2213,2217 ----
  
  /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
! #line 3 "/local/aph/share/bison.simple"
  
  /* Skeleton output parser for bison,
*************** static const short yycheck[] = {     3,
*** 2230,2234 ****
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
!    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  
  /* As a special exception, when this file is copied by Bison into a
--- 2230,2234 ----
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
!    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  
  /* As a special exception, when this file is copied by Bison into a
*************** int yydebug;			/*  nonzero means print p
*** 2364,2371 ****
  /* Prevent warning if -Wstrict-prototypes.  */
  #ifdef __GNUC__
- #ifndef YYPARSE_PARAM
  int yyparse (void);
  #endif
- #endif
  
  #if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
--- 2364,2369 ----
*************** __yy_memcpy (char *to, char *from, int c
*** 2408,2412 ****
  #endif
  
! #line 196 "/usr/share/misc/bison.simple"
  
  /* The user can define YYPARSE_PARAM as the name of an argument to be passed
--- 2406,2410 ----
  #endif
  
! #line 196 "/local/aph/share/bison.simple"
  
  /* The user can define YYPARSE_PARAM as the name of an argument to be passed
*************** case 495:
*** 4697,4701 ****
  }
     /* the action file gets copied in in place of this dollarsign */
! #line 498 "/usr/share/misc/bison.simple"
  
    yyvsp -= yylen;
--- 4695,4699 ----
  }
     /* the action file gets copied in in place of this dollarsign */
! #line 498 "/local/aph/share/bison.simple"
  
    yyvsp -= yylen;
*************** patch_binop (node, wfl_op1, wfl_op2)
*** 11988,11991 ****
--- 11986,11995 ----
  	TREE_SET_CODE (node, TRUNC_DIV_EXPR);
  
+       if (TREE_CODE (prom_type) == INTEGER_TYPE
+ 	  && flag_use_divide_subroutine
+ 	  && ! flag_emit_class_files
+ 	  && (code == RDIV_EXPR || code == TRUNC_MOD_EXPR))
+ 	return build_java_soft_divmod (TREE_CODE (node), prom_type, op1, op2);
+  
        /* This one is more complicated. FLOATs are processed by a
  	 function call to soft_fmod. Duplicate the value of the
Index: gcc/java/parse.y
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/parse.y,v
retrieving revision 1.94
diff -p -2 -c -r1.94 parse.y
*** parse.y	1999/07/07 13:11:03	1.94
--- parse.y	1999/07/19 16:36:00
*************** patch_binop (node, wfl_op1, wfl_op2)
*** 9401,9404 ****
--- 9401,9410 ----
  	TREE_SET_CODE (node, TRUNC_DIV_EXPR);
  
+       if (TREE_CODE (prom_type) == INTEGER_TYPE
+ 	  && flag_use_divide_subroutine
+ 	  && ! flag_emit_class_files
+ 	  && (code == RDIV_EXPR || code == TRUNC_MOD_EXPR))
+ 	return build_java_soft_divmod (TREE_CODE (node), prom_type, op1, op2);
+  
        /* This one is more complicated. FLOATs are processed by a
  	 function call to soft_fmod. Duplicate the value of the
Index: gcc/java/typeck.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/java/typeck.c,v
retrieving revision 1.16
diff -p -2 -c -r1.16 typeck.c
*** typeck.c	1999/05/13 14:33:34	1.16
--- typeck.c	1999/07/19 16:36:00
*************** set_local_type (slot, type)
*** 56,76 ****
  /* Convert an IEEE real to an integer type.  The result of such a
     conversion when the source operand is a NaN isn't defined by
!    IEEE754, but by the Java language standard: it must be zero.  This
!    conversion produces something like:
!    
!    ({ double tmp = expr; (tmp != tmp) ? 0 : (int)tmp; })
  
-    */
- 
  static tree
  convert_ieee_real_to_integer (type, expr)
       tree type, expr;
  {
    expr = save_expr (expr);
  
!   return build (COND_EXPR, type, 
! 		build (NE_EXPR, boolean_type_node, expr, expr),
! 		convert (type, integer_zero_node),
! 		convert_to_integer (type, expr));
  }  
  
--- 56,96 ----
  /* Convert an IEEE real to an integer type.  The result of such a
     conversion when the source operand is a NaN isn't defined by
!    IEEE754, but by the Java language standard: it must be zero.  Also,
!    overflows must be clipped to within range.  This conversion
!    produces something like:
! 
!       ((expr >= (float)MAX_INT)
!        ? MAX_INT 
!        : ((expr <= (float)MIN_INT)
! 	  ? MIN_INT
! 	  : ((expr != expr)
! 	     ? 0 
! 	     : (int)expr))) */
  
  static tree
  convert_ieee_real_to_integer (type, expr)
       tree type, expr;
  {
+   tree result;
    expr = save_expr (expr);
+ 
+   result = build (COND_EXPR, type,
+ 		  build (NE_EXPR, boolean_type_node, expr, expr),
+ 		  convert (type, integer_zero_node),
+ 		  convert_to_integer (type, expr));
+ 		  
+   result = build (COND_EXPR, type, 
+ 		  build (LE_EXPR, boolean_type_node, expr, 
+ 			 convert (TREE_TYPE (expr), TYPE_MIN_VALUE (type))),
+ 		  TYPE_MIN_VALUE (type),
+ 		  result);
+ 
+   result = build (COND_EXPR, type,
+ 		  build (GE_EXPR, boolean_type_node, expr, 
+ 			 convert (TREE_TYPE (expr), TYPE_MAX_VALUE (type))),	
+ 		  TYPE_MAX_VALUE (type),
+ 		  result);
  
!   return result;
  }  
  
*************** convert (type, expr)
*** 101,110 ****
    if (code == INTEGER_TYPE)
      {
!       if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
! #ifdef TARGET_SOFT_FLOAT
! 	  && !TARGET_SOFT_FLOAT
! #endif
! 	  && !flag_emit_class_files
! 	  && !flag_fast_math
  	  && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
  	return fold (convert_ieee_real_to_integer (type, expr));
--- 121,127 ----
    if (code == INTEGER_TYPE)
      {
!       if (flag_exact_fp
! 	  && ! flag_emit_class_files
! 	  && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
  	  && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
  	return fold (convert_ieee_real_to_integer (type, expr));


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