[llvm] [OpenMP][Offload] Continue to update libomptarget debug messages (PR #170425)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 21:54:04 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-offload
Author: Alex Duran (adurang)
<details>
<summary>Changes</summary>
* Add support to use lambdas to output debug messages (like LDBG_OS)
* Update messages for interface.cpp and omptarget.cpp
---
Patch is 61.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170425.diff
3 Files Affected:
- (modified) offload/include/Shared/Debug.h (+63)
- (modified) offload/libomptarget/interface.cpp (+45-40)
- (modified) offload/libomptarget/omptarget.cpp (+238-213)
``````````diff
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 9e657e64484c0..d60ba26257bbe 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -430,6 +430,60 @@ static inline raw_ostream &operator<<(raw_ostream &Os,
#define ODBG_RESET_LEVEL() \
static_cast<llvm::offload::debug::odbg_ostream::IfLevel>(0)
+// helper templates to support lambdas with different number of arguments
+
+template <typename LambdaTy> struct lambdaHelper {
+ template <typename FuncTy, typename RetTy, typename... Args>
+ static constexpr size_t CountArgs(RetTy (FuncTy::*)(Args...)) {
+ return sizeof...(Args);
+ }
+
+ template <typename FuncTy, typename RetTy, typename... Args>
+ static constexpr size_t CountArgs(RetTy (FuncTy::*)(Args...) const) {
+ return sizeof...(Args);
+ }
+
+ static constexpr size_t NArgs = CountArgs(&LambdaTy::operator());
+
+ static void dispatch(LambdaTy func, llvm::raw_ostream &Os, uint32_t Level) {
+ if constexpr (NArgs == 1)
+ func(Os);
+ else if constexpr (NArgs == 2)
+ func(Os, Level);
+ else
+ static_assert(true, "Unsupported number of arguments in debug callback");
+ }
+};
+
+#define ODBG_OS_BASE(Stream, Component, Prefix, Type, Level, Callback) \
+ if (::llvm::offload::debug::isDebugEnabled()) { \
+ uint32_t RealLevel = (Level); \
+ if (::llvm::offload::debug::shouldPrintDebug((Component), (Type), \
+ RealLevel)) { \
+ ::llvm::offload::debug::odbg_ostream OS{ \
+ ::llvm::offload::debug::computePrefix((Prefix), (Type)), (Stream), \
+ RealLevel, /*ShouldPrefixNextString=*/true, \
+ /*ShouldEmitNewLineOnDestruction=*/true}; \
+ auto F = Callback; \
+ ::llvm::offload::debug::lambdaHelper<decltype(F)>::dispatch(F, OS, \
+ RealLevel); \
+ } \
+ }
+
+#define ODBG_OS_STREAM(Stream, Type, Level, Callback) \
+ ODBG_OS_BASE(Stream, GETNAME(TARGET_NAME), DEBUG_PREFIX, Type, Level, \
+ Callback)
+#define ODBG_OS_3(Type, Level, Callback) \
+ ODBG_OS_STREAM(llvm::offload::debug::dbgs(), Type, Level, Callback)
+#define ODBG_OS_2(Type, Callback) ODBG_OS_3(Type, 1, Callback)
+#define ODBG_OS_1(Callback) ODBG_OS_2("default", Callback)
+#define ODBG_OS_SELECT(Type, Level, Callback, NArgs, ...) ODBG_OS_##NArgs
+// Print a debug message of a certain type and verbosity level using a callback
+// to emit the message. If no type or level is provided, "default" and "1 are
+// assumed respectively.
+#define ODBG_OS(...) \
+ ODBG_OS_SELECT(__VA_ARGS__ __VA_OPT__(, ) 3, 2, 1)(__VA_ARGS__)
+
#else
inline bool isDebugEnabled() { return false; }
@@ -446,6 +500,10 @@ inline bool isDebugEnabled() { return false; }
#define ODBG_RESET_LEVEL() 0
#define ODBG(...) ODBG_NULL
+#define ODBG_OS_BASE(Stream, Component, Prefix, Type, Level, Callback)
+#define ODBG_OS_STREAM(Stream, Type, Level, Callback)
+#define ODBG_OS(...)
+
#endif
} // namespace llvm::offload::debug
@@ -476,6 +534,9 @@ constexpr const char *ODT_DumpTable = "DumpTable";
constexpr const char *ODT_MappingChanged = "MappingChanged";
constexpr const char *ODT_PluginKernel = "PluginKernel";
constexpr const char *ODT_EmptyMapping = "EmptyMapping";
+constexpr const char *ODT_Device = "Device";
+constexpr const char *ODT_Interface = "Interface";
+constexpr const char *ODT_Alloc = "Alloc";
static inline odbg_ostream reportErrorStream() {
#ifdef OMPTARGET_DEBUG
@@ -540,4 +601,6 @@ static inline odbg_ostream reportErrorStream() {
} // namespace llvm::omp::target::debug
+inline int getDebugLevel() { return 1; }
+
#endif // OMPTARGET_SHARED_DEBUG_H
diff --git a/offload/libomptarget/interface.cpp b/offload/libomptarget/interface.cpp
index fe18289765906..c17e3e39b04b9 100644
--- a/offload/libomptarget/interface.cpp
+++ b/offload/libomptarget/interface.cpp
@@ -25,6 +25,7 @@
#include "Utils/ExponentialBackoff.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/Support/Format.h"
#include <cassert>
#include <cstdint>
@@ -35,6 +36,7 @@
#ifdef OMPT_SUPPORT
using namespace llvm::omp::target::ompt;
#endif
+using namespace llvm::omp::target::debug;
// If offload is enabled, ensure that device DeviceID has been initialized.
//
@@ -49,25 +51,25 @@ using namespace llvm::omp::target::ompt;
// This step might be skipped if offload is disabled.
bool checkDevice(int64_t &DeviceID, ident_t *Loc) {
if (OffloadPolicy::get(*PM).Kind == OffloadPolicy::DISABLED) {
- DP("Offload is disabled\n");
+ ODBG(ODT_Device) << "Offload is disabled";
return true;
}
if (DeviceID == OFFLOAD_DEVICE_DEFAULT) {
DeviceID = omp_get_default_device();
- DP("Use default device id %" PRId64 "\n", DeviceID);
+ ODBG(ODT_Device) << "Use default device id " << DeviceID;
}
// Proposed behavior for OpenMP 5.2 in OpenMP spec github issue 2669.
if (omp_get_num_devices() == 0) {
- DP("omp_get_num_devices() == 0 but offload is manadatory\n");
+ ODBG(ODT_Device) << "omp_get_num_devices() == 0 but offload is manadatory";
handleTargetOutcome(false, Loc);
return true;
}
if (DeviceID == omp_get_initial_device()) {
- DP("Device is host (%" PRId64 "), returning as if offload is disabled\n",
- DeviceID);
+ ODBG(ODT_Device) << "Device is host (" << DeviceID
+ << "), returning as if offload is disabled";
return true;
}
return false;
@@ -123,25 +125,25 @@ targetData(ident_t *Loc, int64_t DeviceId, int32_t ArgNum, void **ArgsBase,
TIMESCOPE_WITH_DETAILS_AND_IDENT("Runtime: Data Copy",
"NumArgs=" + std::to_string(ArgNum), Loc);
- DP("Entering data %s region for device %" PRId64 " with %d mappings\n",
- RegionName, DeviceId, ArgNum);
+ ODBG(ODT_Interface) << "Entering data " << RegionName << " region for device "
+ << DeviceId << " with " << ArgNum << " mappings";
if (checkDevice(DeviceId, Loc)) {
- DP("Not offloading to device %" PRId64 "\n", DeviceId);
+ ODBG(ODT_Interface) << "Not offloading to device " << DeviceId;
return;
}
if (getInfoLevel() & OMP_INFOTYPE_KERNEL_ARGS)
printKernelArguments(Loc, DeviceId, ArgNum, ArgSizes, ArgTypes, ArgNames,
RegionTypeMsg);
-#ifdef OMPTARGET_DEBUG
- for (int I = 0; I < ArgNum; ++I) {
- DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
- ", Type=0x%" PRIx64 ", Name=%s\n",
- I, DPxPTR(ArgsBase[I]), DPxPTR(Args[I]), ArgSizes[I], ArgTypes[I],
- (ArgNames) ? getNameFromMapping(ArgNames[I]).c_str() : "unknown");
- }
-#endif
+ ODBG_OS(ODT_Kernel, [&](llvm::raw_ostream &Os) {
+ for (int I = 0; I < ArgNum; ++I) {
+ Os << "Entry " << llvm::format_decimal(I, 2) << ": Base=" << ArgsBase[I]
+ << ", Begin=" << Args[I] << ", Size=" << ArgSizes[I]
+ << ", Type=" << llvm::format_hex(ArgTypes[I], 8) << ", Name="
+ << ((ArgNames) ? getNameFromMapping(ArgNames[I]) : "unknown") << "\n";
+ }
+ });
auto DeviceOrErr = PM->getDevice(DeviceId);
if (!DeviceOrErr)
@@ -274,7 +276,7 @@ static KernelArgsTy *upgradeKernelArgs(KernelArgsTy *KernelArgs,
KernelArgsTy &LocalKernelArgs,
int32_t NumTeams, int32_t ThreadLimit) {
if (KernelArgs->Version > OMP_KERNEL_ARG_VERSION)
- DP("Unexpected ABI version: %u\n", KernelArgs->Version);
+ ODBG(ODT_Interface) << "Unexpected ABI version: " << KernelArgs->Version;
uint32_t UpgradedVersion = KernelArgs->Version;
if (KernelArgs->Version < OMP_KERNEL_ARG_VERSION) {
@@ -326,12 +328,11 @@ static inline int targetKernel(ident_t *Loc, int64_t DeviceId, int32_t NumTeams,
assert(PM && "Runtime not initialized");
static_assert(std::is_convertible_v<TargetAsyncInfoTy &, AsyncInfoTy &>,
"Target AsyncInfoTy must be convertible to AsyncInfoTy.");
- DP("Entering target region for device %" PRId64 " with entry point " DPxMOD
- "\n",
- DeviceId, DPxPTR(HostPtr));
+ ODBG(ODT_Interface) << "Entering target region for device " << DeviceId
+ << " with entry point " << HostPtr;
if (checkDevice(DeviceId, Loc)) {
- DP("Not offloading to device %" PRId64 "\n", DeviceId);
+ ODBG(ODT_Interface) << "Not offloading to device " << DeviceId;
return OMP_TGT_FAIL;
}
@@ -354,17 +355,21 @@ static inline int targetKernel(ident_t *Loc, int64_t DeviceId, int32_t NumTeams,
printKernelArguments(Loc, DeviceId, KernelArgs->NumArgs,
KernelArgs->ArgSizes, KernelArgs->ArgTypes,
KernelArgs->ArgNames, "Entering OpenMP kernel");
-#ifdef OMPTARGET_DEBUG
- for (uint32_t I = 0; I < KernelArgs->NumArgs; ++I) {
- DP("Entry %2d: Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
- ", Type=0x%" PRIx64 ", Name=%s\n",
- I, DPxPTR(KernelArgs->ArgBasePtrs[I]), DPxPTR(KernelArgs->ArgPtrs[I]),
- KernelArgs->ArgSizes[I], KernelArgs->ArgTypes[I],
- (KernelArgs->ArgNames)
- ? getNameFromMapping(KernelArgs->ArgNames[I]).c_str()
- : "unknown");
- }
-#endif
+
+ ODBG_OS(ODT_Kernel, [&](llvm::raw_ostream &Os) {
+ for (uint32_t I = 0; I < KernelArgs->NumArgs; ++I) {
+ Os << "Entry " << llvm::format_decimal(I, 2)
+ << " Base=" << KernelArgs->ArgBasePtrs[I]
+ << ", Begin=" << KernelArgs->ArgPtrs[I]
+ << ", Size=" << KernelArgs->ArgSizes[I]
+ << ", Type=" << llvm::format_hex(KernelArgs->ArgTypes[I], 8)
+ << ", Name="
+ << (KernelArgs->ArgNames
+ ? getNameFromMapping(KernelArgs->ArgNames[I]).c_str()
+ : "unknown")
+ << "\n";
+ }
+ });
auto DeviceOrErr = PM->getDevice(DeviceId);
if (!DeviceOrErr)
@@ -463,7 +468,7 @@ EXTERN int __tgt_target_kernel_replay(ident_t *Loc, int64_t DeviceId,
assert(PM && "Runtime not initialized");
OMPT_IF_BUILT(ReturnAddressSetterRAII RA(__builtin_return_address(0)));
if (checkDevice(DeviceId, Loc)) {
- DP("Not offloading to device %" PRId64 "\n", DeviceId);
+ ODBG(ODT_Interface) << "Not offloading to device " << DeviceId;
return OMP_TGT_FAIL;
}
auto DeviceOrErr = PM->getDevice(DeviceId);
@@ -491,8 +496,8 @@ EXTERN int __tgt_target_kernel_replay(ident_t *Loc, int64_t DeviceId,
EXTERN int64_t __tgt_mapper_num_components(void *RtMapperHandle) {
auto *MapperComponentsPtr = (struct MapperComponentsTy *)RtMapperHandle;
int64_t Size = MapperComponentsPtr->Components.size();
- DP("__tgt_mapper_num_components(Handle=" DPxMOD ") returns %" PRId64 "\n",
- DPxPTR(RtMapperHandle), Size);
+ ODBG(ODT_Interface) << "__tgt_mapper_num_components(Handle=" << RtMapperHandle
+ << ") returns " << Size;
return Size;
}
@@ -500,11 +505,11 @@ EXTERN int64_t __tgt_mapper_num_components(void *RtMapperHandle) {
EXTERN void __tgt_push_mapper_component(void *RtMapperHandle, void *Base,
void *Begin, int64_t Size, int64_t Type,
void *Name) {
- DP("__tgt_push_mapper_component(Handle=" DPxMOD
- ") adds an entry (Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
- ", Type=0x%" PRIx64 ", Name=%s).\n",
- DPxPTR(RtMapperHandle), DPxPTR(Base), DPxPTR(Begin), Size, Type,
- (Name) ? getNameFromMapping(Name).c_str() : "unknown");
+ ODBG(ODT_Interface) << "__tgt_push_mapper_component(Handle=" << RtMapperHandle
+ << ") adds an entry (Base=" << Base << ", Begin=" << Begin
+ << ", Size=" << Size
+ << ", Type=" << llvm::format_hex(Type, 8) << ", Name="
+ << ((Name) ? getNameFromMapping(Name) : "unknown") << ")";
auto *MapperComponentsPtr = (struct MapperComponentsTy *)RtMapperHandle;
MapperComponentsPtr->Components.push_back(
MapComponentInfoTy(Base, Begin, Size, Type, Name));
diff --git a/offload/libomptarget/omptarget.cpp b/offload/libomptarget/omptarget.cpp
index 69725e77bae00..021caff159919 100644
--- a/offload/libomptarget/omptarget.cpp
+++ b/offload/libomptarget/omptarget.cpp
@@ -41,6 +41,7 @@ using llvm::SmallVector;
#ifdef OMPT_SUPPORT
using namespace llvm::omp::target::ompt;
#endif
+using namespace llvm::omp::target::debug;
int AsyncInfoTy::synchronize() {
int Result = OFFLOAD_SUCCESS;
@@ -200,10 +201,11 @@ static int32_t getParentIndex(int64_t Type) {
void *targetAllocExplicit(size_t Size, int DeviceNum, int Kind,
const char *Name) {
- DP("Call to %s for device %d requesting %zu bytes\n", Name, DeviceNum, Size);
+ ODBG(ODT_Interface) << "Call to " << Name << " for device " << DeviceNum
+ << " requesting " << Size << " bytes";
if (Size <= 0) {
- DP("Call to %s with non-positive length\n", Name);
+ ODBG(ODT_Interface) << "Call to " << Name << " with non-positive length";
return NULL;
}
@@ -211,7 +213,7 @@ void *targetAllocExplicit(size_t Size, int DeviceNum, int Kind,
if (DeviceNum == omp_get_initial_device()) {
Rc = malloc(Size);
- DP("%s returns host ptr " DPxMOD "\n", Name, DPxPTR(Rc));
+ ODBG(ODT_Interface) << Name << " returns host ptr " << Rc;
return Rc;
}
@@ -220,23 +222,23 @@ void *targetAllocExplicit(size_t Size, int DeviceNum, int Kind,
FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
Rc = DeviceOrErr->allocData(Size, nullptr, Kind);
- DP("%s returns device ptr " DPxMOD "\n", Name, DPxPTR(Rc));
+ ODBG(ODT_Interface) << Name << " returns device ptr " << Rc;
return Rc;
}
void targetFreeExplicit(void *DevicePtr, int DeviceNum, int Kind,
const char *Name) {
- DP("Call to %s for device %d and address " DPxMOD "\n", Name, DeviceNum,
- DPxPTR(DevicePtr));
+ ODBG(ODT_Interface) << "Call to " << Name << " for device " << DeviceNum
+ << " and address " << DevicePtr;
if (!DevicePtr) {
- DP("Call to %s with NULL ptr\n", Name);
+ ODBG(ODT_Interface) << "Call to " << Name << " with NULL ptr";
return;
}
if (DeviceNum == omp_get_initial_device()) {
free(DevicePtr);
- DP("%s deallocated host ptr\n", Name);
+ ODBG(ODT_Interface) << Name << " deallocated host ptr";
return;
}
@@ -249,15 +251,16 @@ void targetFreeExplicit(void *DevicePtr, int DeviceNum, int Kind,
"Failed to deallocate device ptr. Set "
"OFFLOAD_TRACK_ALLOCATION_TRACES=1 to track allocations.");
- DP("omp_target_free deallocated device ptr\n");
+ ODBG(ODT_Interface) << "omp_target_free deallocated device ptr";
}
void *targetLockExplicit(void *HostPtr, size_t Size, int DeviceNum,
const char *Name) {
- DP("Call to %s for device %d locking %zu bytes\n", Name, DeviceNum, Size);
+ ODBG(ODT_Interface) << "Call to " << Name << " for device " << DeviceNum
+ << " locking " << Size << " bytes";
if (Size <= 0) {
- DP("Call to %s with non-positive length\n", Name);
+ ODBG(ODT_Interface) << "Call to " << Name << " with non-positive length";
return NULL;
}
@@ -270,22 +273,23 @@ void *targetLockExplicit(void *HostPtr, size_t Size, int DeviceNum,
int32_t Err = 0;
Err = DeviceOrErr->RTL->data_lock(DeviceNum, HostPtr, Size, &RC);
if (Err) {
- DP("Could not lock ptr %p\n", HostPtr);
+ ODBG(ODT_Interface) << "Could not lock ptr " << HostPtr;
return nullptr;
}
- DP("%s returns device ptr " DPxMOD "\n", Name, DPxPTR(RC));
+ ODBG(ODT_Interface) << Name << " returns device ptr " << RC;
return RC;
}
void targetUnlockExplicit(void *HostPtr, int DeviceNum, const char *Name) {
- DP("Call to %s for device %d unlocking\n", Name, DeviceNum);
+ ODBG(ODT_Interface) << "Call to " << Name << " for device " << DeviceNum
+ << " unlocking";
auto DeviceOrErr = PM->getDevice(DeviceNum);
if (!DeviceOrErr)
FATAL_MESSAGE(DeviceNum, "%s", toString(DeviceOrErr.takeError()).c_str());
DeviceOrErr->RTL->data_unlock(DeviceNum, HostPtr);
- DP("%s returns\n", Name);
+ ODBG(ODT_Interface) << Name << " returns";
}
/// Call the user-defined mapper function followed by the appropriate
@@ -295,7 +299,7 @@ int targetDataMapper(ident_t *Loc, DeviceTy &Device, void *ArgBase, void *Arg,
void *ArgMapper, AsyncInfoTy &AsyncInfo,
TargetDataFuncPtrTy TargetDataFunction,
AttachInfoTy *AttachInfo = nullptr) {
- DP("Calling the mapper function " DPxMOD "\n", DPxPTR(ArgMapper));
+ ODBG(ODT_Interface) << "Calling the mapper function " << ArgMapper;
// The mapper function fills up Components.
MapperComponentsTy MapperComponents;
@@ -368,12 +372,11 @@ static void *calculateTargetPointeeBase(void *HstPteeBase, void *HstPteeBegin,
void *TgtPteeBase = reinterpret_cast<void *>(
reinterpret_cast<uint64_t>(TgtPteeBegin) - Delta);
- DP("HstPteeBase: " DPxMOD ", HstPteeBegin: " DPxMOD
- ", Delta (HstPteeBegin - HstPteeBase): %" PRIu64 ".\n",
- DPxPTR(HstPteeBase), DPxPTR(HstPteeBegin), Delta);
- DP("TgtPteeBase (TgtPteeBegin - Delta): " DPxMOD ", TgtPteeBegin : " DPxMOD
- "\n",
- DPxPTR(TgtPteeBase), DPxPTR(TgtPteeBegin));
+ ODBG(ODT_Mapping) << "HstPteeBase: " << HstPteeBase
+ << ", HstPteeBegin: " << HstPteeBegin
+ << ", Delta (HstPteeBegin - HstPteeBase): " << Delta << "\n"
+ << "TgtPteeBase (TgtPteeBegin - Delta): " << TgtPteeBase
+ << ", TgtPteeBegin: " << TgtPteeBegin;
return TgtPteeBase;
}
@@ -453,18 +456,18 @@ static int performPointerAttachment(DeviceTy &Device, AsyncInfoTy &AsyncInfo,
// Add shadow pointer tracking
if (!PtrTPR.getEntry()->addShadowPointer(
ShadowPtrInfoTy{HstPtrAddr, TgtPtrAddr, TgtPteeBase, HstPtrSize})) {
- DP("Pointer " DPxMOD " is already attached to " DPxMOD "\n",
- DPxPTR(TgtPtrAddr), DPxPTR(TgtPteeBase));
+ ODBG(ODT_Mapping) << "Pointer " << TgtPtrAddr << " is already attached to "
+ << TgtPteeBase;
return OFFLOAD_SUCCESS;
}
- DP("Update pointer (" DPxMOD ") -> [" DPxMOD "]\n", DPxPTR(TgtPtrAddr),
- DPxPTR(TgtPteeBase));
+ ODBG(ODT_Mapping) << "Update pointer (" << TgtPtrAddr << ") -> ["
+ << TgtPteeBase << "]\n";
// Lambda to handle submitData result and perform final steps.
auto HandleSubmitResult = [&](int SubmitResult) -> int {
if (SubmitResult != OFFLOAD_SUCCESS) {
- REPORT("Failed to update pointer on device.\n");
+ REPORT() << "Failed to update pointer on device.";
return OFFLOAD_FAIL;
}
@@ -491,11 +494,11 @@ static int performPointerAttachment(DeviceTy &Device, AsyncInfoTy &AsyncInfo,
std::memcpy(SrcBuffer + VoidPtrSize, HstDescriptorFieldsAddr,
HstDescriptorFieldsSize);
- DP("Updating %" PRId64 " bytes of descriptor (" DPxMOD
- ") (pointer + %" PRId64 " additional bytes from host descriptor " DPxMOD
- ")\n",
- HstPtrSize, DPxPTR(TgtPtrAddr), HstDescriptorFieldsSize,
- DPxPTR(HstDescriptorFieldsAddr));
+ ODBG(ODT_Mapping) << "Updating " << HstPtrSize << " bytes of descriptor ("
+ << TgtPtrAddr << ") (pointer + "
+ << HstDescriptorFieldsSize
+ << " additional bytes from host descriptor "
+ << HstDescriptorFieldsAddr << ")";
}
// Submit the populated source buffer to device.
@@ -524,7 +527,8 @@ int targetDataBegin(ident_t *Loc, DeviceTy &Device, int32_t ArgNum,
// Instead of executing the regular path of targetDataBegin, call the
// targetDataMapper variant which will call targetD...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/170425
More information about the llvm-commits
mailing list