diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index 952588d..5187190 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -907,9 +907,15 @@ output_symtab (void)
     {
       symtab_node node = lto_symtab_encoder_deref (encoder, i);
       if (cgraph_node *cnode = dyn_cast <cgraph_node> (node))
-        lto_output_node (ob, cnode, encoder);
+	{
+	  if (!dumping_omp_target || lookup_attribute ("omp declare target",
+					  DECL_ATTRIBUTES (node->symbol.decl)))
+	    lto_output_node (ob, cnode, encoder);
+	}
       else
-        lto_output_varpool_node (ob, varpool (node), encoder);
+	  if (!dumping_omp_target || lookup_attribute ("omp declare target",
+					  DECL_ATTRIBUTES (node->symbol.decl)))
+	    lto_output_varpool_node (ob, varpool (node), encoder);
 	
     }
 
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
index 59eed71..ad247c1 100644
--- a/gcc/lto-section-out.c
+++ b/gcc/lto-section-out.c
@@ -49,6 +49,7 @@ static vec<lto_out_decl_state_ptr> decl_state_stack;
 
 vec<lto_out_decl_state_ptr> lto_function_decl_states;
 
+vec<lto_out_decl_state_ptr> omp_function_decl_states;
 
 /*****************************************************************************
    Output routines shared by all of the serialization passes.
@@ -443,5 +444,8 @@ lto_record_function_out_decl_state (tree fn_decl,
 	state->streams[i].tree_hash_table = NULL;
       }
   state->fn_decl = fn_decl;
-  lto_function_decl_states.safe_push (state);
+  if (dumping_omp_target)
+    omp_function_decl_states.safe_push (state);
+  else
+    lto_function_decl_states.safe_push (state);
 }
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 8f823f2..66a0747 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -48,6 +48,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 
 
+/* Off by default.  */
+bool dumping_omp_target = false;
+
 /* Clear the line info stored in DATA_IN.  */
 
 static void
@@ -2014,6 +2017,93 @@ lto_output (void)
 #endif
 }
 
+bool
+gate_omp_out (void)
+{
+  return flag_openmp;
+}
+
+static void
+omp_output (void)
+{
+  /* We need omp names for sections, turn this on.  */
+  dumping_omp_target = true;
+
+  lto_streamer_hooks_init();
+  struct lto_out_decl_state *decl_state;
+  int i, n_nodes;
+  lto_symtab_encoder_t encoder = lto_get_out_decl_state ()->symtab_node_encoder;
+
+  /* Initialize the streamer.  */
+  lto_streamer_init ();
+
+  n_nodes = lto_symtab_encoder_size (encoder);
+  /* Process only the functions with bodies.  */
+  for (i = 0; i < n_nodes; i++)
+    {
+      symtab_node snode = lto_symtab_encoder_deref (encoder, i);
+      cgraph_node *node = dyn_cast <cgraph_node> (snode);
+      if (node
+	  && lto_symtab_encoder_encode_body_p (encoder, node)
+	  && !node->symbol.alias
+	  && gimple_has_body_p (node->symbol.decl)
+	  && lookup_attribute ("omp declare target",
+			       DECL_ATTRIBUTES (node->symbol.decl)))
+	{
+	  decl_state = lto_new_out_decl_state ();
+	  lto_push_out_decl_state (decl_state);
+	  output_function (node);
+	  lto_pop_out_decl_state ();
+	  lto_record_function_out_decl_state (node->symbol.decl, decl_state);
+	}
+    }
+
+  /* Emit the callgraph after emitting function bodies.  This needs to
+     be done now to make sure that all the statements in every function
+     have been renumbered so that edges can be associated with call
+     statements using the statement UIDs.  */
+  output_symtab ();
+}
+
+namespace {
+
+const pass_data pass_data_ipa_omp_gimple_out =
+{
+  IPA_PASS, /* type */
+  "omp_gimple_out", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  false, /* has_execute */
+  TV_IPA_OMP_GIMPLE_OUT, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_ipa_omp_gimple_out : public ipa_opt_pass_d
+{
+public:
+  pass_ipa_omp_gimple_out(gcc::context *ctxt)
+    : ipa_opt_pass_d(pass_data_ipa_omp_gimple_out, ctxt,
+		     NULL, /* generate_summary */
+		     omp_output, /* write_summary */
+		     NULL, /* read_summary */
+		     omp_output, /* write_optimization_summary */
+		     NULL, /* read_optimization_summary */
+		     NULL, /* stmt_fixup */
+		     0, /* function_transform_todo_flags_start */
+		     NULL, /* function_transform */
+		     NULL) /* variable_transform */
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_omp_out (); }
+
+}; // class pass_ipa_omp_gimple_out
+
+} // anon namespace
 namespace {
 
 const pass_data pass_data_ipa_lto_gimple_out =
@@ -2055,6 +2145,12 @@ public:
 } // anon namespace
 
 ipa_opt_pass_d *
+make_pass_ipa_omp_gimple_out (gcc::context *ctxt)
+{
+  return new pass_ipa_omp_gimple_out (ctxt);
+}
+
+ipa_opt_pass_d *
 make_pass_ipa_lto_gimple_out (gcc::context *ctxt)
 {
   return new pass_ipa_lto_gimple_out (ctxt);
@@ -2353,7 +2449,9 @@ produce_symtab (struct output_block *ob)
     {
       symtab_node node = lsei_node (lsei);
 
-      if (!output_symbol_p (node) || DECL_EXTERNAL (node->symbol.decl))
+      if (!output_symbol_p (node) || DECL_EXTERNAL (node->symbol.decl)
+	  || (dumping_omp_target && !lookup_attribute ("omp declare target",
+					   DECL_ATTRIBUTES (node->symbol.decl))))
 	continue;
       write_symbol (cache, &stream, node->symbol.decl, seen, false);
     }
@@ -2362,7 +2460,9 @@ produce_symtab (struct output_block *ob)
     {
       symtab_node node = lsei_node (lsei);
 
-      if (!output_symbol_p (node) || !DECL_EXTERNAL (node->symbol.decl))
+      if (!output_symbol_p (node) || !DECL_EXTERNAL (node->symbol.decl)
+	  || (dumping_omp_target && !lookup_attribute ("omp declare target",
+					   DECL_ATTRIBUTES (node->symbol.decl))))
 	continue;
       write_symbol (cache, &stream, node->symbol.decl, seen, false);
     }
@@ -2393,6 +2493,11 @@ produce_asm_for_decls (void)
   size_t decl_state_size;
   int32_t num_decl_states;
 
+  vec<lto_out_decl_state_ptr> decl_states = dumping_omp_target
+    ? omp_function_decl_states
+    : lto_function_decl_states;
+
+
   ob = create_output_block (LTO_section_decls);
   ob->global = true;
 
@@ -2409,12 +2514,11 @@ produce_asm_for_decls (void)
 
   /* Write the global symbols.  */
   out_state = lto_get_out_decl_state ();
-  num_fns = lto_function_decl_states.length ();
+  num_fns = decl_states.length ();
   lto_output_decl_state_streams (ob, out_state);
   for (idx = 0; idx < num_fns; idx++)
     {
-      fn_out_state =
-	lto_function_decl_states[idx];
+      fn_out_state = decl_states[idx];
       lto_output_decl_state_streams (ob, fn_out_state);
     }
 
@@ -2430,8 +2534,7 @@ produce_asm_for_decls (void)
   decl_state_size += lto_out_decl_state_written_size (out_state);
   for (idx = 0; idx < num_fns; idx++)
     {
-      fn_out_state =
-	lto_function_decl_states[idx];
+      fn_out_state = decl_states[idx];
       decl_state_size += lto_out_decl_state_written_size (fn_out_state);
     }
   header.decl_state_size = decl_state_size;
@@ -2453,8 +2556,7 @@ produce_asm_for_decls (void)
   lto_output_decl_state_refs (ob, decl_state_stream, out_state);
   for (idx = 0; idx < num_fns; idx++)
     {
-      fn_out_state =
-	lto_function_decl_states[idx];
+      fn_out_state = decl_states[idx];
       lto_output_decl_state_refs (ob, decl_state_stream, fn_out_state);
     }
   lto_write_stream (decl_state_stream);
@@ -2471,20 +2573,29 @@ produce_asm_for_decls (void)
     produce_symtab (ob);
 
   /* Write command line opts.  */
-  lto_write_options ();
+  if (!dumping_omp_target)
+    lto_write_options ();
 
   /* Deallocate memory and clean up.  */
   for (idx = 0; idx < num_fns; idx++)
     {
-      fn_out_state =
-	lto_function_decl_states[idx];
+      fn_out_state = decl_states[idx];
       lto_delete_out_decl_state (fn_out_state);
     }
-  lto_symtab_encoder_delete (ob->decl_state->symtab_node_encoder);
+  if (!dumping_omp_target || !flag_lto)
+    lto_symtab_encoder_delete (ob->decl_state->symtab_node_encoder);
+  omp_function_decl_states.release ();
   lto_function_decl_states.release ();
   destroy_output_block (ob);
 }
 
+static void
+produce_asm_for_decls_omp ()
+{
+  produce_asm_for_decls ();
+  /* Disable after everything is done.  */
+  dumping_omp_target = false;
+}
 
 namespace {
 
@@ -2531,3 +2642,48 @@ make_pass_ipa_lto_finish_out (gcc::context *ctxt)
 {
   return new pass_ipa_lto_finish_out (ctxt);
 }
+namespace {
+
+const pass_data pass_data_ipa_omp_finish_out =
+{
+  IPA_PASS, /* type */
+  "omp_decls_out", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  false, /* has_execute */
+  TV_IPA_OMP_DECL_OUT, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_ipa_omp_finish_out : public ipa_opt_pass_d
+{
+public:
+  pass_ipa_omp_finish_out(gcc::context *ctxt)
+    : ipa_opt_pass_d(pass_data_ipa_omp_finish_out, ctxt,
+		     NULL, /* generate_summary */
+		     produce_asm_for_decls_omp, /* write_summary */
+		     NULL, /* read_summary */
+		     produce_asm_for_decls_omp, /* write_optimization_summary */
+		     NULL, /* read_optimization_summary */
+		     NULL, /* stmt_fixup */
+		     0, /* function_transform_todo_flags_start */
+		     NULL, /* function_transform */
+		     NULL) /* variable_transform */
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_omp_out (); }
+
+}; // class pass_ipa_lto_finish_out
+
+} // anon namespace
+
+ipa_opt_pass_d *
+make_pass_ipa_omp_finish_out (gcc::context *ctxt)
+{
+  return new pass_ipa_omp_finish_out (ctxt);
+}
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index cdc75de..5cc3f37 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -173,7 +173,9 @@ lto_get_section_name (int section_type, const char *name, struct lto_file_decl_d
     sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, f->id);
   else
     sprintf (post, "." HOST_WIDE_INT_PRINT_HEX_PURE, get_random_seed (false)); 
-  return concat (LTO_SECTION_NAME_PREFIX, sep, add, post, NULL);
+  return concat (dumping_omp_target ? OMP_SECTION_NAME_PREFIX
+				     : LTO_SECTION_NAME_PREFIX,
+				       sep, add, post, NULL);
 }
 
 
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 13a9593..93106b3 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -141,12 +141,17 @@ along with GCC; see the file COPYING3.  If not see
    name for the functions and static_initializers.  For other types of
    sections a '.' and the section type are appended.  */
 #define LTO_SECTION_NAME_PREFIX         ".gnu.lto_"
+#define OMP_SECTION_NAME_PREFIX         ".gnu.target_lto_"
 
 #define LTO_major_version 2
 #define LTO_minor_version 2
 
 typedef unsigned char	lto_decl_flags_t;
 
+/* When we dump gimple for omp target stuff we need to use
+   OMP_SECTION_NAME_PREFIX, for section names. We use this to
+   distinguish omp dumps by setting to true in them.  */
+extern bool dumping_omp_target;
 
 /* Tags representing the various IL objects written to the bytecode file
    (GIMPLE statements, basic blocks, EH regions, tree nodes, etc).
@@ -918,6 +923,7 @@ extern const char *lto_section_name[];
 /* Holds all the out decl states of functions output so far in the
    current output file.  */
 extern vec<lto_out_decl_state_ptr> lto_function_decl_states;
+extern vec<lto_out_decl_state_ptr> omp_function_decl_states;
 
 /* Return true if LTO tag TAG corresponds to a tree code.  */
 static inline bool
diff --git a/gcc/passes.c b/gcc/passes.c
index f3f85fd..fda68cf 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -2329,7 +2329,7 @@ ipa_write_summaries (void)
   struct cgraph_node *node;
   struct cgraph_node **order;
 
-  if (!flag_generate_lto || seen_error ())
+  if (!(flag_generate_lto || flag_openmp) || seen_error ())
     return;
 
   encoder = lto_symtab_encoder_new (false);
diff --git a/gcc/passes.def b/gcc/passes.def
index 84eb3f3..774cab8 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -102,6 +102,8 @@ along with GCC; see the file COPYING3.  If not see
   TERMINATE_PASS_LIST ()
 
   INSERT_PASSES_AFTER (all_regular_ipa_passes)
+  NEXT_PASS (pass_ipa_omp_gimple_out);
+  NEXT_PASS (pass_ipa_omp_finish_out);
   NEXT_PASS (pass_ipa_whole_program_visibility);
   NEXT_PASS (pass_ipa_profile);
   NEXT_PASS (pass_ipa_devirt);
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5a880a8..d473083 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -74,8 +74,10 @@ DEFTIMEVAR (TV_IPA_FNSPLIT           , "ipa function splitting")
 DEFTIMEVAR (TV_IPA_OPT		     , "ipa various optimizations")
 DEFTIMEVAR (TV_IPA_LTO_GIMPLE_IN     , "ipa lto gimple in")
 DEFTIMEVAR (TV_IPA_LTO_GIMPLE_OUT    , "ipa lto gimple out")
+DEFTIMEVAR (TV_IPA_OMP_GIMPLE_OUT    , "ipa omp gimple out")
 DEFTIMEVAR (TV_IPA_LTO_DECL_IN       , "ipa lto decl in")
 DEFTIMEVAR (TV_IPA_LTO_DECL_OUT      , "ipa lto decl out")
+DEFTIMEVAR (TV_IPA_OMP_DECL_OUT      , "ipa omp decl out")
 DEFTIMEVAR (TV_IPA_LTO_DECL_INIT_IO  , "ipa lto decl init I/O")
 DEFTIMEVAR (TV_IPA_LTO_CGRAPH_IO     , "ipa lto cgraph I/O")
 DEFTIMEVAR (TV_IPA_LTO_DECL_MERGE    , "ipa lto decl merge")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index ea1a62f..1fb487c 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -460,6 +460,7 @@ extern simple_ipa_opt_pass *make_pass_early_local_passes (gcc::context *ctxt);
 
 extern ipa_opt_pass_d *make_pass_ipa_whole_program_visibility (gcc::context
 							       *ctxt);
+extern ipa_opt_pass_d *make_pass_ipa_omp_gimple_out (gcc::context *ctxt);
 extern ipa_opt_pass_d *make_pass_ipa_lto_gimple_out (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_increase_alignment (gcc::context
 							      *ctxt);
@@ -473,6 +474,7 @@ extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
 extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt);
 extern ipa_opt_pass_d *make_pass_ipa_lto_finish_out (gcc::context *ctxt);
+extern ipa_opt_pass_d *make_pass_ipa_omp_finish_out (gcc::context *ctxt);
 extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
 extern ipa_opt_pass_d *make_pass_ipa_profile (gcc::context *ctxt);
 extern ipa_opt_pass_d *make_pass_ipa_cdtor_merge (gcc::context *ctxt);
