[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Joseph Huber via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa4a26374aa11: [libc] Add support for creating wrapper 
headers for offloading in clang (authored by jhuber6).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/inttypes.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+auto Type = ObjectSpec->getValueAsString("Type");
+OS << "extern " << Type << " " << Name << " __LIBC_ATTRS;\n";
+  }
+
+  // 

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 537787.
jhuber6 added a comment.

Changing this to only apply to OpenMP for now. It breaks CUDA / HIP builds
because they already have forward declarations of things like `malloc` or
`memcpy` on the GPU that conflict. We'll need to clean those up later.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/inttypes.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+auto Type = ObjectSpec->getValueAsString("Type");
+OS << "extern " << Type << " " << Name << " 

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Johannes Doerfert via Phabricator via cfe-commits
jdoerfert accepted this revision.
jdoerfert added a comment.

If it compiles, ship it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Jon Chesterfield via Phabricator via cfe-commits
JonChesterfield accepted this revision.
JonChesterfield added a comment.
This revision is now accepted and ready to land.

OK, let's go with this. It's a fairly alarming mess localised quite closely to 
the language that requires the complexity, minimal damage to libc itself.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added inline comments.



Comment at: libc/include/CMakeLists.txt:8
+if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
+  include(GetClangResourceDir)
+endif()

sivachandra wrote:
> Where does this come from?
It's a global CMake module that LLVM provides in 
`cmake/Modules/GetClangResourceDir.cmake`. I only expect the GPU build to be 
done in-tree.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-06 Thread Siva Chandra via Phabricator via cfe-commits
sivachandra added a comment.

The libc specific changes are really minimal straightforward. The GPU side, the 
clang driver changes etc. need a review by a GPU expert.




Comment at: libc/include/CMakeLists.txt:8
+if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
+  include(GetClangResourceDir)
+endif()

Where does this come from?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-07-05 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 537535.
jhuber6 added a comment.

Fix guard on the headers for offloading languages


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+auto Type = ObjectSpec->getValueAsString("Type");
+OS << "extern " << Type << " " << Name << " __LIBC_ATTRS;\n";
+  }
+
+  // Emit a final newline if we emitted any object declarations.
+  if (llvm::any_of(EntrypointNameList, [&](const std::string ) {
+return G.ObjectSpecMap.find(Name) != 

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-06-29 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 535983.
jhuber6 added a comment.

Add some checks to `stdlib.h` to ensure ABI compatibility for `div` functions.

Because this patch makes us always include the LLVM libc repo when offloading,
we mask off the wrappers if they were not installed by `libc`, so this is simply
a passthrough include header if the user didn't build with LLVM C library for
the GPU.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+auto Type = 

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-06-29 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 535835.
jhuber6 added a comment.

Semi-fix hack for `string.h` and fix `ctype.h`. `string.h` required undefining
C++ mode so we didn't use weird GNU C++ handling, which we then still need the
`extern "C"` for. The cytpe problems come from GNU defining everything as a
macro so it fails to redeclare.

The amount of hacks that just this has required so far is fairly convincing to
me that this is the more correct solution and should be separate from `libc`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-06-28 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 updated this revision to Diff 535600.
jhuber6 added a comment.

Hack around the `string` problem. GNU likes to provide different prototypes for 
C++. Manually disable this for now. Unsure if this will have reasonable 
fallout, but it seems bizarre that `string.h` would define C++ constructs?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+for (size_t i = 0; i < ArgsList.size(); ++i) {
+  llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+  OS << G.getTypeAsString(ArgType);
+  if (i < ArgsList.size() - 1)
+OS << ", ";
+}
+
+OS << ") __LIBC_ATTRS;\n\n";
+  }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto  : EntrypointNameList) {
+if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+  continue;
+llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+auto Type = ObjectSpec->getValueAsString("Type");
+OS << "extern " << Type << " " << Name << " __LIBC_ATTRS;\n";
+  }
+
+  // Emit a 

[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-06-28 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 added a comment.

For reference, here is what one of the newly generated headers looks like that 
is used.

  #ifndef __LLVM_LIBC_DECLARATIONS_STDIO_H
  #define __LLVM_LIBC_DECLARATIONS_STDIO_H
  
  #ifndef __LIBC_ATTRS
  #define __LIBC_ATTRS
  #endif
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  int puts(const char *__restrict) __LIBC_ATTRS;
  
  int fputs(const char *__restrict, FILE *__restrict) __LIBC_ATTRS;
  
  extern FILE * stdin __LIBC_ATTRS;
  extern FILE * stdout __LIBC_ATTRS;
  extern FILE * stderr __LIBC_ATTRS;
  
  #ifdef __cplusplus
  }
  #endif

Unfortunately I have already run into a few problems with the re-declarations 
given the GNU `libc` headers. Here is the error message when including 
`string.h` now,

  
/home/jhuber/Documents/llvm/clang/lib/clang/17/include/llvm_libc_wrappers/llvm-libc-decls/string.h:54:8:
 error: 'strstr' is missing exception specification 'noexcept(true)'
 54 | char * strstr(const char *, const char *) __LIBC_ATTRS;
|^
  /usr/include/string.h:343:1: note: previous declaration is here
343 | strstr (const char *__haystack, const char *__needle) __THROW
| ^
  5 errors generated.

This occurs for `memchr`, `strchr`, `strpbrk`, `strchr`, and `strstr`. If you 
define `__LIBC_ATTRS` to the `noexcept(true)` you get a different error,

  
/home/jhuber/Documents/llvm/clang/lib/clang/17/include/llvm_libc_wrappers/llvm-libc-decls/string.h:54:8:
 error: functions that differ only in their return type cannot be overloaded
 54 | char * strstr(const char *, const char *) __LIBC_ATTRS;
| ~~ ^
  /usr/include/string.h:343:1: note: previous definition is here
343 | __extern_always_inline const char *
|  ~~
344 | strstr (const char *__haystack, const char *__needle) __THROW
| ^

Looking at the definitions, they look like this in the GNU headers,

  extern char *strstr (char *__haystack, const char *__needle)
   __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2));
  extern const char *strstr (const char *__haystack, const char *__needle)
   __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2));

Does anyone have any suggestions on working around this? The other supported 
headers work as far as I can tell.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154036/new/

https://reviews.llvm.org/D154036

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154036: [libc] Add support for creating wrapper headers for offloading in clang

2023-06-28 Thread Joseph Huber via Phabricator via cfe-commits
jhuber6 created this revision.
jhuber6 added reviewers: jdoerfert, tianshilei1992, sivachandra, lntue, 
michaelrj, tra, JonChesterfield.
Herald added projects: libc-project, All.
Herald added a subscriber: libc-commits.
jhuber6 requested review of this revision.
Herald added subscribers: cfe-commits, jplehr, sstefan1, MaskRay.
Herald added a project: clang.

This is an alternate approach to the patches proposed in D153897 
 and
D153794 . Rather than exporting a single 
header that can be included on
the GPU in all circumstances, this patch chooses to instead generate a
separate set of headers that only provides the declarations. This can
then be used by external tooling to set up what's on the GPU. This
leaves room for header hacks for offloading languages without needing to
worry about the `libc` implementation.

Currently this generates a set of headers that only contain the
declarations. These will then be installed to a new clang resource
directory called `llvm_libc_wrappers/` which will house the shim code.
We can then automaticlaly include this from `clang` when offloading to
wrap around the headers while specifying what's on the GPU.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154036

Files:
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/llvm_libc_wrappers/ctype.h
  clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
  clang/lib/Headers/llvm_libc_wrappers/stdio.h
  clang/lib/Headers/llvm_libc_wrappers/stdlib.h
  clang/lib/Headers/llvm_libc_wrappers/string.h
  clang/test/Driver/gpu-libc-headers.c
  libc/cmake/modules/LLVMLibCHeaderRules.cmake
  libc/include/CMakeLists.txt
  libc/utils/HdrGen/Generator.cpp
  libc/utils/HdrGen/Generator.h
  libc/utils/HdrGen/Main.cpp

Index: libc/utils/HdrGen/Main.cpp
===
--- libc/utils/HdrGen/Main.cpp
+++ libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@
 llvm::cl::list ReplacementValues(
 "args", llvm::cl::desc("Command separated = pairs."),
 llvm::cl::value_desc("[,name=value]"));
+llvm::cl::opt ExportDecls(
+"export-decls",
+llvm::cl::desc("Output a new header containing only the entrypoints."));
 
 void ParseArgValuePairs(std::unordered_map ) {
   for (std::string  : ReplacementValues) {
@@ -48,7 +51,10 @@
   std::unordered_map ArgMap;
   ParseArgValuePairs(ArgMap);
   Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
-  G.generate(OS, Records);
+  if (ExportDecls)
+G.generateDecls(OS, Records);
+  else
+G.generate(OS, Records);
 
   return false;
 }
Index: libc/utils/HdrGen/Generator.h
===
--- libc/utils/HdrGen/Generator.h
+++ libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@
 ArgMap(Map) {}
 
   void generate(llvm::raw_ostream , llvm::RecordKeeper );
+  void generateDecls(llvm::raw_ostream , llvm::RecordKeeper );
 };
 
 } // namespace llvm_libc
Index: libc/utils/HdrGen/Generator.cpp
===
--- libc/utils/HdrGen/Generator.cpp
+++ libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
 
 #include "IncludeFileCommand.h"
 #include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@
   }
 }
 
+void Generator::generateDecls(llvm::raw_ostream ,
+  llvm::RecordKeeper ) {
+
+  OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+"Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+"===---"
+"---===//\n\n";
+
+  std::string HeaderGuard(StdHeader.size(), '\0');
+  llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+return !isalnum(C) ? '_' : llvm::toUpper(C);
+  });
+  OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+  OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+  OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+  APIIndexer G(StdHeader, Records);
+  for (auto  : EntrypointNameList) {
+// Filter out functions not exported by this header.
+if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+  continue;
+
+llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+