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

>From 4f400f1cf35c8db55c43e3e3d8d422d8fe5be856 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Fri, 5 Dec 2025 10:26:19 -0800
Subject: [PATCH 1/2] Add Function Argument Demotion support

This commit migrates the Function Argument Demotion feature from
the incubator repository to upstream. The feature handles K&R-style
function parameters that are promoted (e.g., short->int, float->double)
and demotes them back to their declared types.

Changes:
- Add emitArgumentDemotion helper function for type demotion
- Create emitFunctionProlog function to handle function prologue setup
  (addresses existing TODO to move parameter handling logic)
- Move parameter handling logic into emitFunctionProlog
- Add test case kr-func-promote.c to verify the feature

Tested: All CIR tests pass (320/321, 99.69%). The one unsupported
test is an expected failure.
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 62 +++++++++++++++++-------
 clang/lib/CIR/CodeGen/CIRGenFunction.h   |  4 ++
 clang/test/CIR/CodeGen/kr-func-promote.c | 13 +++++
 3 files changed, 61 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/kr-func-promote.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 5d5209b9ffb60..10c4a16fb9687 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -412,28 +412,30 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
   (void)emitReturn(localScope->endLoc);
 }
 
-void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
-                                   cir::FuncOp fn, cir::FuncType funcType,
-                                   FunctionArgList args, SourceLocation loc,
-                                   SourceLocation startLoc) {
-  assert(!curFn &&
-         "CIRGenFunction can only be used for one function at a time");
+/// An argument came in as a promoted argument; demote it back to its
+/// declared type.
+static mlir::Value emitArgumentDemotion(CIRGenFunction &cgf, const VarDecl 
*var,
+                                        mlir::Value value) {
+  mlir::Type ty = cgf.convertType(var->getType());
 
-  curFn = fn;
+  // This can happen with promotions that actually don't change the
+  // underlying type, like the enum promotions.
+  if (value.getType() == ty)
+    return value;
 
-  const Decl *d = gd.getDecl();
-
-  didCallStackSave = false;
-  curCodeDecl = d;
-  const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
-  curFuncDecl = d->getNonClosureContext();
+  assert((mlir::isa<cir::IntType>(ty) || cir::isAnyFloatingPointType(ty)) &&
+         "unexpected promotion type");
 
-  prologueCleanupDepth = ehStack.stable_begin();
+  if (mlir::isa<cir::IntType>(ty))
+    return cgf.getBuilder().CIRBaseBuilderTy::createIntCast(value, ty);
 
-  mlir::Block *entryBB = &fn.getBlocks().front();
-  builder.setInsertionPointToStart(entryBB);
+  return cgf.getBuilder().CIRBaseBuilderTy::createCast(cir::CastKind::floating,
+                                                       value, ty);
+}
 
-  // TODO(cir): this should live in `emitFunctionProlog
+void CIRGenFunction::emitFunctionProlog(const FunctionArgList &args,
+                                        mlir::Block *entryBB,
+                                        const FunctionDecl *fd) {
   // Declare all the function arguments in the symbol table.
   for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
     const VarDecl *paramVar = std::get<0>(nameValue);
@@ -456,7 +458,7 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
                       cast<ParmVarDecl>(paramVar)->isKNRPromoted();
     assert(!cir::MissingFeatures::constructABIArgDirectExtend());
     if (isPromoted)
-      cgm.errorNYI(fd->getSourceRange(), "Function argument demotion");
+      paramVal = emitArgumentDemotion(*this, paramVar, paramVal);
 
     // Location of the store to the param storage tracked as beginning of
     // the function body.
@@ -464,6 +466,30 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
     builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);
   }
   assert(builder.getInsertionBlock() && "Should be valid");
+}
+
+void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
+                                   cir::FuncOp fn, cir::FuncType funcType,
+                                   FunctionArgList args, SourceLocation loc,
+                                   SourceLocation startLoc) {
+  assert(!curFn &&
+         "CIRGenFunction can only be used for one function at a time");
+
+  curFn = fn;
+
+  const Decl *d = gd.getDecl();
+
+  didCallStackSave = false;
+  curCodeDecl = d;
+  const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
+  curFuncDecl = d->getNonClosureContext();
+
+  prologueCleanupDepth = ehStack.stable_begin();
+
+  mlir::Block *entryBB = &fn.getBlocks().front();
+  builder.setInsertionPointToStart(entryBB);
+
+  emitFunctionProlog(args, entryBB, fd);
 
   // When the current function is not void, create an address to store the
   // result value.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index e5cecaa573a6e..7ce7998825b18 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -901,6 +901,10 @@ class CIRGenFunction : public CIRGenTypeCache {
   clang::QualType buildFunctionArgList(clang::GlobalDecl gd,
                                        FunctionArgList &args);
 
+  /// Emit the function prologue: declare function arguments in the symbol 
table.
+  void emitFunctionProlog(const FunctionArgList &args, mlir::Block *entryBB,
+                          const FunctionDecl *fd);
+
   /// Emit code for the start of a function.
   /// \param loc       The location to be associated with the function.
   /// \param startLoc  The location of the function body.
diff --git a/clang/test/CIR/CodeGen/kr-func-promote.c 
b/clang/test/CIR/CodeGen/kr-func-promote.c
new file mode 100644
index 0000000000000..f34e11ce3e9e1
--- /dev/null
+++ b/clang/test/CIR/CodeGen/kr-func-promote.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
- | FileCheck %s
+
+// CHECK: cir.func {{.*}}@foo(%arg0: !s32i
+// CHECK:   %0 = cir.alloca !s16i, !cir.ptr<!s16i>, ["x", init]
+// CHECK:   %1 = cir.cast integral %arg0 : !s32i -> !s16i
+// CHECK:   cir.store %1, %0 : !s16i, !cir.ptr<!s16i>
+void foo(x) short x; {}
+
+// CHECK: cir.func no_proto dso_local @bar(%arg0: !cir.double
+// CHECK:   %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["f", init]
+// CHECK:   %1 = cir.cast floating %arg0 : !cir.double -> !cir.float
+// CHECK:   cir.store %1, %0 : !cir.float, !cir.ptr<!cir.float>
+void bar(f) float f; {}

>From 813701df6334a4492a65a790d204203b647d8b98 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Fri, 5 Dec 2025 13:58:42 -0800
Subject: [PATCH 2/2] Fix null pointer dereference in emitFunctionProlog

The emitFunctionProlog function was dereferencing fd->getBody()
unconditionally without checking if fd is null or if getBody()
returns null. Similarly, startFunction was dereferencing
fd->getBody()->getEndLoc() without null checks.

Fix by:
- Adding SourceLocation bodyBeginLoc parameter to emitFunctionProlog
- Computing bodyBeginLoc safely in startFunction with null checks
- Computing bodyEndLoc safely in startFunction with null checks
- Using fallback locations (startLoc/loc) when fd is null or has no body

This prevents crashes when fd is null (e.g., for non-function
declarations) or when the function has no body (declaration only).
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 31 ++++++++++++++++++++----
 clang/lib/CIR/CodeGen/CIRGenFunction.h   |  2 +-
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 10c4a16fb9687..65a51e865bdbd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -435,7 +435,8 @@ static mlir::Value emitArgumentDemotion(CIRGenFunction 
&cgf, const VarDecl *var,
 
 void CIRGenFunction::emitFunctionProlog(const FunctionArgList &args,
                                         mlir::Block *entryBB,
-                                        const FunctionDecl *fd) {
+                                        const FunctionDecl *fd,
+                                        SourceLocation bodyBeginLoc) {
   // Declare all the function arguments in the symbol table.
   for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
     const VarDecl *paramVar = std::get<0>(nameValue);
@@ -462,7 +463,7 @@ void CIRGenFunction::emitFunctionProlog(const 
FunctionArgList &args,
 
     // Location of the store to the param storage tracked as beginning of
     // the function body.
-    mlir::Location fnBodyBegin = getLoc(fd->getBody()->getBeginLoc());
+    mlir::Location fnBodyBegin = getLoc(bodyBeginLoc);
     builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);
   }
   assert(builder.getInsertionBlock() && "Should be valid");
@@ -489,13 +490,33 @@ void CIRGenFunction::startFunction(GlobalDecl gd, 
QualType returnType,
   mlir::Block *entryBB = &fn.getBlocks().front();
   builder.setInsertionPointToStart(entryBB);
 
-  emitFunctionProlog(args, entryBB, fd);
+  // Determine the function body begin location for the prolog.
+  // If fd is null or has no body, use startLoc as fallback.
+  SourceLocation bodyBeginLoc = startLoc;
+  if (fd) {
+    if (Stmt *body = fd->getBody())
+      bodyBeginLoc = body->getBeginLoc();
+    else
+      bodyBeginLoc = fd->getLocation();
+  }
+
+  emitFunctionProlog(args, entryBB, fd, bodyBeginLoc);
 
   // When the current function is not void, create an address to store the
   // result value.
-  if (!returnType->isVoidType())
-    emitAndUpdateRetAlloca(returnType, getLoc(fd->getBody()->getEndLoc()),
+  if (!returnType->isVoidType()) {
+    // Determine the function body end location.
+    // If fd is null or has no body, use loc as fallback.
+    SourceLocation bodyEndLoc = loc;
+    if (fd) {
+      if (Stmt *body = fd->getBody())
+        bodyEndLoc = body->getEndLoc();
+      else
+        bodyEndLoc = fd->getLocation();
+    }
+    emitAndUpdateRetAlloca(returnType, getLoc(bodyEndLoc),
                            getContext().getTypeAlignInChars(returnType));
+  }
 
   if (isa_and_nonnull<CXXMethodDecl>(d) &&
       cast<CXXMethodDecl>(d)->isInstance()) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 7ce7998825b18..cb6399a322faf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -903,7 +903,7 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   /// Emit the function prologue: declare function arguments in the symbol 
table.
   void emitFunctionProlog(const FunctionArgList &args, mlir::Block *entryBB,
-                          const FunctionDecl *fd);
+                          const FunctionDecl *fd, SourceLocation bodyBeginLoc);
 
   /// Emit code for the start of a function.
   /// \param loc       The location to be associated with the function.

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

Reply via email to