diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dd962349c0f9dfbb7d9846b148e2df72ad011441..4502a2a7217715a2140650618372c0dd05dd433d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2002-03-12  Hans-Peter Nilsson  <hp@axis.com>
+
+	* config/cris/cris.c (cris_target_asm_function_prologue):  Do not
+	emit pic register load if "internal" visibility.
+	(cris_print_operand): Avoid traditional-warning for 0xffffffff.
+	(cris_expand_builtin_va_arg): Do all computations on trees.
+
 2002-03-11  Richard Henderson  <rth@redhat.com>
 
 	* rtlanal.c: Include recog.h.
diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
index 94568742f3e84b5d56519b773cf64e7314dc8176..d1c6f5b4b114bdb7e033aa90bb9ef0d6f1cd6eda 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -857,11 +857,19 @@ cris_target_asm_function_prologue (file, size)
       framesize += size + cfoa_size;
     }
 
-  /* Set up the PIC register.  */
+  /* Set up the PIC register.  Not needed for a function marked with
+     visibility "internal".  */
   if (current_function_uses_pic_offset_table)
-    asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
-		 reg_names[PIC_OFFSET_TABLE_REGNUM],
-		 reg_names[PIC_OFFSET_TABLE_REGNUM]);
+    {
+      tree vis = lookup_attribute ("visibility", DECL_ATTRIBUTES (cfun->decl));
+
+      if (!vis
+	  || strcmp ("internal",
+		     TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (vis)))))
+	asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
+		     reg_names[PIC_OFFSET_TABLE_REGNUM],
+		     reg_names[PIC_OFFSET_TABLE_REGNUM]);
+    }
 
   if (TARGET_PDEBUG)
     fprintf (file,
@@ -1452,7 +1460,8 @@ cris_print_operand (file, x, code)
 	}
       else if (HOST_BITS_PER_WIDE_INT > 32 && GET_CODE (operand) == CONST_INT)
 	{
-	  fprintf (file, "0x%x", (unsigned int)(INTVAL (x) & 0xffffffff));
+	  fprintf (file, "0x%x",
+		   INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1));
 	  return;
 	}
       /* Otherwise the least significant part equals the normal part,
@@ -2612,32 +2621,69 @@ cris_expand_builtin_va_arg (valist, type)
 {
   tree addr_tree, t;
   rtx addr;
-  enum machine_mode mode = TYPE_MODE (type);
-  int passed_size;
+  tree passed_size = size_zero_node;
+  tree type_size = NULL;
+  tree size3 = size_int (3);
+  tree size4 = size_int (4);
+  tree size8 = size_int (8);
+  tree rounded_size;
 
   /* Get AP.  */
   addr_tree = valist;
 
-  /* Check if the type is passed by value or by reference.  */
-  if (MUST_PASS_IN_STACK (mode, type)
-      || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8)
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    /* Presumable an error; the size isn't computable.  A message has
+       supposedly been emitted elsewhere.  */
+    rounded_size = size_zero_node;
+  else
+    rounded_size
+      = fold (build (MULT_EXPR, sizetype,
+		     fold (build (TRUNC_DIV_EXPR, sizetype,
+				  fold (build (PLUS_EXPR, sizetype,
+					       type_size, size3)),
+				  size4)),
+		     size4));
+
+  if (!integer_zerop (rounded_size))
     {
-      tree type_ptr = build_pointer_type (type);
-      addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
-      passed_size = 4;
+      /* Check if the type is passed by value or by reference.  This test must
+	 be different than the call-site test and be done at run-time:
+	 gcc.c-torture/execute/20020307-2.c.  Hence the tree stuff.
+
+	 Values up to 8 bytes are passed by-value, padded to register-size
+	 (4 bytes).  Larger values are passed by-reference.  */
+      passed_size
+	= fold (build (COND_EXPR, sizetype,
+		       fold (build (GT_EXPR, sizetype,
+				    rounded_size,
+				    size8)),
+		       size4,
+		       rounded_size));
+
+      addr_tree
+       = fold (build (COND_EXPR, TREE_TYPE (addr_tree),
+		      fold (build (GT_EXPR, sizetype,
+				   rounded_size,
+				   size8)),
+		      build1 (INDIRECT_REF, build_pointer_type (type),
+			      addr_tree),
+		      addr_tree));
     }
-  else
-    passed_size = (CRIS_FUNCTION_ARG_SIZE (mode, type) > 4) ? 8 : 4;
 
   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
 
-  /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-	     build (PLUS_EXPR, TREE_TYPE (valist), valist,
-		    build_int_2 (passed_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (!integer_zerop (rounded_size))
+    {
+      /* Compute new value for AP.  */
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+		 build (PLUS_EXPR, TREE_TYPE (valist), valist,
+			passed_size));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
   return addr;
 }