[llvm] [OFFLOAD][L0] Add support to run ctor/dtor code (PR #187510)

Kevin Sala Penades via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 24 12:48:33 PDT 2026


================
@@ -1142,4 +1139,143 @@ Expected<bool> L0DeviceTy::isAccessiblePtrImpl(const void *Ptr, size_t Size) {
   return getMemAllocator(Ptr).contains(Ptr, Size);
 }
 
+Error L0DeviceTy::callGlobalConstructors(GenericPluginTy &Plugin,
+                                         DeviceImageTy &Image) {
+  return callGlobalCtorDtorCommon(Plugin, Image, /*IsCtor=*/true);
+}
+
+Error L0DeviceTy::callGlobalDestructors(GenericPluginTy &Plugin,
+                                        DeviceImageTy &Image) {
+  return callGlobalCtorDtorCommon(Plugin, Image, /*IsCtor=*/false);
+}
+
+Error L0DeviceTy::callGlobalCtorDtorCommon(GenericPluginTy &Plugin,
+                                           DeviceImageTy &Image, bool IsCtor) {
+  const char *KernelName = IsCtor ? "spirv$device$init" : "spirv$device$fini";
+
+  // Check if a kernel was generated to run constructor or destructors.
+  // It should be created by the 'spirv-lower-ctor-dtor' pass.
+  GenericGlobalHandlerTy &Handler = Plugin.getGlobalHandler();
+  if (!Handler.isSymbolInImage(*this, Image, KernelName))
+    return Plugin::success();
+
+  // Instead of returning errors directly, we capture them and provide
+  // more of context about this routine.
+  auto HandleErr = [&](Error Err) {
+    std::string Buffer;
+    llvm::raw_string_ostream(Buffer)
+        << "failed to call global " << (IsCtor ? "constructors" : "destructors")
+        << " in the image";
+    return Plugin::error(ErrorCode::INVALID_BINARY, std::move(Err),
+                         Buffer.c_str());
+  };
+  auto HandleErrStr = [&](const std::string &Msg) {
+    return Plugin::error(ErrorCode::INVALID_BINARY,
+                         "failed to call global %s in the image: %s",
+                         IsCtor ? "constructors" : "destructors", Msg.c_str());
+  };
+
+  // The SPIR-V backend cannot handle creating the ctor / dtor array
+  // automatically so we must create it ourselves. The backend will emit
+  // several globals that contain function pointers we can call. These are
+  // prefixed with a __init_array_object_ or __fini_array_object_.
+  auto ELFObjOrErr = Handler.getELFObjectFile(Image);
+  if (!ELFObjOrErr)
+    return HandleErr(ELFObjOrErr.takeError());
+
+  using FuncNameAndPriority = std::pair<StringRef, uint16_t>;
+  SmallVector<FuncNameAndPriority> Funcs;
+  for (ELFSymbolRef Sym : (*ELFObjOrErr)->symbols()) {
+    auto NameOrErr = Sym.getName();
+    if (!NameOrErr)
+      return HandleErr(NameOrErr.takeError());
+
+    if (!NameOrErr->starts_with(IsCtor ? "__init_array_object_"
+                                       : "__fini_array_object_"))
+      continue;
+
+    uint16_t Priority;
+    if (NameOrErr->rsplit('_').second.getAsInteger(10, Priority))
+      return HandleErrStr("invalid priority for constructor or destructor");
----------------
kevinsala wrote:

Can you create the error here instead of using a lambda? It's only used once.

https://github.com/llvm/llvm-project/pull/187510


More information about the llvm-commits mailing list