https://github.com/badumbatish created 
https://github.com/llvm/llvm-project/pull/174832

In CIR, sometimes we create implicit returns in cir but when inspecting the 
CIR, we wouldn't be able to know that the return is implicit. This PR seeks to 
add the extra information to the IR.

Future analysis would benefit from this. For example: checking in CIR whether a 
non-void function returns anything 


>From bd5547ab1b9fed9cd932f2abf875e57c839e1a36 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Mon, 15 Dec 2025 13:14:39 -0800
Subject: [PATCH 1/2] Add implicit return to return op

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp     | 8 ++++----
 clang/lib/CIR/CodeGen/CIRGenFunction.h       | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 8358b076ee7b6..7b4ae2bd51fb7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -714,7 +714,7 @@ def CIR_ReturnOp : CIR_Op<"return", [
 
   // The return operation takes an optional input operand to return. This
   // value must match the return type of the enclosing function.
-  let arguments = (ins Variadic<CIR_AnyType>:$input);
+  let arguments = (ins Variadic<CIR_AnyType>:$input, UnitAttr:$is_implicit);
 
   // The return operation only emits the input in the format if it is present.
   let assemblyFormat = "($input^ `:` type($input))? attr-dict ";
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index ac66d00950f05..48039747d5a33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -352,7 +352,7 @@ void CIRGenFunction::LexicalScope::cleanup() {
   insertCleanupAndLeave(curBlock);
 }
 
-cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
+cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc, 
bool isImplicit) {
   CIRGenBuilderTy &builder = cgf.getBuilder();
 
   // If we are on a coroutine, add the coro_end builtin call.
@@ -365,9 +365,9 @@ cir::ReturnOp 
CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
     auto value = cir::LoadOp::create(
         builder, loc, fn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);
     return cir::ReturnOp::create(builder, loc,
-                                 llvm::ArrayRef(value.getResult()));
+                                 llvm::ArrayRef(value.getResult()), 
isImplicit);
   }
-  return cir::ReturnOp::create(builder, loc);
+  return cir::ReturnOp::create(builder, loc, {}, isImplicit);
 }
 
 // This is copied from CodeGenModule::MayDropFunctionReturn.  This is a
@@ -410,7 +410,7 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
     }
   }
 
-  (void)emitReturn(localScope->endLoc);
+  (void)emitReturn(localScope->endLoc, /*isImplicit=*/true);
 }
 
 cir::TryOp CIRGenFunction::LexicalScope::getClosestTryParent() {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 49ebccc221950..721f4fd9622b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1206,7 +1206,7 @@ class CIRGenFunction : public CIRGenTypeCache {
       return b;
     }
 
-    cir::ReturnOp emitReturn(mlir::Location loc);
+    cir::ReturnOp emitReturn(mlir::Location loc, bool isImplicit = false);
     void emitImplicitReturn();
 
   public:

>From 02cd548294b05d4ccec6ef1eb29ad82525032732 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <[email protected]>
Date: Wed, 7 Jan 2026 10:57:10 -0800
Subject: [PATCH 2/2] Update test case

---
 clang/test/CIR/CodeGen/basic.c              | 10 +++++-----
 clang/test/CIR/CodeGen/loop.cpp             |  6 +++---
 clang/test/CIR/CodeGen/member-functions.cpp |  6 +++---
 clang/test/CIR/CodeGen/nullptr-init.cpp     |  2 +-
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
index 9268615bc9fb0..b2e180bcca1f1 100644
--- a/clang/test/CIR/CodeGen/basic.c
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -94,7 +94,7 @@ int f3(void) {
 // CIR-NEXT:   %[[I:.*]] = cir.load{{.*}} %[[I_PTR]] : !cir.ptr<!s32i>, !s32i
 // CIR-NEXT:   cir.store{{.*}} %[[I]], %[[RV]] : !s32i, !cir.ptr<!s32i>
 // CIR-NEXT:   %[[R:.*]] = cir.load{{.*}} %[[RV]] : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT:   cir.return %[[R]] : !s32i
+// CIR-NEXT:   cir.return  %[[R]] : !s32i
 
 //      LLVM: define{{.*}} i32 @f3()
 // LLVM-NEXT:   %[[RV:.*]] = alloca i32, i64 1, align 4
@@ -118,7 +118,7 @@ void f4(void) {
 }
 
 //      CIR: cir.func{{.*}} @f4()
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 
 //      LLVM: define{{.*}} void @f4()
 // LLVM-NEXT:   ret void
@@ -144,7 +144,7 @@ void f5(void) {
 // CIR-NEXT:        cir.yield
 // CIR-NEXT:      }
 // CIR-NEXT:   }
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
 
 // LLVM: define{{.*}} void @f5()
@@ -258,7 +258,7 @@ int f8(int *p) {
 void f9() {}
 
 //      CIR: cir.func{{.*}} @f9()
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 
 //      LLVM: define{{.*}} void @f9()
 // LLVM-NEXT:   ret void
@@ -272,7 +272,7 @@ void f10(int arg0, ...) {}
 //      CIR: cir.func{{.*}} @f10(%[[ARG0:.*]]: !s32i loc({{.*}}), ...)
 // CIR-NEXT:   %[[ARG0_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["arg0", 
init] {alignment = 4 : i64}
 // CIR-NEXT:   cir.store{{.*}} %[[ARG0]], %[[ARG0_PTR]] : !s32i, 
!cir.ptr<!s32i>
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 
 //      LLVM: define{{.*}} void @f10(i32 %[[ARG0:.*]], ...)
 // LLVM-NEXT:   %[[ARG0_PTR:.*]] = alloca i32, i64 1, align 4
diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp
index 463434c38a1af..61713f60cb101 100644
--- a/clang/test/CIR/CodeGen/loop.cpp
+++ b/clang/test/CIR/CodeGen/loop.cpp
@@ -64,7 +64,7 @@ void l1() {
 // CIR-NEXT:       cir.yield
 // CIR-NEXT:     }
 // CIR-NEXT:   }
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
 
 // LLVM: define{{.*}} void @_Z2l1v(){{.*}}
@@ -114,7 +114,7 @@ void l2() {
 // CIR-NEXT:       cir.yield
 // CIR-NEXT:     }
 // CIR-NEXT:   }
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
 
 // LLVM: define{{.*}} void @_Z2l2v(){{.*}}
@@ -162,7 +162,7 @@ void l3() {
 // CIR-NEXT:       cir.yield
 // CIR-NEXT:     }
 // CIR-NEXT:   }
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
 
 // LLVM: define{{.*}} void @_Z2l3v(){{.*}}
diff --git a/clang/test/CIR/CodeGen/member-functions.cpp 
b/clang/test/CIR/CodeGen/member-functions.cpp
index d46345dbadd6d..f60a838075749 100644
--- a/clang/test/CIR/CodeGen/member-functions.cpp
+++ b/clang/test/CIR/CodeGen/member-functions.cpp
@@ -14,7 +14,7 @@ void C::f() {}
 // CIR:   %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, 
!cir.ptr<!cir.ptr<!rec_C>>, ["this", init]
 // CIR:   cir.store %[[THIS_ARG]], %[[THIS_ADDR]] : !cir.ptr<!rec_C>, 
!cir.ptr<!cir.ptr<!rec_C>>
 // CIR:   %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_C>>, 
!cir.ptr<!rec_C>
-// CIR:   cir.return
+// CIR:   cir.return {is_implicit}
 // CIR: }
 
 void C::f2(int a, int b) {}
@@ -27,7 +27,7 @@ void C::f2(int a, int b) {}
 // CIR-NEXT:   cir.store %[[A_ARG]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>
 // CIR-NEXT:   cir.store %[[B_ARG]], %[[B_ADDR]] : !s32i, !cir.ptr<!s32i>
 // CIR-NEXT:   %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : 
!cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
 
 void test1() {
@@ -42,5 +42,5 @@ void test1() {
 // CIR-NEXT:   %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
 // CIR-NEXT:   %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
 // CIR-NEXT:   cir.call @_ZN1C2f2Eii(%[[C_ADDR]], %[[ONE]], %[[TWO]]) : 
(!cir.ptr<!rec_C>, !s32i, !s32i) -> ()
-// CIR-NEXT:   cir.return
+// CIR-NEXT:   cir.return {is_implicit}
 // CIR-NEXT: }
diff --git a/clang/test/CIR/CodeGen/nullptr-init.cpp 
b/clang/test/CIR/CodeGen/nullptr-init.cpp
index 091269d09c985..73b01d4cad6b4 100644
--- a/clang/test/CIR/CodeGen/nullptr-init.cpp
+++ b/clang/test/CIR/CodeGen/nullptr-init.cpp
@@ -21,7 +21,7 @@ void t1() {
 // CIR-NEXT:     cir.store{{.*}} %[[NULLPTR2]], %[[P2]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
 // CIR-NEXT:     %[[NULLPTR3:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
 // CIR-NEXT:     cir.store{{.*}} %[[NULLPTR3]], %[[P3]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
-// CIR-NEXT:     cir.return
+// CIR-NEXT:     cir.return {is_implicit}
 // CIR-NEXT: }
 
 // LLVM:      define{{.*}} @_Z2t1v()

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

Reply via email to