Skip to content

Conversation

@andykaylor
Copy link
Contributor

A previous refactoring had reduced the ArgInfo structure to contain a single member, the argument type. This change eliminates the ArgInfo structure entirely, instead just storing the argument type directly in places where ArgInfo had previously been used.

This also updates the place where the arg types were previously being copied for a call to CIRGenFunctionInfo::Profile to instead use the stored argument types buffer directly and adds assertions where the calculated folding set ID is used to verify that any match was correct.

A previous refactoring had reduced the ArgInfo structure to contain a
single member, the argument type. This change eliminates the ArgInfo
structure entirely, instead just storing the argument type directly in
places where ArgInfo had previously been used.

This also updates the place where the arg types were previously being
copied for a call to CIRGenFunctionInfo::Profile to instead use the
stored argument types buffer directly and adds assertions where the
calculated folding set ID is used to verify that any match was
correct.
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels May 19, 2025
@andykaylor
Copy link
Contributor Author

This corresponds to the incubator PR at llvm/clangir#1629

@llvmbot
Copy link
Member

llvmbot commented May 19, 2025

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

Changes

A previous refactoring had reduced the ArgInfo structure to contain a single member, the argument type. This change eliminates the ArgInfo structure entirely, instead just storing the argument type directly in places where ArgInfo had previously been used.

This also updates the place where the arg types were previously being copied for a call to CIRGenFunctionInfo::Profile to instead use the stored argument types buffer directly and adds assertions where the calculated folding set ID is used to verify that any match was correct.


Full diff: https://github.com/llvm/llvm-project/pull/140612.diff

3 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+10-11)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h (+26-39)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+8-1)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 17bfa19f9fd63..f63b971ac26b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -23,8 +23,9 @@ CIRGenFunctionInfo *
 CIRGenFunctionInfo::create(CanQualType resultType,
                            llvm::ArrayRef<CanQualType> argTypes,
                            RequiredArgs required) {
-  // The first slot allocated for ArgInfo is for the return value.
-  void *buffer = operator new(totalSizeToAlloc<ArgInfo>(argTypes.size() + 1));
+  // The first slot allocated for arg type slot is for the return value.
+  void *buffer = operator new(
+      totalSizeToAlloc<CanQualType>(argTypes.size() + 1));
 
   assert(!cir::MissingFeatures::opCallCIRGenFuncInfoParamInfo());
 
@@ -33,10 +34,8 @@ CIRGenFunctionInfo::create(CanQualType resultType,
   fi->required = required;
   fi->numArgs = argTypes.size();
 
-  ArgInfo *argsBuffer = fi->getArgsBuffer();
-  (argsBuffer++)->type = resultType;
-  for (CanQualType ty : argTypes)
-    (argsBuffer++)->type = ty;
+  fi->getArgTypes()[0] = resultType;
+  std::copy(argTypes.begin(), argTypes.end(), fi->argTypesBegin());
   assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
 
   return fi;
@@ -47,8 +46,8 @@ cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &fi) {
   SmallVector<mlir::Type, 8> argTypes;
   argTypes.reserve(fi.getNumRequiredArgs());
 
-  for (const CIRGenFunctionInfoArgInfo &argInfo : fi.requiredArguments())
-    argTypes.push_back(convertType(argInfo.type));
+  for (const CanQualType &argType : fi.requiredArguments())
+    argTypes.push_back(convertType(argType));
 
   return cir::FuncType::get(argTypes,
                             (resultType ? resultType : builder.getVoidTy()),
@@ -189,13 +188,13 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
   assert(!cir::MissingFeatures::emitLifetimeMarkers());
 
   // Translate all of the arguments as necessary to match the CIR lowering.
-  for (auto [argNo, arg, argInfo] :
-       llvm::enumerate(args, funcInfo.argInfos())) {
+  for (auto [argNo, arg, canQualArgType] :
+       llvm::enumerate(args, funcInfo.argTypes())) {
 
     // Insert a padding argument to ensure proper alignment.
     assert(!cir::MissingFeatures::opCallPaddingArgs());
 
-    mlir::Type argType = convertType(argInfo.type);
+    mlir::Type argType = convertType(canQualArgType);
     if (!mlir::isa<cir::RecordType>(argType)) {
       mlir::Value v;
       if (arg.isAggregate())
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
index b74460b09a44e..334b2864a2fb2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunctionInfo.h
@@ -21,10 +21,6 @@
 
 namespace clang::CIRGen {
 
-struct CIRGenFunctionInfoArgInfo {
-  CanQualType type;
-};
-
 /// A class for recording the number of arguments that a function signature
 /// requires.
 class RequiredArgs {
@@ -72,16 +68,15 @@ class RequiredArgs {
 
 class CIRGenFunctionInfo final
     : public llvm::FoldingSetNode,
-      private llvm::TrailingObjects<CIRGenFunctionInfo,
-                                    CIRGenFunctionInfoArgInfo> {
-  using ArgInfo = CIRGenFunctionInfoArgInfo;
-
+      private llvm::TrailingObjects<CIRGenFunctionInfo, CanQualType> {
   RequiredArgs required;
 
   unsigned numArgs;
 
-  ArgInfo *getArgsBuffer() { return getTrailingObjects<ArgInfo>(); }
-  const ArgInfo *getArgsBuffer() const { return getTrailingObjects<ArgInfo>(); }
+  CanQualType *getArgTypes() { return getTrailingObjects<CanQualType>(); }
+  const CanQualType *getArgTypes() const {
+    return getTrailingObjects<CanQualType>();
+  }
 
   CIRGenFunctionInfo() : required(RequiredArgs::All) {}
 
@@ -96,8 +91,8 @@ class CIRGenFunctionInfo final
   // these have to be public.
   friend class TrailingObjects;
 
-  using const_arg_iterator = const ArgInfo *;
-  using arg_iterator = ArgInfo *;
+  using const_arg_iterator = const CanQualType *;
+  using arg_iterator = CanQualType *;
 
   // This function has to be CamelCase because llvm::FoldingSet requires so.
   // NOLINTNEXTLINE(readability-identifier-naming)
@@ -112,49 +107,41 @@ class CIRGenFunctionInfo final
 
   // NOLINTNEXTLINE(readability-identifier-naming)
   void Profile(llvm::FoldingSetNodeID &id) {
-    // It's unfortunate that we are looping over the arguments twice (here and
-    // in the static Profile function we call from here), but if the Profile
-    // functions get out of sync, we can end up with incorrect function
-    // signatures, and we don't have the argument types in the format that the
-    // static Profile function requires.
-    llvm::SmallVector<CanQualType, 16> argTypes;
-    for (const ArgInfo &argInfo : arguments())
-      argTypes.push_back(argInfo.type);
-
-    Profile(id, required, getReturnType(), argTypes);
+    // If the Profile functions get out of sync, we can end up with incorrect
+    // function signatures, so we call the static Profile function here rather
+    // than duplicating the logic.
+    Profile(id, required, getReturnType(), arguments());
   }
 
-  llvm::ArrayRef<ArgInfo> arguments() const {
-    return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+  llvm::ArrayRef<CanQualType> arguments() const {
+    return llvm::ArrayRef<CanQualType>(argTypesBegin(), numArgs);
   }
 
-  llvm::ArrayRef<ArgInfo> requiredArguments() const {
-    return llvm::ArrayRef<ArgInfo>(argInfoBegin(), getNumRequiredArgs());
+  llvm::ArrayRef<CanQualType> requiredArguments() const {
+    return llvm::ArrayRef<CanQualType>(argTypesBegin(), getNumRequiredArgs());
   }
 
-  CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
+  CanQualType getReturnType() const { return getArgTypes()[0]; }
 
-  const_arg_iterator argInfoBegin() const { return getArgsBuffer() + 1; }
-  const_arg_iterator argInfoEnd() const {
-    return getArgsBuffer() + 1 + numArgs;
-  }
-  arg_iterator argInfoBegin() { return getArgsBuffer() + 1; }
-  arg_iterator argInfoEnd() { return getArgsBuffer() + 1 + numArgs; }
+  const_arg_iterator argTypesBegin() const { return getArgTypes() + 1; }
+  const_arg_iterator argTypesEnd() const { return getArgTypes() + 1 + numArgs; }
+  arg_iterator argTypesBegin() { return getArgTypes() + 1; }
+  arg_iterator argTypesEnd() { return getArgTypes() + 1 + numArgs; }
 
-  unsigned argInfoSize() const { return numArgs; }
+  unsigned argTypeSize() const { return numArgs; }
 
-  llvm::MutableArrayRef<ArgInfo> argInfos() {
-    return llvm::MutableArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+  llvm::MutableArrayRef<CanQualType> argTypes() {
+    return llvm::MutableArrayRef<CanQualType>(argTypesBegin(), numArgs);
   }
-  llvm::ArrayRef<ArgInfo> argInfos() const {
-    return llvm::ArrayRef<ArgInfo>(argInfoBegin(), numArgs);
+  llvm::ArrayRef<CanQualType> argTypes() const {
+    return llvm::ArrayRef<CanQualType>(argTypesBegin(), numArgs);
   }
 
   bool isVariadic() const { return required.allowsOptionalArgs(); }
   RequiredArgs getRequiredArgs() const { return required; }
   unsigned getNumRequiredArgs() const {
     return isVariadic() ? getRequiredArgs().getNumRequiredArgs()
-                        : argInfoSize();
+                        : argTypeSize();
   }
 };
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index dc8872122995c..45990f198d227 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -542,8 +542,15 @@ CIRGenTypes::arrangeCIRFunctionInfo(CanQualType returnType,
 
   void *insertPos = nullptr;
   CIRGenFunctionInfo *fi = functionInfos.FindNodeOrInsertPos(id, insertPos);
-  if (fi)
+  if (fi) {
+    // We found a matching function info based on id. These asserts verify that
+    // it really is a match.
+    assert(
+        fi->getReturnType() == returnType &&
+        std::equal(fi->argTypesBegin(), fi->argTypesEnd(), argTypes.begin()) &&
+        "Bad match based on CIRGenFunctionInfo folding set id");
     return *fi;
+  }
 
   assert(!cir::MissingFeatures::opCallCallConv());
 

assert(
fi->getReturnType() == returnType &&
std::equal(fi->argTypesBegin(), fi->argTypesEnd(), argTypes.begin()) &&
"Bad match based on CIRGenFunctionInfo folding set id");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bcardosolopes I think this assert accomplishes the testing you asked for in #140322 thoroughly without the need to introduce a unit test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks Andy!

assert(
fi->getReturnType() == returnType &&
std::equal(fi->argTypesBegin(), fi->argTypesEnd(), argTypes.begin()) &&
"Bad match based on CIRGenFunctionInfo folding set id");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks Andy!

Copy link
Member

@el-ev el-ev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@Lancern Lancern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one nit

CIRGenFunctionInfoArgInfo> {
using ArgInfo = CIRGenFunctionInfoArgInfo;

private llvm::TrailingObjects<CIRGenFunctionInfo, CanQualType> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we have some comment here to indicate that CanQualType refers to the argument type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, that part of the buffer is used for both the return type and the argument types, but I agree that a comment would be useful.

@andykaylor andykaylor merged commit 554e27e into llvm:main May 20, 2025
11 checks passed
@andykaylor andykaylor deleted the cir-remove-arginfo branch May 20, 2025 22:17
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 20, 2025

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime-2 running on rocm-worker-hw-02 while building clang at step 5 "compile-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/10/builds/5735

Here is the relevant piece of the build log for the reference
Step 5 (compile-openmp) failure: build (failure)
...
0.156 [388/130/179] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/wchar.h
0.157 [387/130/180] Generating header wchar.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/wchar.yaml
0.157 [386/130/181] Generating header ctype.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/ctype.yaml
0.158 [385/130/182] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/ctype.h
0.158 [384/130/183] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/stdlib.h
0.158 [384/129/184] Generating header locale.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/locale.yaml
0.159 [382/130/185] Generating header uchar.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/uchar.yaml
0.159 [381/130/186] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/stdio.h
0.159 [380/130/187] Generating header time.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/time.yaml
0.160 [379/130/188] Building CXX object libc/src/stdlib/CMakeFiles/libc.src.stdlib.memalignment.dir/memalignment.cpp.o
FAILED: libc/src/stdlib/CMakeFiles/libc.src.stdlib.memalignment.dir/memalignment.cpp.o 
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/./bin/clang++ --target=amdgcn-amd-amdhsa -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -D__LIBC_USE_FLOAT16_CONVERSION -I/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/libc -isystem /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa -O3 -DNDEBUG --target=amdgcn-amd-amdhsa -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES | LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT)" -fpie -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -nogpulib -fvisibility=hidden -fconvergent-functions -flto -Wno-multi-gpu -Xclang -mcode-object-version=none -DLIBC_COPT_PUBLIC_PACKAGING -UNDEBUG -MD -MT libc/src/stdlib/CMakeFiles/libc.src.stdlib.memalignment.dir/memalignment.cpp.o -MF libc/src/stdlib/CMakeFiles/libc.src.stdlib.memalignment.dir/memalignment.cpp.o.d -o libc/src/stdlib/CMakeFiles/libc.src.stdlib.memalignment.dir/memalignment.cpp.o -c /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/libc/src/stdlib/memalignment.cpp
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/libc/src/stdlib/memalignment.cpp:20:3: error: unknown type name 'uintptr_t'
   20 |   uintptr_t addr = reinterpret_cast<uintptr_t>(p);
      |   ^
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/libc/src/stdlib/memalignment.cpp:20:37: error: unknown type name 'uintptr_t'
   20 |   uintptr_t addr = reinterpret_cast<uintptr_t>(p);
      |                                     ^
2 errors generated.
0.160 [379/129/189] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.bcopy.dir/bcopy.cpp.o
0.160 [379/128/190] Generating header stdlib.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/stdlib.yaml
0.160 [379/127/191] Generating header stdio.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/stdio.yaml
0.160 [379/126/192] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/time.h
0.160 [379/125/193] Generating /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/include/amdgcn-amd-amdhsa/llvm-libc-decls/signal.h
0.161 [379/124/194] Generating header signal.h from /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/runtimes/../libc/include/signal.yaml
0.172 [379/123/195] Building CXX object libc/src/string/CMakeFiles/libc.src.string.strstr.dir/strstr.cpp.o
0.179 [379/122/196] Building CXX object libc/src/__support/GPU/CMakeFiles/libc.src.__support.GPU.allocator.dir/allocator.cpp.o
0.181 [379/121/197] Building CXX object libc/src/errno/CMakeFiles/libc.src.errno.errno.dir/libc_errno.cpp.o
0.184 [379/120/198] Building CXX object libc/src/string/CMakeFiles/libc.src.string.strcasestr.dir/strcasestr.cpp.o
0.185 [379/119/199] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.common_constants.dir/common_constants.cpp.o
0.212 [379/118/200] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_ones_ui.dir/stdc_trailing_ones_ui.cpp.o
0.217 [379/117/201] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_zeros_ui.dir/stdc_trailing_zeros_ui.cpp.o
0.220 [379/116/202] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ull.dir/stdc_bit_width_ull.cpp.o
0.229 [379/115/203] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_count_ones_ui.dir/stdc_count_ones_ui.cpp.o
0.229 [379/114/204] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_leading_zeros_uc.dir/stdc_leading_zeros_uc.cpp.o
0.230 [379/113/205] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_count_ones_ul.dir/stdc_count_ones_ul.cpp.o
0.231 [379/112/206] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_leading_zeros_ul.dir/stdc_leading_zeros_ul.cpp.o
0.232 [379/111/207] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_zeros_ull.dir/stdc_trailing_zeros_ull.cpp.o
0.235 [379/110/208] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_ones_us.dir/stdc_trailing_ones_us.cpp.o
0.235 [379/109/209] Building CXX object libc/src/ctype/CMakeFiles/libc.src.ctype.isdigit_l.dir/isdigit_l.cpp.o
0.235 [379/108/210] Building CXX object libc/src/ctype/CMakeFiles/libc.src.ctype.isblank_l.dir/isblank_l.cpp.o
0.236 [379/107/211] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_count_zeros_ui.dir/stdc_count_zeros_ui.cpp.o
0.236 [379/106/212] Building CXX object libc/src/ctype/CMakeFiles/libc.src.ctype.iscntrl_l.dir/iscntrl_l.cpp.o
0.236 [379/105/213] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_ones_ull.dir/stdc_trailing_ones_ull.cpp.o
0.237 [379/104/214] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ui.dir/stdc_has_single_bit_ui.cpp.o
0.237 [379/103/215] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_one_ull.dir/stdc_first_leading_one_ull.cpp.o
0.239 [379/102/216] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_trailing_one_ul.dir/stdc_first_trailing_one_ul.cpp.o
0.239 [379/101/217] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_us.dir/stdc_has_single_bit_us.cpp.o
0.239 [379/100/218] Building CXX object libc/src/ctype/CMakeFiles/libc.src.ctype.isalnum.dir/isalnum.cpp.o

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants