diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake
--- a/libc/cmake/modules/LLVMLibCHeaderRules.cmake
+++ b/libc/cmake/modules/LLVMLibCHeaderRules.cmake
@@ -118,11 +118,17 @@
     set(hdrgen_exe ${LIBC_TABLEGEN_EXE})
     set(hdrgen_deps "${LIBC_TABLEGEN_EXE};${LIBC_TABLEGEN_TARGET}")
   endif()
+  option(LIBC_GPU_OFFLOAD_HEADERS "Create offloading headers for the GPU" ON)
+  if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND LIBC_GPU_OFFLOAD_HEADERS)
+    set(offloading "--offloading")
+  else()
+    set(offloading "")
+  endif()
   add_custom_command(
     OUTPUT ${out_file}
     COMMAND ${hdrgen_exe} -o ${out_file} --header ${ADD_GEN_HDR_GEN_HDR}
             --def ${in_file} ${replacement_params} -I ${LIBC_SOURCE_DIR}
-           ${ENTRYPOINT_NAME_LIST_ARG}
+           ${ENTRYPOINT_NAME_LIST_ARG} ${offloading}
            ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td
 
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/libc/config/gpu/api.td b/libc/config/gpu/api.td
--- a/libc/config/gpu/api.td
+++ b/libc/config/gpu/api.td
@@ -12,6 +12,11 @@
     "size_t",
     "__atexithandler_t",
   ];
+
+  // The offloading wrapper headers need this type defined.
+  let ExtraDefn = [{
+    #include <llvm-libc-types/__atexithandler_t.h>
+  }];
 }
 
 def FenvAPI: PublicAPI<"fenv.h"> {
diff --git a/libc/config/public_api.td b/libc/config/public_api.td
--- a/libc/config/public_api.td
+++ b/libc/config/public_api.td
@@ -23,4 +23,5 @@
   list<string> Structs = [];
   list<string> Functions = [];
   list<string> Objects = [];
+  string ExtraDefn = "";
 }
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -500,6 +500,7 @@
     DEPENDS
       .llvm_libc_common_h
       .llvm-libc-types.rpc_opcodes_t
+      .llvm-libc-macros.gpu_macros
   )
 endif()
 
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -172,3 +172,9 @@
   HDR
     wchar-macros.h
 )
+
+add_header(
+  gpu_macros
+  HDR
+    gpu-macros.h
+)
diff --git a/libc/include/llvm-libc-macros/gpu-macros.h b/libc/include/llvm-libc-macros/gpu-macros.h
new file mode 100644
--- /dev/null
+++ b/libc/include/llvm-libc-macros/gpu-macros.h
@@ -0,0 +1,61 @@
+//===-- GPU definitions for LLVM-libc public offloading header files ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_GPU_MACROS_H
+#define LLVM_LIBC_MACROS_GPU_MACROS_H
+
+#undef __OFFLOADING
+#if defined(_OPENMP) || defined(__HIP__) || defined(__CUDA__)
+#define __OFFLOADING
+#endif
+
+#undef __BEGIN_OPENMP_DECLS
+#ifdef _OPENMP
+#define __BEGIN_OPENMP_DECLS _Pragma("omp begin declare target");
+#else
+#define __BEGIN_OPENMP_DECLS
+#endif
+
+#undef __END_OPENMP_DECLS
+#ifdef _OPENMP
+#define __END_OPENMP_DECLS _Pragma("omp end declare target");
+#else
+#define __END_OPENMP_DECLS
+#endif
+
+#undef __DEVICE
+#if defined(__HIP__) || defined(__CUDA__)
+#define __DEVICE __attribute__((device))
+#else
+#define __DEVICE
+#endif
+
+#ifdef __OFFLOADING
+#undef __NOEXCEPT
+#define __NOEXCEPT
+#endif
+
+#ifdef __cplusplus
+
+#undef __BEGIN_C_DECLS
+#define __BEGIN_C_DECLS extern "C" {
+
+#undef __END_C_DECLS
+#define __END_C_DECLS }
+
+#else
+
+#undef __BEGIN_C_DECLS
+#define __BEGIN_C_DECLS
+
+#undef __END_C_DECLS
+#define __END_C_DECLS
+
+#endif
+
+#endif // LLVM_LIBC_MACROS_GPU_MACROS_H
diff --git a/libc/utils/HdrGen/BeginCommand.h b/libc/utils/HdrGen/BeginCommand.h
--- a/libc/utils/HdrGen/BeginCommand.h
+++ b/libc/utils/HdrGen/BeginCommand.h
@@ -19,9 +19,13 @@
 namespace llvm_libc {
 
 class BeginCommand : public Command {
+  const bool Offloading;
+
 public:
   static const char Name[];
 
+  BeginCommand(bool Offloading) : Offloading(Offloading) {}
+
   void run(llvm::raw_ostream &OS, const ArgVector &Args,
            llvm::StringRef StdHeader, llvm::RecordKeeper &Records,
            const Command::ErrorReporter &Reporter) const override;
diff --git a/libc/utils/HdrGen/BeginCommand.cpp b/libc/utils/HdrGen/BeginCommand.cpp
--- a/libc/utils/HdrGen/BeginCommand.cpp
+++ b/libc/utils/HdrGen/BeginCommand.cpp
@@ -22,6 +22,17 @@
                        const Command::ErrorReporter &Reporter) const {
   if (Args.size() != 0)
     Reporter.printFatalError("%%begin command does not take any arguments.");
+
+  if (!Offloading)
+    return;
+
+  // Offloading languages must have the same headers included from both the host
+  // and device compilations. For this reason, if the user has an offloading
+  // language enabled we need to defer to the system header.
+  OS << "#include <llvm-libc-macros/gpu-macros.h>\n\n"
+     << "#ifdef __OFFLOADING\n"
+     << "#include_next <" << StdHeader << ">\n"
+     << "#else\n";
 }
 
 } // namespace llvm_libc
diff --git a/libc/utils/HdrGen/EndCommand.h b/libc/utils/HdrGen/EndCommand.h
--- a/libc/utils/HdrGen/EndCommand.h
+++ b/libc/utils/HdrGen/EndCommand.h
@@ -19,9 +19,13 @@
 namespace llvm_libc {
 
 class EndCommand : public Command {
+  const bool Offloading;
+
 public:
   static const char Name[];
 
+  EndCommand(bool Offloading) : Offloading(Offloading) {}
+
   void run(llvm::raw_ostream &OS, const ArgVector &Args,
            llvm::StringRef StdHeader, llvm::RecordKeeper &Records,
            const Command::ErrorReporter &Reporter) const override;
diff --git a/libc/utils/HdrGen/EndCommand.cpp b/libc/utils/HdrGen/EndCommand.cpp
--- a/libc/utils/HdrGen/EndCommand.cpp
+++ b/libc/utils/HdrGen/EndCommand.cpp
@@ -22,6 +22,11 @@
                      const Command::ErrorReporter &Reporter) const {
   if (Args.size() != 0)
     Reporter.printFatalError("%%end command does not take any arguments.");
+
+  if (!Offloading)
+    return;
+
+  OS << "#endif\n";
 }
 
 } // namespace llvm_libc
diff --git a/libc/utils/HdrGen/Generator.h b/libc/utils/HdrGen/Generator.h
--- a/libc/utils/HdrGen/Generator.h
+++ b/libc/utils/HdrGen/Generator.h
@@ -33,6 +33,7 @@
   llvm::StringRef HeaderDefFile;
   const std::vector<std::string> &EntrypointNameList;
   llvm::StringRef StdHeader;
+  const bool Offloading;
   std::unordered_map<std::string, std::string> &ArgMap;
 
   std::unique_ptr<Command> BeginCmd;
@@ -48,10 +49,10 @@
 
 public:
   Generator(const std::string &DefFile, const std::vector<std::string> &EN,
-            const std::string &Header,
+            const std::string &Header, const bool Offloading,
             std::unordered_map<std::string, std::string> &Map)
       : HeaderDefFile(DefFile), EntrypointNameList(EN), StdHeader(Header),
-        ArgMap(Map) {}
+        Offloading(Offloading), ArgMap(Map) {}
 
   void generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records);
 };
diff --git a/libc/utils/HdrGen/Generator.cpp b/libc/utils/HdrGen/Generator.cpp
--- a/libc/utils/HdrGen/Generator.cpp
+++ b/libc/utils/HdrGen/Generator.cpp
@@ -38,11 +38,11 @@
 Command *Generator::getCommandHandler(llvm::StringRef CommandName) {
   if (CommandName == BeginCommand::Name) {
     if (!BeginCmd)
-      BeginCmd = std::make_unique<BeginCommand>();
+      BeginCmd = std::make_unique<BeginCommand>(Offloading);
     return BeginCmd.get();
   } else if (CommandName == EndCommand::Name) {
     if (!EndCmd)
-      EndCmd = std::make_unique<EndCommand>();
+      EndCmd = std::make_unique<EndCommand>(Offloading);
     return EndCmd.get();
   } else if (CommandName == IncludeFileCommand::Name) {
     if (!IncludeFileCmd)
@@ -50,7 +50,8 @@
     return IncludeFileCmd.get();
   } else if (CommandName == PublicAPICommand::Name) {
     if (!PublicAPICmd)
-      PublicAPICmd = std::make_unique<PublicAPICommand>(EntrypointNameList);
+      PublicAPICmd =
+          std::make_unique<PublicAPICommand>(EntrypointNameList, Offloading);
     return PublicAPICmd.get();
   } else {
     return nullptr;
diff --git a/libc/utils/HdrGen/Main.cpp b/libc/utils/HdrGen/Main.cpp
--- a/libc/utils/HdrGen/Main.cpp
+++ b/libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list<std::string> ReplacementValues(
     "args", llvm::cl::desc("Command separated <argument name>=<value> pairs."),
     llvm::cl::value_desc("<name=value>[,name=value]"));
+llvm::cl::opt<bool> Offloading(
+    "offloading",
+    llvm::cl::desc("Create headers suitable for offloading languages"));
 
 void ParseArgValuePairs(std::unordered_map<std::string, std::string> &Map) {
   for (std::string &R : ReplacementValues) {
@@ -47,7 +50,8 @@
 bool HeaderGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {
   std::unordered_map<std::string, std::string> ArgMap;
   ParseArgValuePairs(ArgMap);
-  Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
+  Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, Offloading,
+              ArgMap);
   G.generate(OS, Records);
 
   return false;
diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h
--- a/libc/utils/HdrGen/PublicAPICommand.h
+++ b/libc/utils/HdrGen/PublicAPICommand.h
@@ -29,11 +29,14 @@
 private:
   const std::vector<std::string> &EntrypointNameList;
 
+  const bool Offloading;
+
 public:
   static const char Name[];
 
-  PublicAPICommand(const std::vector<std::string> &EntrypointNames)
-      : EntrypointNameList(EntrypointNames) {}
+  PublicAPICommand(const std::vector<std::string> &EntrypointNames,
+                   const bool Offloading)
+      : EntrypointNameList(EntrypointNames), Offloading(Offloading) {}
 
   void run(llvm::raw_ostream &OS, const ArgVector &Args,
            llvm::StringRef StdHeader, llvm::RecordKeeper &Records,
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -48,8 +48,11 @@
 namespace llvm_libc {
 
 void writeAPIFromIndex(APIIndexer &G,
-                       std::vector<std::string> EntrypointNameList,
-                       llvm::raw_ostream &OS) {
+                       const std::vector<std::string> &EntrypointNameList,
+                       const bool Offloading, llvm::raw_ostream &OS) {
+  if (Offloading)
+    OS << "#ifndef __OFFLOADING\n";
+
   for (auto &Pair : G.MacroDefsMap) {
     const std::string &Name = Pair.first;
     if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
@@ -87,6 +90,16 @@
   if (G.Enumerations.size() != 0)
     OS << "};\n\n";
 
+  if (Offloading) {
+    if (!G.ExtraDefn.empty()) {
+      OS << "#else\n";
+      dedentAndWrite(G.ExtraDefn, OS);
+    }
+    OS << "#endif\n\n";
+  }
+
+  if (Offloading)
+    OS << "__BEGIN_OPENMP_DECLS\n";
   OS << "__BEGIN_C_DECLS\n\n";
   for (auto &Name : EntrypointNameList) {
     if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
@@ -112,7 +125,10 @@
         OS << ", ";
     }
 
-    OS << ") __NOEXCEPT;\n\n";
+    if (Offloading)
+      OS << ") __NOEXCEPT __DEVICE;\n\n";
+    else
+      OS << ") __NOEXCEPT;\n\n";
   }
 
   // Make another pass over entrypoints to emit object declarations.
@@ -121,9 +137,14 @@
       continue;
     llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
     auto Type = ObjectSpec->getValueAsString("Type");
-    OS << "extern " << Type << " " << Name << ";\n";
+    if (Offloading)
+      OS << "extern " << Type << " " << Name << " __DEVICE;\n";
+    else
+      OS << "extern " << Type << " " << Name << ";\n";
   }
   OS << "__END_C_DECLS\n";
+  if (Offloading)
+    OS << "__END_OPENMP_DECLS\n";
 }
 
 void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
@@ -139,7 +160,7 @@
   }
 
   APIIndexer G(StdHeader, Records);
-  writeAPIFromIndex(G, EntrypointNameList, OS);
+  writeAPIFromIndex(G, EntrypointNameList, Offloading, OS);
 }
 
 } // namespace llvm_libc
diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h
--- a/libc/utils/LibcTableGenUtil/APIIndexer.h
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.h
@@ -75,6 +75,7 @@
   NameSet Functions;
   NameSet Objects;
   NameSet PublicHeaders;
+  llvm::StringRef ExtraDefn;
 
   std::string getTypeAsString(llvm::Record *TypeRecord);
 };
diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
--- a/libc/utils/LibcTableGenUtil/APIIndexer.cpp
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
@@ -146,6 +146,8 @@
   auto ObjectList = PublicAPI->getValueAsListOfStrings("Objects");
   for (llvm::StringRef ObjectName : ObjectList)
     Objects.insert(std::string(ObjectName));
+
+  ExtraDefn = PublicAPI->getValueAsString("ExtraDefn");
 }
 
 void APIIndexer::index(llvm::RecordKeeper &Records) {