diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 050bc681c8b81ca47f2f7417761833b457620aaf..a698dba7c8b13a178a0601d4ba1d4a92360a1c88 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,8 @@
 2007-12-04  Jakub Jelinek  <jakub@redhat.com>
 
+	* omp-low.c (optimize_omp_library_calls): New function.
+	(expand_omp_parallel): Call it if optimizing.
+
 	PR middle-end/34134
 	* stmt.c (expand_stack_restore): Call expand_normal on var to get
 	rtx for it instead of assuming it will be a VAR_DECL.
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 420e7553f51b3fb89987e0e2627421a6f78699b9..5323ec2eb4df13ea1a266048a4de2ea9857cef48 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -2426,6 +2426,61 @@ remove_exit_barriers (struct omp_region *region)
     }
 }
 
+/* Optimize omp_get_thread_num () and omp_get_num_threads ()
+   calls.  These can't be declared as const functions, but
+   within one parallel body they are constant, so they can be
+   transformed there into __builtin_omp_get_{thread_num,num_threads} ()
+   which are declared const.  */
+
+static void
+optimize_omp_library_calls (void)
+{
+  basic_block bb;
+  block_stmt_iterator bsi;
+  tree thr_num_id
+    = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM]);
+  tree num_thr_id
+    = DECL_ASSEMBLER_NAME (built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS]);
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+	tree stmt = bsi_stmt (bsi);
+	tree call = get_call_expr_in (stmt);
+	tree decl;
+
+	if (call
+	    && (decl = get_callee_fndecl (call))
+	    && DECL_EXTERNAL (decl)
+	    && TREE_PUBLIC (decl)
+	    && DECL_INITIAL (decl) == NULL)
+	  {
+	    tree built_in;
+
+	    if (DECL_NAME (decl) == thr_num_id)
+	      built_in = built_in_decls [BUILT_IN_OMP_GET_THREAD_NUM];
+	    else if (DECL_NAME (decl) == num_thr_id)
+	      built_in = built_in_decls [BUILT_IN_OMP_GET_NUM_THREADS];
+	    else
+	      continue;
+
+	    if (DECL_ASSEMBLER_NAME (decl) != DECL_ASSEMBLER_NAME (built_in)
+		|| call_expr_nargs (call) != 0)
+	      continue;
+
+	    if (flag_exceptions && !TREE_NOTHROW (decl))
+	      continue;
+
+	    if (TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE
+		|| TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl)))
+		   != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (built_in))))
+	      continue;
+
+	    CALL_EXPR_FN (call) = build_fold_addr_expr (built_in);
+	  }
+      }
+}
+
 /* Expand the OpenMP parallel directive starting at REGION.  */
 
 static void
@@ -2588,6 +2643,8 @@ expand_omp_parallel (struct omp_region *region)
       /* Fix the callgraph edges for child_cfun.  Those for cfun will be
 	 fixed in a following pass.  */
       push_cfun (child_cfun);
+      if (optimize)
+	optimize_omp_library_calls ();
       rebuild_cgraph_edges ();
       pop_cfun ();
     }
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 76293bdd8ced8b7c2ce8cc67eb1210f263361b86..7d3ef12a7190894ebc07df486f0fa0ce771c3e26 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,7 @@
+2007-12-04  Jakub Jelinek  <jakub@redhat.com>
+
+	* omp.h.in (__GOMP_NOTHROW): Define.  Use it on omp_* prototypes.
+
 2007-12-03  Jakub Jelinek  <jakub@redhat.com>
 
 	* testsuite/libgomp.c/private-1.c: New test.
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index 44fda9088c33a71478fdb80c7588c15894b51443..5ebcdbb2735102ece3a4330abbbfbcf6ee3a1343 100644
--- a/libgomp/omp.h.in
+++ b/libgomp/omp.h.in
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>.
 
    This file is part of the GNU OpenMP Library (libgomp).
@@ -49,36 +49,39 @@ typedef struct
 
 #ifdef __cplusplus
 extern "C" {
+# define __GOMP_NOTHROW throw ()
+#else
+# define __GOMP_NOTHROW __attribute__((__nothrow__))
 #endif
 
-extern void omp_set_num_threads (int);
-extern int omp_get_num_threads (void);
-extern int omp_get_max_threads (void);
-extern int omp_get_thread_num (void);
-extern int omp_get_num_procs (void);
+extern void omp_set_num_threads (int) __GOMP_NOTHROW;
+extern int omp_get_num_threads (void) __GOMP_NOTHROW;
+extern int omp_get_max_threads (void) __GOMP_NOTHROW;
+extern int omp_get_thread_num (void) __GOMP_NOTHROW;
+extern int omp_get_num_procs (void) __GOMP_NOTHROW;
 
-extern int omp_in_parallel (void);
+extern int omp_in_parallel (void) __GOMP_NOTHROW;
 
-extern void omp_set_dynamic (int);
-extern int omp_get_dynamic (void);
+extern void omp_set_dynamic (int) __GOMP_NOTHROW;
+extern int omp_get_dynamic (void) __GOMP_NOTHROW;
 
-extern void omp_set_nested (int);
-extern int omp_get_nested (void);
+extern void omp_set_nested (int) __GOMP_NOTHROW;
+extern int omp_get_nested (void) __GOMP_NOTHROW;
 
-extern void omp_init_lock (omp_lock_t *);
-extern void omp_destroy_lock (omp_lock_t *);
-extern void omp_set_lock (omp_lock_t *);
-extern void omp_unset_lock (omp_lock_t *);
-extern int omp_test_lock (omp_lock_t *);
+extern void omp_init_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_destroy_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_set_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern void omp_unset_lock (omp_lock_t *) __GOMP_NOTHROW;
+extern int omp_test_lock (omp_lock_t *) __GOMP_NOTHROW;
 
-extern void omp_init_nest_lock (omp_nest_lock_t *);
-extern void omp_destroy_nest_lock (omp_nest_lock_t *);
-extern void omp_set_nest_lock (omp_nest_lock_t *);
-extern void omp_unset_nest_lock (omp_nest_lock_t *);
-extern int omp_test_nest_lock (omp_nest_lock_t *);
+extern void omp_init_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_destroy_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_set_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern void omp_unset_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
+extern int omp_test_nest_lock (omp_nest_lock_t *) __GOMP_NOTHROW;
 
-extern double omp_get_wtime (void);
-extern double omp_get_wtick (void);
+extern double omp_get_wtime (void) __GOMP_NOTHROW;
+extern double omp_get_wtick (void) __GOMP_NOTHROW;
 
 #ifdef __cplusplus
 }