https://github.com/adams381 updated 
https://github.com/llvm/llvm-project/pull/191483

>From a2442e5314eaff940def53cac6dd8faf7ab21284 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Fri, 10 Apr 2026 11:09:42 -0700
Subject: [PATCH 1/3] =?UTF-8?q?[CIR]=20Add=20restrict=E2=86=92noalias=20an?=
 =?UTF-8?q?d=20skip=20builtins?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add noalias attribute for restrict-qualified pointer parameters on
non-builtin functions.  Builtins like printf are skipped because OGCG
applies restrict→noalias through calling convention lowering, which
builtins bypass.

Pass targetDecl to constructFunctionArgumentAttributes so it can
access ParmVarDecl for source-level qualifiers.

Made-with: Cursor
---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          | 25 ++++++++++--
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  4 +-
 .../CIR/CodeGen/asm-label-inline-builtins.c   |  4 +-
 clang/test/CIR/CodeGen/restrict-noalias.c     | 38 +++++++++++++++++++
 4 files changed, 63 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/restrict-noalias.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 876fef687b477..efcb80545d493 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -480,7 +480,7 @@ void CIRGenModule::constructAttributeList(
   // TODO(cir): Add loader-replaceable attribute here.
 
   constructFunctionReturnAttributes(info, targetDecl, isThunk, retAttrs);
-  constructFunctionArgumentAttributes(info, isThunk, argAttrs);
+  constructFunctionArgumentAttributes(info, targetDecl, isThunk, argAttrs);
 }
 
 bool CIRGenModule::hasStrictReturn(QualType retTy, const Decl *targetDecl) {
@@ -616,13 +616,13 @@ void CIRGenModule::constructFunctionReturnAttributes(
 }
 
 void CIRGenModule::constructFunctionArgumentAttributes(
-    const CIRGenFunctionInfo &info, bool isThunk,
+    const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk,
     llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs) {
   assert(!cir::MissingFeatures::abiArgInfo());
   // TODO(cir): classic codegen does a lot of work here based on the ABIArgInfo
   // to set things based on calling convention.
-  // At the moment, only nonnull, dereferenceable, align, and noundef are being
-  // implemented here, using similar logic to how we do so for return types.
+
+  const auto *fd = dyn_cast_or_null<FunctionDecl>(targetDecl);
 
   if (info.isInstanceMethod() && !isThunk) {
     QualType thisPtrTy = info.arguments()[0];
@@ -698,6 +698,23 @@ void CIRGenModule::constructFunctionArgumentAttributes(
             builder.getI64IntegerAttr(
                 getNaturalPointeeTypeAlignment(argType).getQuantity()));
     }
+
+    // restrict on pointer parameters -> noalias.  Skip builtins: OGCG only
+    // applies restrict->noalias through calling convention lowering, which
+    // builtins bypass.
+    if (fd) {
+      unsigned paramIdx = &argAttrList - argAttrs.data();
+      unsigned srcIdx = info.isInstanceMethod() ? paramIdx - 1 : paramIdx;
+      if (srcIdx < fd->getNumParams()) {
+        const ParmVarDecl *pvd = fd->getParamDecl(srcIdx);
+        QualType pvdType = pvd->getType();
+
+        if (pvdType->isPointerType() && pvdType.isRestrictQualified() &&
+            !fd->getBuiltinID())
+          argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
+                          mlir::UnitAttr::get(&getMLIRContext()));
+      }
+    }
   }
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index ca59f56366822..42d1b5c308b7d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -120,8 +120,8 @@ class CIRGenModule : public CIRGenTypeCache {
                                          mlir::NamedAttrList &retAttrs);
   /// A helper for constructAttributeList that handles argument attributes.
   void constructFunctionArgumentAttributes(
-      const CIRGenFunctionInfo &info, bool isThunk,
-      llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs);
+      const CIRGenFunctionInfo &info, const clang::Decl *targetDecl,
+      bool isThunk, llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs);
   /// A helper function for constructAttributeList that determines whether a
   /// return value might have been discarded.
   bool mayDropFunctionReturn(const ASTContext &context, QualType retTy);
diff --git a/clang/test/CIR/CodeGen/asm-label-inline-builtins.c 
b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
index f3ff4c5a0c2ba..2d11712812dd6 100644
--- a/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
+++ b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
@@ -32,14 +32,14 @@ void test(const char *fmt, __builtin_va_list ap) {
 }
 
 // CIR: cir.func always_inline internal private 
@__vprintfieee128.inline({{.*}}) -> !s32i
-// CIR:   cir.call @__vfprintf_chkieee128(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}})
+// CIR:   cir.call @__vfprintf_chkieee128({{.*}}) : (!cir.ptr<!rec__IO_FILE> 
{llvm.noalias, llvm.noundef}, !s32i {llvm.noundef}, !cir.ptr<!s8i> 
{llvm.noalias, llvm.noundef}, !cir.ptr<!rec___va_list_tag> {llvm.noundef}) -> 
!s32i
 //
 // CIR: cir.func {{.*}} @test({{.*}})
 // CIR:   cir.call @__vprintfieee128.inline(%{{.*}}, %{{.*}})
 
 
 // LLVM: define internal i32 @__vprintfieee128.inline({{.*}}) 
#[[ALWAYS_INLINE_ATTR:.*]] {
-// LLVM:   call i32 @__vfprintf_chkieee128(ptr {{.*}} %{{.*}}, i32 {{.*}} 1, 
ptr {{.*}} %{{.*}}, ptr {{.*}} %{{.*}})
+// LLVM:   call i32 @__vfprintf_chkieee128(ptr noalias noundef %{{.*}}, i32 
noundef 1, ptr noalias noundef %{{.*}}, ptr noundef %{{.*}})
 //
 // LLVM: define {{.*}} void @test{{.*}}
 // LLVM:   call i32 @__vprintfieee128.inline(ptr {{.*}} %{{.*}}, ptr {{.*}} 
%{{.*}})
diff --git a/clang/test/CIR/CodeGen/restrict-noalias.c 
b/clang/test/CIR/CodeGen/restrict-noalias.c
new file mode 100644
index 0000000000000..06513688d16dc
--- /dev/null
+++ b/clang/test/CIR/CodeGen/restrict-noalias.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+void user_func(int *__restrict p);
+
+void test_user(int *__restrict p) {
+  user_func(p);
+}
+
+// CIR: cir.func private @user_func(!cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef})
+// CIR: cir.func {{.*}} @test_user(%arg0: !cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef}
+// CIR:   cir.call @user_func(%{{.*}}) : (!cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef}) -> ()
+
+// LLVM: define dso_local void @test_user(ptr noalias noundef %{{.*}})
+// LLVM:   call void @user_func(ptr noalias noundef %{{.*}})
+
+// OGCG: define dso_local void @test_user(ptr noalias noundef %{{.*}})
+// OGCG:   call void @user_func(ptr noundef %{{.*}})
+
+int printf(const char *__restrict fmt, ...);
+
+void test_builtin(const char *__restrict fmt) {
+  printf(fmt);
+}
+
+// Builtins must NOT get noalias from restrict (matching OGCG behavior).
+// CIR: cir.func {{.*}} @test_builtin(%arg0: !cir.ptr<!s8i> {llvm.noalias, 
llvm.noundef}
+// CIR:   cir.call @printf(%{{.*}}) : (!cir.ptr<!s8i> {llvm.noundef}) -> !s32i
+
+// LLVM: define dso_local void @test_builtin(ptr noalias noundef %{{.*}})
+// LLVM:   call i32 (ptr, ...) @printf(ptr noundef %{{.*}})
+
+// OGCG: define dso_local void @test_builtin(ptr noalias noundef %{{.*}})
+// OGCG:   call i32 (ptr, ...) @printf(ptr noundef %{{.*}})

>From 706699eb8c493854984501f769336ac35b78ec58 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Mon, 13 Apr 2026 14:50:04 -0700
Subject: [PATCH 2/3] [CIR] Address review feedback on restrict->noalias

- Replace pointer arithmetic with argNo counter
- Move FunctionDecl cast closer to usage
- Add attrOnCallSite guard to skip restrict->noalias at call
  sites, matching OGCG behavior (classic codegen applies it in
  EmitFunctionProlog, not constructAttributeList)
- Update test to match OGCG: no noalias on call sites

Made-with: Cursor
---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp      | 35 +++++++++++------------
 clang/lib/CIR/CodeGen/CIRGenModule.h      |  3 +-
 clang/test/CIR/CodeGen/restrict-noalias.c |  4 +--
 3 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index efcb80545d493..277b6c8da2af9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -480,7 +480,8 @@ void CIRGenModule::constructAttributeList(
   // TODO(cir): Add loader-replaceable attribute here.
 
   constructFunctionReturnAttributes(info, targetDecl, isThunk, retAttrs);
-  constructFunctionArgumentAttributes(info, targetDecl, isThunk, argAttrs);
+  constructFunctionArgumentAttributes(info, targetDecl, isThunk, 
attrOnCallSite,
+                                      argAttrs);
 }
 
 bool CIRGenModule::hasStrictReturn(QualType retTy, const Decl *targetDecl) {
@@ -617,13 +618,11 @@ void CIRGenModule::constructFunctionReturnAttributes(
 
 void CIRGenModule::constructFunctionArgumentAttributes(
     const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk,
-    llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs) {
+    bool attrOnCallSite, llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs) {
   assert(!cir::MissingFeatures::abiArgInfo());
   // TODO(cir): classic codegen does a lot of work here based on the ABIArgInfo
   // to set things based on calling convention.
 
-  const auto *fd = dyn_cast_or_null<FunctionDecl>(targetDecl);
-
   if (info.isInstanceMethod() && !isThunk) {
     QualType thisPtrTy = info.arguments()[0];
     // Member allocation functions are instance methods, but setting attributes
@@ -666,6 +665,8 @@ void CIRGenModule::constructFunctionArgumentAttributes(
   // that seems risky at the moment. At one point we should evaluate if at 
least
   // dereferenceable, nonnull, and align can be combined.
   const cir::CIRDataLayout &layout = getDataLayout();
+  const auto *fd = dyn_cast_or_null<FunctionDecl>(targetDecl);
+  unsigned argNo = 0;
   for (const auto &[argAttrList, argCanType] :
        llvm::zip_equal(argAttrs, info.arguments())) {
     assert(!cir::MissingFeatures::abiArgInfo());
@@ -699,22 +700,18 @@ void CIRGenModule::constructFunctionArgumentAttributes(
                 getNaturalPointeeTypeAlignment(argType).getQuantity()));
     }
 
-    // restrict on pointer parameters -> noalias.  Skip builtins: OGCG only
-    // applies restrict->noalias through calling convention lowering, which
-    // builtins bypass.
-    if (fd) {
-      unsigned paramIdx = &argAttrList - argAttrs.data();
-      unsigned srcIdx = info.isInstanceMethod() ? paramIdx - 1 : paramIdx;
-      if (srcIdx < fd->getNumParams()) {
-        const ParmVarDecl *pvd = fd->getParamDecl(srcIdx);
-        QualType pvdType = pvd->getType();
-
-        if (pvdType->isPointerType() && pvdType.isRestrictQualified() &&
-            !fd->getBuiltinID())
-          argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
-                          mlir::UnitAttr::get(&getMLIRContext()));
-      }
+    // restrict -> noalias on definitions only (not call sites).  Skip
+    // builtins: OGCG applies restrict->noalias in EmitFunctionProlog.
+    if (!attrOnCallSite && fd && argType->isPointerType()) {
+      unsigned srcIdx = info.isInstanceMethod() ? argNo - 1 : argNo;
+      if (srcIdx < fd->getNumParams() &&
+          fd->getParamDecl(srcIdx)->getType().isRestrictQualified() &&
+          !fd->getBuiltinID())
+        argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
+                        mlir::UnitAttr::get(&getMLIRContext()));
     }
+
+    ++argNo;
   }
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 42d1b5c308b7d..f76fd0e8663e4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -121,7 +121,8 @@ class CIRGenModule : public CIRGenTypeCache {
   /// A helper for constructAttributeList that handles argument attributes.
   void constructFunctionArgumentAttributes(
       const CIRGenFunctionInfo &info, const clang::Decl *targetDecl,
-      bool isThunk, llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs);
+      bool isThunk, bool attrOnCallSite,
+      llvm::MutableArrayRef<mlir::NamedAttrList> argAttrs);
   /// A helper function for constructAttributeList that determines whether a
   /// return value might have been discarded.
   bool mayDropFunctionReturn(const ASTContext &context, QualType retTy);
diff --git a/clang/test/CIR/CodeGen/restrict-noalias.c 
b/clang/test/CIR/CodeGen/restrict-noalias.c
index 06513688d16dc..9ba14ce69e9e9 100644
--- a/clang/test/CIR/CodeGen/restrict-noalias.c
+++ b/clang/test/CIR/CodeGen/restrict-noalias.c
@@ -13,10 +13,10 @@ void test_user(int *__restrict p) {
 
 // CIR: cir.func private @user_func(!cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef})
 // CIR: cir.func {{.*}} @test_user(%arg0: !cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef}
-// CIR:   cir.call @user_func(%{{.*}}) : (!cir.ptr<!s32i> {llvm.noalias, 
llvm.noundef}) -> ()
+// CIR:   cir.call @user_func(%{{.*}}) : (!cir.ptr<!s32i> {llvm.noundef}) -> ()
 
 // LLVM: define dso_local void @test_user(ptr noalias noundef %{{.*}})
-// LLVM:   call void @user_func(ptr noalias noundef %{{.*}})
+// LLVM:   call void @user_func(ptr noundef %{{.*}})
 
 // OGCG: define dso_local void @test_user(ptr noalias noundef %{{.*}})
 // OGCG:   call void @user_func(ptr noundef %{{.*}})

>From b53cf838e5f01d764b2485b9b1f8f95b8f860503 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Tue, 14 Apr 2026 11:45:07 -0700
Subject: [PATCH 3/3] Rework restrict->noalias to use ParmVarDecl in zip
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Build a parallel SmallVector of ParmVarDecl pointers aligned with
the argAttrs array, then include it in the zip_equal loop.  This
replaces manual index arithmetic (argNo counter with instance-method
offset) with direct ParmVarDecl access, addressing review feedback
about sidesteping the function's organizational structure.

Also fix stale CIR and LLVM CHECK lines in asm-label-inline-builtins.c
that expected noalias on call sites — call sites do not carry noalias,
only declarations do.

Made-with: Cursor
---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          | 30 +++++++++++--------
 .../CIR/CodeGen/asm-label-inline-builtins.c   |  4 +--
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 277b6c8da2af9..ecc66bbcd90be 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -666,9 +666,19 @@ void CIRGenModule::constructFunctionArgumentAttributes(
   // dereferenceable, nonnull, and align can be combined.
   const cir::CIRDataLayout &layout = getDataLayout();
   const auto *fd = dyn_cast_or_null<FunctionDecl>(targetDecl);
-  unsigned argNo = 0;
-  for (const auto &[argAttrList, argCanType] :
-       llvm::zip_equal(argAttrs, info.arguments())) {
+
+  // Build a parallel array of ParmVarDecls aligned with argAttrs so we can
+  // access parameter-level qualifiers (e.g. restrict) without manual index
+  // arithmetic in the loop.
+  SmallVector<const ParmVarDecl *> parmDecls(argAttrs.size(), nullptr);
+  if (fd) {
+    unsigned offset = info.isInstanceMethod() ? 1 : 0;
+    for (unsigned i = 0; i < fd->getNumParams(); ++i)
+      parmDecls[i + offset] = fd->getParamDecl(i);
+  }
+
+  for (const auto &[argAttrList, argCanType, pvd] :
+       llvm::zip_equal(argAttrs, info.arguments(), parmDecls)) {
     assert(!cir::MissingFeatures::abiArgInfo());
     QualType argType = argCanType;
     const cir::ABIArgInfo argInfo = cir::ABIArgInfo::getDirect();
@@ -702,16 +712,10 @@ void CIRGenModule::constructFunctionArgumentAttributes(
 
     // restrict -> noalias on definitions only (not call sites).  Skip
     // builtins: OGCG applies restrict->noalias in EmitFunctionProlog.
-    if (!attrOnCallSite && fd && argType->isPointerType()) {
-      unsigned srcIdx = info.isInstanceMethod() ? argNo - 1 : argNo;
-      if (srcIdx < fd->getNumParams() &&
-          fd->getParamDecl(srcIdx)->getType().isRestrictQualified() &&
-          !fd->getBuiltinID())
-        argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
-                        mlir::UnitAttr::get(&getMLIRContext()));
-    }
-
-    ++argNo;
+    if (!attrOnCallSite && pvd && pvd->getType()->isPointerType() &&
+        pvd->getType().isRestrictQualified() && !fd->getBuiltinID())
+      argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
+                      mlir::UnitAttr::get(&getMLIRContext()));
   }
 }
 
diff --git a/clang/test/CIR/CodeGen/asm-label-inline-builtins.c 
b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
index 2d11712812dd6..bee255fb149f9 100644
--- a/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
+++ b/clang/test/CIR/CodeGen/asm-label-inline-builtins.c
@@ -32,14 +32,14 @@ void test(const char *fmt, __builtin_va_list ap) {
 }
 
 // CIR: cir.func always_inline internal private 
@__vprintfieee128.inline({{.*}}) -> !s32i
-// CIR:   cir.call @__vfprintf_chkieee128({{.*}}) : (!cir.ptr<!rec__IO_FILE> 
{llvm.noalias, llvm.noundef}, !s32i {llvm.noundef}, !cir.ptr<!s8i> 
{llvm.noalias, llvm.noundef}, !cir.ptr<!rec___va_list_tag> {llvm.noundef}) -> 
!s32i
+// CIR:   cir.call @__vfprintf_chkieee128({{.*}}) : (!cir.ptr<!rec__IO_FILE> 
{llvm.noundef}, !s32i {llvm.noundef}, !cir.ptr<!s8i> {llvm.noundef}, 
!cir.ptr<!rec___va_list_tag> {llvm.noundef}) -> !s32i
 //
 // CIR: cir.func {{.*}} @test({{.*}})
 // CIR:   cir.call @__vprintfieee128.inline(%{{.*}}, %{{.*}})
 
 
 // LLVM: define internal i32 @__vprintfieee128.inline({{.*}}) 
#[[ALWAYS_INLINE_ATTR:.*]] {
-// LLVM:   call i32 @__vfprintf_chkieee128(ptr noalias noundef %{{.*}}, i32 
noundef 1, ptr noalias noundef %{{.*}}, ptr noundef %{{.*}})
+// LLVM:   call i32 @__vfprintf_chkieee128(ptr noundef %{{.*}}, i32 noundef 1, 
ptr noundef %{{.*}}, ptr noundef %{{.*}})
 //
 // LLVM: define {{.*}} void @test{{.*}}
 // LLVM:   call i32 @__vprintfieee128.inline(ptr {{.*}} %{{.*}}, ptr {{.*}} 
%{{.*}})

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to