https://github.com/dkolsen-pgi updated 
https://github.com/llvm/llvm-project/pull/131945

>From ef54ceca65c8a62544651cbbd30967efc7adec36 Mon Sep 17 00:00:00 2001
From: David Olsen <dol...@nvidia.com>
Date: Tue, 18 Mar 2025 17:37:26 -0700
Subject: [PATCH 1/2] [CIR] Upstream a basic version of class LexicalScope

Upstream the parts of class `CIRGenFunction::LexicalScope` that
implement function return values.  There is a bit of other functionality
in here, such as the implicit `cir.yield` at the end of a non-function
scope, but this is mostly about function returns.

The parts of `LexicalScope` that handle calling destructors, switch
statements, ternary expressions, and exception handling still need to be
upstreamed.

There is a change in the generated ClangIR (which is why many of the
tests needed updating).  Return values are stored in the
compiler-generated variable `__retval` rather than being passed to the
`cir.return` op directly.  But there should be no change in the behavior
of the generated code.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |  16 ++
 clang/include/clang/CIR/MissingFeatures.h    |   1 +
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp     | 219 +++++++++++++++----
 clang/lib/CIR/CodeGen/CIRGenFunction.h       | 156 ++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp         |  33 ++-
 clang/test/CIR/CodeGen/basic.c               |  46 +++-
 clang/test/CIR/CodeGen/basic.cpp             |  20 +-
 clang/test/CIR/CodeGen/cast.cpp              |   9 +-
 clang/test/CIR/CodeGen/unary.cpp             |  15 ++
 clang/test/CIR/Lowering/basic.cpp            |  20 +-
 clang/test/CIR/Lowering/func-simple.cpp      |  51 +++--
 clang/test/CIR/func-simple.cpp               |  74 +++++--
 12 files changed, 544 insertions(+), 116 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2a5caf1bf1f63..352d72ff31a8a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -832,6 +832,22 @@ def FuncOp : CIR_Op<"func", [
   let hasVerifier = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// UnreachableOp
+//===----------------------------------------------------------------------===//
+
+def UnreachableOp : CIR_Op<"unreachable", [Terminator]> {
+  let summary = "invoke immediate undefined behavior";
+  let description = [{
+    If the program control flow reaches a `cir.unreachable` operation, the
+    program exhibits undefined behavior immediately. This operation is useful
+    in cases where the unreachability of a program point needs to be explicitly
+    marked.
+  }];
+
+  let assemblyFormat = "attr-dict";
+}
+
 
//===----------------------------------------------------------------------===//
 // TrapOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 6adff30f5c91a..e37bff1f548c9 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -89,6 +89,7 @@ struct MissingFeatures {
   static bool astVarDeclInterface() { return false; }
   static bool stackSaveOp() { return false; }
   static bool aggValueSlot() { return false; }
+  static bool generateDebugInfo() { return false; }
 
   static bool fpConstraints() { return false; }
   static bool sanitizers() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 2338ec9cd952a..5685339c9e637 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -135,6 +135,13 @@ mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, 
mlir::Location rhs) {
   return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());
 }
 
+void CIRGenFunction::emitAndUpdateRetAlloca(QualType type, mlir::Location loc,
+                                            CharUnits alignment) {
+  if (!type->isVoidType()) {
+    fnRetAlloca = emitAlloca("__retval", convertType(type), loc, alignment);
+  }
+}
+
 void CIRGenFunction::declare(mlir::Value addrVal, const Decl *var, QualType ty,
                              mlir::Location loc, CharUnits alignment,
                              bool isParam) {
@@ -149,6 +156,118 @@ void CIRGenFunction::declare(mlir::Value addrVal, const 
Decl *var, QualType ty,
     allocaOp.setConstantAttr(mlir::UnitAttr::get(&getMLIRContext()));
 }
 
+void CIRGenFunction::LexicalScope::cleanup() {
+  CIRGenBuilderTy &builder = cgf.builder;
+  LexicalScope *localScope = cgf.currLexScope;
+
+  if (returnBlock != nullptr) {
+    // Write out the return block, which loads the value from `__retval` and
+    // issues the `cir.return`.
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToEnd(returnBlock);
+    (void)emitReturn(*returnLoc);
+  }
+
+  mlir::Block *currBlock = builder.getBlock();
+  if (isGlobalInit() && !currBlock)
+    return;
+  if (currBlock->mightHaveTerminator() && currBlock->getTerminator())
+    return;
+
+  // Get rid of any empty block at the end of the scope.
+  bool entryBlock = builder.getInsertionBlock()->isEntryBlock();
+  if (!entryBlock && currBlock->empty()) {
+    currBlock->erase();
+    if (returnBlock != nullptr && returnBlock->getUses().empty())
+      returnBlock->erase();
+    return;
+  }
+
+  // Reached the end of the scope.
+  {
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToEnd(currBlock);
+
+    if (localScope->depth == 0) {
+      // Reached the end of the function.
+      if (returnBlock != nullptr) {
+        if (returnBlock->getUses().empty())
+          returnBlock->erase();
+        else {
+          builder.create<cir::BrOp>(*returnLoc, returnBlock);
+          return;
+        }
+      }
+      emitImplicitReturn();
+      return;
+    }
+    // Reached the end of a non-function scope.  Some scopes, such as those
+    // used with the ?: operator, can return a value.
+    if (!localScope->isTernary() && !currBlock->mightHaveTerminator()) {
+      !retVal ? builder.create<cir::YieldOp>(localScope->endLoc)
+              : builder.create<cir::YieldOp>(localScope->endLoc, retVal);
+    }
+  }
+}
+
+cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+
+  if (!cgf.curFn.getFunctionType().hasVoidReturn()) {
+    // Load the value from `__retval` and return it via the `cir.return` op.
+    auto value = builder.create<cir::LoadOp>(
+        loc, cgf.curFn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);
+    return builder.create<cir::ReturnOp>(loc,
+                                         llvm::ArrayRef(value.getResult()));
+  }
+  return builder.create<cir::ReturnOp>(loc);
+}
+
+// This is copyied from CodeGenModule::MayDropFunctionReturn.  This is a
+// candidate for sharing between CIRGen and CodeGen.
+static bool mayDropFunctionReturn(const ASTContext &astContext,
+                                  QualType returnType) {
+  // We can't just discard the return value for a record type with a complex
+  // destructor or a non-trivially copyable type.
+  if (const RecordType *recordType =
+          returnType.getCanonicalType()->getAs<RecordType>()) {
+    if (const auto *classDecl = dyn_cast<CXXRecordDecl>(recordType->getDecl()))
+      return classDecl->hasTrivialDestructor();
+  }
+  return returnType.isTriviallyCopyableType(astContext);
+}
+
+void CIRGenFunction::LexicalScope::emitImplicitReturn() {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  LexicalScope *localScope = cgf.currLexScope;
+
+  const auto *fd = cast<clang::FunctionDecl>(cgf.curGD.getDecl());
+
+  // In C++, flowing off the end of a non-void function is always undefined
+  // behavior. In C, flowing off the end of a non-void function is undefined
+  // behavior only if the non-existent return value is used by the caller.
+  // That influences whether the terminating op is trap, unreachable, or
+  // return.
+  if (cgf.getLangOpts().CPlusPlus && !fd->hasImplicitReturnZero() &&
+      !cgf.sawAsmBlock && !fd->getReturnType()->isVoidType() &&
+      builder.getInsertionBlock()) {
+    bool shouldEmitUnreachable =
+        cgf.cgm.getCodeGenOpts().StrictReturn ||
+        !mayDropFunctionReturn(fd->getASTContext(), fd->getReturnType());
+
+    if (shouldEmitUnreachable) {
+      if (cgf.cgm.getCodeGenOpts().OptimizationLevel == 0)
+        builder.create<cir::TrapOp>(localScope->endLoc);
+      else
+        builder.create<cir::UnreachableOp>(localScope->endLoc);
+      builder.clearInsertionPoint();
+      return;
+    }
+  }
+
+  (void)emitReturn(localScope->endLoc);
+}
+
 void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
                                    cir::FuncOp fn, cir::FuncType funcType,
                                    FunctionArgList args, SourceLocation loc,
@@ -156,7 +275,6 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
   assert(!curFn &&
          "CIRGenFunction can only be used for one function at a time");
 
-  fnRetTy = returnType;
   curFn = fn;
 
   const auto *fd = dyn_cast_or_null<FunctionDecl>(gd.getDecl());
@@ -194,6 +312,12 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
     builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);
   }
   assert(builder.getInsertionBlock() && "Should be valid");
+
+  // When the current function is not void, create an address to store the
+  // result value.
+  if (!returnType->isVoidType())
+    emitAndUpdateRetAlloca(returnType, getLoc(fd->getBody()->getEndLoc()),
+                           getContext().getTypeAlignInChars(returnType));
 }
 
 void CIRGenFunction::finishFunction(SourceLocation endLoc) {}
@@ -208,9 +332,24 @@ mlir::LogicalResult CIRGenFunction::emitFunctionBody(const 
clang::Stmt *body) {
   return result;
 }
 
+static void eraseEmptyAndUnusedBlocks(cir::FuncOp func) {
+  // Remove any leftover blocks that are unreachable and empty, since they do
+  // not represent unreachable code useful for warnings nor anything deemed
+  // useful in general.
+  SmallVector<mlir::Block *> blocksToDelete;
+  for (mlir::Block &block : func.getBlocks()) {
+    if (block.empty() && block.getUses().empty())
+      blocksToDelete.push_back(&block);
+  }
+  for (mlir::Block *block : blocksToDelete)
+    block->erase();
+}
+
 cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
                                          cir::FuncType funcType) {
   const auto funcDecl = cast<FunctionDecl>(gd.getDecl());
+  curGD = gd;
+
   SourceLocation loc = funcDecl->getLocation();
   Stmt *body = funcDecl->getBody();
   SourceRange bodyRange =
@@ -219,55 +358,53 @@ cir::FuncOp 
CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
   SourceLocRAIIObject fnLoc{*this, loc.isValid() ? getLoc(loc)
                                                  : builder.getUnknownLoc()};
 
-  // This will be used once more code is upstreamed.
-  [[maybe_unused]] mlir::Block *entryBB = fn.addEntryBlock();
+  auto validMLIRLoc = [&](clang::SourceLocation clangLoc) {
+    return clangLoc.isValid() ? getLoc(clangLoc) : builder.getUnknownLoc();
+  };
+  const mlir::Location fusedLoc = mlir::FusedLoc::get(
+      &getMLIRContext(),
+      {validMLIRLoc(bodyRange.getBegin()), validMLIRLoc(bodyRange.getEnd())});
+  mlir::Block *entryBB = fn.addEntryBlock();
 
   FunctionArgList args;
   QualType retTy = buildFunctionArgList(gd, args);
 
-  startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
-
-  if (isa<CXXDestructorDecl>(funcDecl))
-    getCIRGenModule().errorNYI(bodyRange, "C++ destructor definition");
-  else if (isa<CXXConstructorDecl>(funcDecl))
-    getCIRGenModule().errorNYI(bodyRange, "C++ constructor definition");
-  else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice &&
-           funcDecl->hasAttr<CUDAGlobalAttr>())
-    getCIRGenModule().errorNYI(bodyRange, "CUDA kernel");
-  else if (isa<CXXMethodDecl>(funcDecl) &&
-           cast<CXXMethodDecl>(funcDecl)->isLambdaStaticInvoker())
-    getCIRGenModule().errorNYI(bodyRange, "Lambda static invoker");
-  else if (funcDecl->isDefaulted() && isa<CXXMethodDecl>(funcDecl) &&
-           (cast<CXXMethodDecl>(funcDecl)->isCopyAssignmentOperator() ||
-            cast<CXXMethodDecl>(funcDecl)->isMoveAssignmentOperator()))
-    getCIRGenModule().errorNYI(bodyRange, "Default assignment operator");
-  else if (body) {
-    if (mlir::failed(emitFunctionBody(body))) {
-      fn.erase();
-      return nullptr;
-    }
-  } else
-    llvm_unreachable("no definition for normal function");
-
-  // This code to insert a cir.return or cir.trap at the end of the function is
-  // temporary until the function return code, including
-  // CIRGenFunction::LexicalScope::emitImplicitReturn(), is upstreamed.
-  mlir::Block &lastBlock = fn.getRegion().back();
-  if (lastBlock.empty() || !lastBlock.mightHaveTerminator() ||
-      !lastBlock.getTerminator()->hasTrait<mlir::OpTrait::IsTerminator>()) {
-    builder.setInsertionPointToEnd(&lastBlock);
-    if (mlir::isa<cir::VoidType>(funcType.getReturnType())) {
-      builder.create<cir::ReturnOp>(getLoc(bodyRange.getEnd()));
+  {
+    LexicalScope lexScope(*this, fusedLoc, entryBB);
+
+    startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
+
+    if (isa<CXXDestructorDecl>(funcDecl))
+      getCIRGenModule().errorNYI(bodyRange, "C++ destructor definition");
+    else if (isa<CXXConstructorDecl>(funcDecl))
+      getCIRGenModule().errorNYI(bodyRange, "C++ constructor definition");
+    else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice &&
+             funcDecl->hasAttr<CUDAGlobalAttr>())
+      getCIRGenModule().errorNYI(bodyRange, "CUDA kernel");
+    else if (isa<CXXMethodDecl>(funcDecl) &&
+             cast<CXXMethodDecl>(funcDecl)->isLambdaStaticInvoker())
+      getCIRGenModule().errorNYI(bodyRange, "Lambda static invoker");
+    else if (funcDecl->isDefaulted() && isa<CXXMethodDecl>(funcDecl) &&
+             (cast<CXXMethodDecl>(funcDecl)->isCopyAssignmentOperator() ||
+              cast<CXXMethodDecl>(funcDecl)->isMoveAssignmentOperator()))
+      getCIRGenModule().errorNYI(bodyRange, "Default assignment operator");
+    else if (body) {
+      if (mlir::failed(emitFunctionBody(body))) {
+        fn.erase();
+        return nullptr;
+      }
     } else {
-      builder.create<cir::TrapOp>(getLoc(bodyRange.getEnd()));
+      // Anything without a body should have been handled above.
+      llvm_unreachable("no definition for normal function");
     }
-  }
 
-  if (mlir::failed(fn.verifyBody()))
-    return nullptr;
+    if (mlir::failed(fn.verifyBody()))
+      return nullptr;
 
-  finishFunction(bodyRange.getEnd());
+    finishFunction(bodyRange.getEnd());
+  }
 
+  eraseEmptyAndUnusedBlocks(fn);
   return fn;
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index f931da32d51db..b52f5ec734f70 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -49,11 +49,15 @@ class CIRGenFunction : public CIRGenTypeCache {
   CIRGenBuilderTy &builder;
 
 public:
-  clang::QualType fnRetTy;
+  /// The GlobalDecl for the current function being compiled or the global
+  /// variable currently being initialized.
+  clang::GlobalDecl curGD;
 
-  /// This is the current function or global initializer that is generated code
-  /// for.
-  mlir::Operation *curFn = nullptr;
+  /// The compiler-generated variable that holds the return value.
+  std::optional<mlir::Value> fnRetAlloca;
+
+  /// The function for which code is currently being generated.
+  cir::FuncOp curFn;
 
   using DeclMapTy = llvm::DenseMap<const clang::Decl *, Address>;
   /// This keeps track of the CIR allocas or globals for local C
@@ -67,15 +71,15 @@ class CIRGenFunction : public CIRGenTypeCache {
   CIRGenModule &getCIRGenModule() { return cgm; }
   const CIRGenModule &getCIRGenModule() const { return cgm; }
 
-  mlir::Block *getCurFunctionEntryBlock() {
-    auto fn = mlir::dyn_cast<cir::FuncOp>(curFn);
-    assert(fn && "other callables NYI");
-    return &fn.getRegion().front();
-  }
+  mlir::Block *getCurFunctionEntryBlock() { return &curFn.getRegion().front(); 
}
 
   /// Sanitizers enabled for this function.
   clang::SanitizerSet sanOpts;
 
+  /// Whether or not a Microsoft-style asm block has been processed within
+  /// this fuction. These can potentially set the return value.
+  bool sawAsmBlock = false;
+
   mlir::Type convertTypeForMem(QualType T);
 
   mlir::Type convertType(clang::QualType T);
@@ -131,6 +135,9 @@ class CIRGenFunction : public CIRGenTypeCache {
     ~VarDeclContext() { restore(); }
   };
 
+  void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc,
+                              clang::CharUnits alignment);
+
 public:
   /// Use to track source locations across nested visitor traversals.
   /// Always use a `SourceLocRAIIObject` to change currSrcLoc.
@@ -330,9 +337,140 @@ class CIRGenFunction : public CIRGenTypeCache {
                      FunctionArgList args, clang::SourceLocation loc,
                      clang::SourceLocation startLoc);
 
+  /// Represents a scope, including function bodies, compound statements, and
+  /// the substatements of if/while/do/for/switch/try statements.  This class
+  /// handles any automatic cleanup, along with the return value.
+  struct LexicalScope {
+  private:
+    // TODO(CIR): This will live in the base class RunCleanupScope once that
+    // class is upstreamed.
+    CIRGenFunction &cgf;
+
+    // Block containing cleanup code for things initialized in this lexical
+    // context (scope).
+    mlir::Block *cleanupBlock = nullptr;
+
+    // Points to the scope entry block. This is useful, for instance, for
+    // helping to insert allocas before finalizing any recursive CodeGen from
+    // switches.
+    mlir::Block *entryBlock;
+
+    LexicalScope *parentScope = nullptr;
+
+    // Only Regular is used at the moment. Support for other kinds will be
+    // added as the relevant statements/expressions are upstreamed.
+    enum Kind {
+      Regular,   // cir.if, cir.scope, if_regions
+      Ternary,   // cir.ternary
+      Switch,    // cir.switch
+      Try,       // cir.try
+      GlobalInit // cir.global initialization code
+    };
+    Kind scopeKind = Kind::Regular;
+
+    // The scope return value.
+    mlir::Value retVal = nullptr;
+
+    mlir::Location beginLoc;
+    mlir::Location endLoc;
+
+  public:
+    unsigned depth = 0;
+
+    LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb)
+        : cgf(cgf), entryBlock(eb), parentScope(cgf.currLexScope),
+          beginLoc(loc), endLoc(loc) {
+
+      assert(entryBlock && "LexicalScope requires an entry block");
+      cgf.currLexScope = this;
+      if (parentScope)
+        ++depth;
+
+      if (const auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc)) {
+        assert(fusedLoc.getLocations().size() == 2 && "too many locations");
+        beginLoc = fusedLoc.getLocations()[0];
+        endLoc = fusedLoc.getLocations()[1];
+      }
+    }
+
+    void setRetVal(mlir::Value v) { retVal = v; }
+
+    void cleanup();
+    void restore() { cgf.currLexScope = parentScope; }
+
+    ~LexicalScope() {
+      assert(!cir::MissingFeatures::generateDebugInfo());
+      cleanup();
+      restore();
+    }
+
+    // ---
+    // Kind
+    // ---
+    bool isGlobalInit() { return scopeKind == Kind::GlobalInit; }
+    bool isRegular() { return scopeKind == Kind::Regular; }
+    bool isSwitch() { return scopeKind == Kind::Switch; }
+    bool isTernary() { return scopeKind == Kind::Ternary; }
+    bool isTry() { return scopeKind == Kind::Try; }
+
+    void setAsGlobalInit() { scopeKind = Kind::GlobalInit; }
+    void setAsSwitch() { scopeKind = Kind::Switch; }
+    void setAsTernary() { scopeKind = Kind::Ternary; }
+
+    // ---
+    // Return handling.
+    // ---
+
+  private:
+    // `returnBlock`, `returnLoc`, and all the functions that deal with them
+    // will change and become more complicated when `switch` statements are
+    // upstreamed.  `case` statements within the `switch` are in the same scope
+    // but have their own regions.  Therefore the LexicalScope will need to
+    // keep track of multiple return blocks.
+    mlir::Block *returnBlock = nullptr;
+    std::optional<mlir::Location> returnLoc;
+
+    // See the comment on `getOrCreateRetBlock`.
+    mlir::Block *createRetBlock(CIRGenFunction &cgf, mlir::Location loc) {
+      assert(returnBlock == nullptr && "only one return block per scope");
+      // Create the cleanup block but don't hook it up just yet.
+      mlir::OpBuilder::InsertionGuard guard(cgf.builder);
+      returnBlock =
+          cgf.builder.createBlock(cgf.builder.getBlock()->getParent());
+      updateRetLoc(returnBlock, loc);
+      return returnBlock;
+    }
+
+    cir::ReturnOp emitReturn(mlir::Location loc);
+    void emitImplicitReturn();
+
+  public:
+    mlir::Block *getRetBlock() { return returnBlock; }
+    mlir::Location getRetLoc(mlir::Block *b) { return *returnLoc; }
+    void updateRetLoc(mlir::Block *b, mlir::Location loc) { returnLoc = loc; }
+
+    // Create the return block for this scope, or return the existing one.
+    // This get-or-create logic is necessary to handle multiple return
+    // statements within the same scope, which can happen if some of them are
+    // dead code or if there is a `goto` into the middle of the scope.
+    mlir::Block *getOrCreateRetBlock(CIRGenFunction &cgf, mlir::Location loc) {
+      if (returnBlock == nullptr) {
+        returnBlock = createRetBlock(cgf, loc);
+        return returnBlock;
+      }
+      updateRetLoc(returnBlock, loc);
+      return returnBlock;
+    }
+
+    mlir::Block *getEntryBlock() { return entryBlock; }
+  };
+
+  LexicalScope *currLexScope = nullptr;
+
   Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,
                            const Twine &name = "tmp");
 };
+
 } // namespace clang::CIRGen
 
 #endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 7a38f9838b290..d4bc2db24d95c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -30,20 +30,16 @@ void CIRGenFunction::emitCompoundStmtWithoutScope(const 
CompoundStmt &s) {
 
 void CIRGenFunction::emitCompoundStmt(const CompoundStmt &s) {
   mlir::Location scopeLoc = getLoc(s.getSourceRange());
-  auto scope = builder.create<cir::ScopeOp>(
+  mlir::OpBuilder::InsertPoint scopeInsPt;
+  builder.create<cir::ScopeOp>(
       scopeLoc, [&](mlir::OpBuilder &b, mlir::Type &type, mlir::Location loc) {
-        emitCompoundStmtWithoutScope(s);
+        scopeInsPt = b.saveInsertionPoint();
       });
-
-  // This code to insert a cir.yield at the end of the scope is temporary until
-  // CIRGenFunction::LexicalScope::cleanup() is upstreamed.
-  if (!scope.getRegion().empty()) {
-    mlir::Block &lastBlock = scope.getRegion().back();
-    if (lastBlock.empty() || !lastBlock.mightHaveTerminator() ||
-        !lastBlock.getTerminator()->hasTrait<mlir::OpTrait::IsTerminator>()) {
-      builder.setInsertionPointToEnd(&lastBlock);
-      builder.create<cir::YieldOp>(getLoc(s.getEndLoc()));
-    }
+  {
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.restoreInsertionPoint(scopeInsPt);
+    LexicalScope lexScope(*this, scopeLoc, builder.getInsertionBlock());
+    emitCompoundStmtWithoutScope(s);
   }
 }
 
@@ -251,16 +247,15 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const 
ReturnStmt &s) {
                                "named return value optimization");
   } else if (!rv) {
     // No return expression. Do nothing.
-    // TODO(CIR): In the future when function returns are fully implemented,
-    // this section will do nothing.  But for now a ReturnOp is necessary.
-    builder.create<ReturnOp>(loc);
   } else if (rv->getType()->isVoidType()) {
     // Make sure not to return anything, but evaluate the expression
     // for side effects.
     if (rv) {
       emitAnyExpr(rv);
     }
-  } else if (fnRetTy->isReferenceType()) {
+  } else if (cast<FunctionDecl>(curGD.getDecl())
+                 ->getReturnType()
+                 ->isReferenceType()) {
     getCIRGenModule().errorNYI(s.getSourceRange(),
                                "function return type that is a reference");
   } else {
@@ -269,7 +264,7 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const 
ReturnStmt &s) {
     case cir::TEK_Scalar:
       value = emitScalarExpr(rv);
       if (value) { // Change this to an assert once emitScalarExpr is complete
-        builder.create<ReturnOp>(loc, llvm::ArrayRef(value));
+        builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca);
       }
       break;
     default:
@@ -279,5 +274,9 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const 
ReturnStmt &s) {
     }
   }
 
+  auto *retBlock = currLexScope->getOrCreateRetBlock(*this, loc);
+  builder.create<cir::BrOp>(loc, retBlock);
+  builder.createBlock(builder.getBlock()->getParent());
+
   return mlir::success();
 }
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
index 754f11f1361ba..01e58398a6438 100644
--- a/clang/test/CIR/CodeGen/basic.c
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -15,17 +15,27 @@ int f1(int i) {
 //      CIR: module
 // CIR-NEXT: cir.func @f1(%arg0: !cir.int<s, 32> loc({{.*}})) -> !cir.int<s, 
32>
 // CIR-NEXT:   %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CIR-NEXT:   %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CIR-NEXT:   cir.store %arg0, %[[I_PTR]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
 // CIR-NEXT:   %[[I_IGNORED:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 
32>>, !cir.int<s, 32>
 // CIR-NEXT:   %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
-// CIR-NEXT:   cir.return %[[I]] : !cir.int<s, 32>
+// CIR-NEXT:   cir.store %[[I]], %[[RV]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT:   cir.br ^[[BB1:[^ ]+]]
+// CIR-NEXT: ^[[BB1]]:
+// CIR-NEXT:   %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CIR-NEXT:   cir.return %[[R]] : !cir.int<s, 32>
 
-//      LLVM: define i32 @f1(i32 %[[I:.*]])
+//      LLVM: define i32 @f1(i32 %[[IP:.*]])
 // LLVM-NEXT:   %[[I_PTR:.*]] = alloca i32, i64 1, align 4
-// LLVM-NEXT:   store i32 %[[I]], ptr %[[I_PTR]], align 4
+// LLVM-NEXT:   %[[RV:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:   store i32 %[[IP]], ptr %[[I_PTR]], align 4
 // LLVM-NEXT:   %[[I_IGNORED:.*]] = load i32, ptr %[[I_PTR]], align 4
 // LLVM-NEXT:   %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
-// LLVM-NEXT:   ret i32 %[[I]]
+// LLVM-NEXT:   store i32 %[[I]], ptr %[[RV]], align 4
+// LLVM-NEXT:   br label %[[BB1:.*]]
+//      LLVM: [[BB1]]:
+// LLVM-NEXT:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// LLVM-NEXT:   ret i32 %[[R]]
 
 //      OGCG: define{{.*}} i32 @f1(i32 noundef %[[I:.*]])
 // OGCG-NEXT: entry:
@@ -38,11 +48,21 @@ int f1(int i) {
 int f2(void) { return 3; }
 
 //      CIR: cir.func @f2() -> !cir.int<s, 32>
+// CIR-NEXT:   %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CIR-NEXT:   %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
-// CIR-NEXT:   cir.return %[[THREE]] : !cir.int<s, 32>
+// CIR-NEXT:   cir.store %[[THREE]], %[[RV]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT:   cir.br ^[[BB1:[^ ]+]]
+// CIR-NEXT: ^[[BB1]]:
+// CIR-NEXT:   %[[R:.*]] = cir.load %0 : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CIR-NEXT:   cir.return %[[R]] : !cir.int<s, 32>
 
 //      LLVM: define i32 @f2()
-// LLVM-NEXT:   ret i32 3
+// LLVM-NEXT:   %[[RV:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:   store i32 3, ptr %[[RV]], align 4
+// LLVM-NEXT:   br label %[[BB1:.*]]
+//      LLVM: [[BB1]]:
+// LLVM-NEXT:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// LLVM-NEXT:   ret i32 %[[R]]
 
 //      OGCG: define{{.*}} i32 @f2()
 // OGCG-NEXT: entry:
@@ -54,17 +74,27 @@ int f3(void) {
 }
 
 //      CIR: cir.func @f3() -> !cir.int<s, 32>
+// CIR-NEXT:   %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CIR-NEXT:   %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
 // CIR-NEXT:   %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
 // CIR-NEXT:   cir.store %[[THREE]], %[[I_PTR]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
 // CIR-NEXT:   %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
-// CIR-NEXT:   cir.return %[[I]] : !cir.int<s, 32>
+// CIR-NEXT:   cir.store %[[I]], %[[RV]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT:   cir.br ^[[BB1:[^ ]+]]
+// CIR-NEXT: ^[[BB1]]:
+// CIR-NEXT:   %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CIR-NEXT:   cir.return %[[R]] : !cir.int<s, 32>
 
 //      LLVM: define i32 @f3()
+// LLVM-NEXT:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM-NEXT:   %[[I_PTR:.*]] = alloca i32, i64 1, align 4
 // LLVM-NEXT:   store i32 3, ptr %[[I_PTR]], align 4
 // LLVM-NEXT:   %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
-// LLVM-NEXT:   ret i32 %[[I]]
+// LLVM-NEXT:   store i32 %[[I]], ptr %[[RV]], align 4
+// LLVM-NEXT:   br label %[[BB1:.*]]
+//      LLVM: [[BB1]]:
+// LLVM-NEXT:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// LLVM-NEXT:   ret i32 %[[R]]
 
 //      OGCG: define{{.*}} i32 @f3
 // OGCG-NEXT: entry:
diff --git a/clang/test/CIR/CodeGen/basic.cpp b/clang/test/CIR/CodeGen/basic.cpp
index ef922cc2b46fc..04687c340843a 100644
--- a/clang/test/CIR/CodeGen/basic.cpp
+++ b/clang/test/CIR/CodeGen/basic.cpp
@@ -7,9 +7,12 @@ int f1() {
 
 // CHECK: module
 // CHECK: cir.func @f1() -> !cir.int<s, 32>
+// CHECK:    %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CHECK:    %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["i"] {alignment = 4 : i64}
 // CHECK:    %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
-// CHECK:    cir.return %[[I]] : !cir.int<s, 32>
+// CHECK:    cir.store %[[I]], %[[RV]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>
+// CHECK:    %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CHECK:    cir.return %[[R]] : !cir.int<s, 32>
 
 int f2() {
   const int i = 2;
@@ -17,11 +20,14 @@ int f2() {
 }
 
 // CHECK: cir.func @f2() -> !cir.int<s, 32>
+// CHECK:    %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CHECK:    %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["i", init, const] {alignment = 4 : i64}
 // CHECK:    %[[TWO:.*]] = cir.const #cir.int<2> : !cir.int<s, 32>
 // CHECK:    cir.store %[[TWO]], %[[I_PTR]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
 // CHECK:    %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
-// CHECK:    cir.return %[[I]] : !cir.int<s, 32>
+// CHECK:    cir.store %[[I]], %[[RV]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>
+// CHECK:    %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CHECK:    cir.return %[[R]] : !cir.int<s, 32>
 
 int f3(int i) {
   return i;
@@ -29,9 +35,12 @@ int f3(int i) {
 
 // CHECK: cir.func @f3(%[[ARG:.*]]: !cir.int<s, 32> loc({{.*}})) -> 
!cir.int<s, 32>
 // CHECK:   %[[ARG_ALLOCA:.*]] = cir.alloca !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CHECK:   %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CHECK:   cir.store %[[ARG]], %[[ARG_ALLOCA]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
 // CHECK:   %[[ARG_VAL:.*]] = cir.load %[[ARG_ALLOCA]] : !cir.ptr<!cir.int<s, 
32>>, !cir.int<s, 32>
-// CHECK:   cir.return %[[ARG_VAL]] : !cir.int<s, 32>
+// CHECK:   cir.store %[[ARG_VAL]], %[[RV]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
+// CHECK:   %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CHECK:   cir.return %[[R]] : !cir.int<s, 32>
 
 int f4(const int i) {
   return i;
@@ -39,6 +48,9 @@ int f4(const int i) {
 
 // CHECK: cir.func @f4(%[[ARG:.*]]: !cir.int<s, 32> loc({{.*}})) -> 
!cir.int<s, 32>
 // CHECK:   %[[ARG_ALLOCA:.*]] = cir.alloca !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>, ["i", init, const] {alignment = 4 : i64}
+// CHECK:   %[[RV:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["__retval"] {alignment = 4 : i64}
 // CHECK:   cir.store %[[ARG]], %[[ARG_ALLOCA]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
 // CHECK:   %[[ARG_VAL:.*]] = cir.load %[[ARG_ALLOCA]] : !cir.ptr<!cir.int<s, 
32>>, !cir.int<s, 32>
-// CHECK:   cir.return %[[ARG_VAL]] : !cir.int<s, 32>
+// CHECK:   cir.store %[[ARG_VAL]], %[[RV]] : !cir.int<s, 32>, 
!cir.ptr<!cir.int<s, 32>>
+// CHECK:   %[[R:.*]] = cir.load %[[RV]] : !cir.ptr<!cir.int<s, 32>>, 
!cir.int<s, 32>
+// CHECK:   cir.return %[[R]] : !cir.int<s, 32>
diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp
index b25a0cdb4b055..4d9e364b3c186 100644
--- a/clang/test/CIR/CodeGen/cast.cpp
+++ b/clang/test/CIR/CodeGen/cast.cpp
@@ -9,16 +9,21 @@ unsigned char cxxstaticcast_0(unsigned int x) {
 
 // CIR: cir.func @cxxstaticcast_0
 // CIR:    %[[XPTR:[0-9]+]] = cir.alloca !cir.int<u, 32>, !cir.ptr<!cir.int<u, 
32>>, ["x", init] {alignment = 4 : i64}
+// CIR:    %[[RV:[0-9]+]] = cir.alloca !cir.int<u, 8>, !cir.ptr<!cir.int<u, 
8>>, ["__retval"] {alignment = 1 : i64}
 // CIR:    cir.store %arg0, %[[XPTR]] : !cir.int<u, 32>, !cir.ptr<!cir.int<u, 
32>>
 // CIR:    %[[XVAL:[0-9]+]] = cir.load %[[XPTR]] : !cir.ptr<!cir.int<u, 32>>, 
!cir.int<u, 32>
 // CIR:    %[[CASTED:[0-9]+]] = cir.cast(integral, %[[XVAL]] : !cir.int<u, 
32>), !cir.int<u, 8>
-// CIR:    cir.return %[[CASTED]] : !cir.int<u, 8>
+// CIR:    cir.store %[[CASTED]], %[[RV]] : !cir.int<u, 8>, 
!cir.ptr<!cir.int<u, 8>>
+// CIR:    %[[R:[0-9]+]] = cir.load %1 : !cir.ptr<!cir.int<u, 8>>, !cir.int<u, 
8>
+// CIR:    cir.return %[[R]] : !cir.int<u, 8>
 // CIR:  }
 
 // LLVM: define i8 @cxxstaticcast_0(i32 %{{[0-9]+}})
 // LLVM: %[[LOAD:[0-9]+]] = load i32, ptr %{{[0-9]+}}, align 4
 // LLVM: %[[TRUNC:[0-9]+]] = trunc i32 %[[LOAD]] to i8
-// LLVM: ret i8 %[[TRUNC]]
+// LLVM: store i8 %[[TRUNC]], ptr %[[RV:[0-9]+]], align 1
+// LLVM: %[[R:[0-9]+]] = load i8, ptr %[[RV]], align 1
+// LLVM: ret i8 %[[R]]
 
 
 int cStyleCasts_0(unsigned x1, int x2, float x3, short x4, double x5) {
diff --git a/clang/test/CIR/CodeGen/unary.cpp b/clang/test/CIR/CodeGen/unary.cpp
index 5d93587463562..924f4188199ab 100644
--- a/clang/test/CIR/CodeGen/unary.cpp
+++ b/clang/test/CIR/CodeGen/unary.cpp
@@ -16,6 +16,7 @@ unsigned up0() {
 // CHECK:   %[[OUTPUT:.*]] = cir.unary(plus, %[[INPUT]])
 
 // LLVM: define i32 @up0()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -36,6 +37,7 @@ unsigned um0() {
 // CHECK:   %[[OUTPUT:.*]] = cir.unary(minus, %[[INPUT]])
 
 // LLVM: define i32 @um0()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -58,6 +60,7 @@ unsigned un0() {
 // CHECK:   %[[OUTPUT:.*]] = cir.unary(not, %[[INPUT]])
 
 // LLVM: define i32 @un0()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -85,6 +88,7 @@ int inc0() {
 // CHECK:   %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
 
 // LLVM: define i32 @inc0()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -112,6 +116,7 @@ int dec0() {
 // CHECK:   %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
 
 // LLVM: define i32 @dec0()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -139,6 +144,7 @@ int inc1() {
 // CHECK:   %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
 
 // LLVM: define i32 @inc1()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -166,6 +172,7 @@ int dec1() {
 // CHECK:   %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
 
 // LLVM: define i32 @dec1()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
@@ -196,6 +203,7 @@ int inc2() {
 // CHECK:   %[[B_TO_OUTPUT:.*]] = cir.load %[[B]]
 
 // LLVM: define i32 @inc2()
+// LLVM:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca i32, i64 1, align 4
 // LLVM:   %[[B:.*]] = alloca i32, i64 1, align 4
 // LLVM:   store i32 1, ptr %[[A]], align 4
@@ -226,6 +234,7 @@ float fpPlus() {
 // CHECK:   %[[OUTPUT:.*]] = cir.unary(plus, %[[INPUT]])
 
 // LLVM: define float @fpPlus()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -246,6 +255,7 @@ float fpMinus() {
 // CHECK:   %[[OUTPUT:.*]] = cir.unary(minus, %[[INPUT]])
 
 // LLVM: define float @fpMinus()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -270,6 +280,7 @@ float fpPreInc() {
 // CHECK:   %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
 
 // LLVM: define float @fpPreInc()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -294,6 +305,7 @@ float fpPreDec() {
 // CHECK:   %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
 
 // LLVM: define float @fpPreDec()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -318,6 +330,7 @@ float fpPostInc() {
 // CHECK:   %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
 
 // LLVM: define float @fpPostInc()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -342,6 +355,7 @@ float fpPostDec() {
 // CHECK:   %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
 
 // LLVM: define float @fpPostDec()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
 // LLVM:   %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
@@ -372,6 +386,7 @@ float fpPostInc2() {
 // CHECK:   %[[B_TO_OUTPUT:.*]] = cir.load %[[B]]
 
 // LLVM: define float @fpPostInc2()
+// LLVM:   %[[RV:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[A:.*]] = alloca float, i64 1, align 4
 // LLVM:   %[[B:.*]] = alloca float, i64 1, align 4
 // LLVM:   store float 1.000000e+00, ptr %[[A]], align 4
diff --git a/clang/test/CIR/Lowering/basic.cpp 
b/clang/test/CIR/Lowering/basic.cpp
index d1dc343a068a8..9627057a469a5 100644
--- a/clang/test/CIR/Lowering/basic.cpp
+++ b/clang/test/CIR/Lowering/basic.cpp
@@ -6,9 +6,12 @@ int f1() {
 }
 
 // CHECK: define{{.*}} i32 @f1() {
+// CHECK:    %[[RV:.*]] = alloca i32, i64 1, align 4
 // CHECK:    %[[I_PTR:.*]] = alloca i32, i64 1, align 4
 // CHECK:    %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
-// CHECK:    ret i32 %[[I]]
+// CHECK:    store i32 %[[I]], ptr %[[RV]], align 4
+// CHECK:    %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:    ret i32 %[[R]]
 
 int f2() {
   const int i = 2;
@@ -16,10 +19,13 @@ int f2() {
 }
 
 // CHECK: define{{.*}} i32 @f2() {
+// CHECK:    %[[RV:.*]] = alloca i32, i64 1, align 4
 // CHECK:    %[[I_PTR:.*]] = alloca i32, i64 1, align 4
 // CHECK:    store i32 2, ptr %[[I_PTR]], align 4
 // CHECK:    %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
-// CHECK:    ret i32 %[[I]]
+// CHECK:    store i32 %[[I]], ptr %[[RV]], align 4
+// CHECK:    %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:    ret i32 %[[R]]
 
 int f3(int i) {
     return i;
@@ -27,9 +33,12 @@ int f3(int i) {
 
 // CHECK: define{{.*}} i32 @f3(i32 %[[ARG:.*]])
 // CHECK:   %[[ARG_ALLOCA:.*]] = alloca i32, i64 1, align 4
+// CHECK:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // CHECK:   store i32 %[[ARG]], ptr %[[ARG_ALLOCA]], align 4
 // CHECK:   %[[ARG_VAL:.*]] = load i32, ptr %[[ARG_ALLOCA]], align 4
-// CHECK:   ret i32 %[[ARG_VAL]]
+// CHECK:   store i32 %[[ARG_VAL]], ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:   ret i32 %[[R]]
 
 int f4(const int i) {
   return i;
@@ -37,6 +46,9 @@ int f4(const int i) {
 
 // CHECK: define{{.*}} i32 @f4(i32 %[[ARG:.*]])
 // CHECK:   %[[ARG_ALLOCA:.*]] = alloca i32, i64 1, align 4
+// CHECK:   %[[RV:.*]] = alloca i32, i64 1, align 4
 // CHECK:   store i32 %[[ARG]], ptr %[[ARG_ALLOCA]], align 4
 // CHECK:   %[[ARG_VAL:.*]] = load i32, ptr %[[ARG_ALLOCA]], align 4
-// CHECK:   ret i32 %[[ARG_VAL]]
+// CHECK:   store i32 %[[ARG_VAL]], ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:   ret i32 %[[R]]
diff --git a/clang/test/CIR/Lowering/func-simple.cpp 
b/clang/test/CIR/Lowering/func-simple.cpp
index 32d75cdd2c15d..f22562a66e066 100644
--- a/clang/test/CIR/Lowering/func-simple.cpp
+++ b/clang/test/CIR/Lowering/func-simple.cpp
@@ -11,7 +11,10 @@ void voidret() { return; }
 
 int intfunc() { return 42; }
 // CHECK: define{{.*}} i32 @intfunc()
-// CHECK:   ret i32 42
+// CHECK:   %[[RV:.*]] = alloca i32, i64 1, align 4
+// CHECK:   store i32 42, ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:   ret i32 %[[R]]
 
 int scopes() {
   {
@@ -21,34 +24,52 @@ int scopes() {
   }
 }
 // CHECK: define{{.*}} i32 @scopes() {
-// CHECK:     br label %[[LABEL1:.*]]
-// CHECK:     [[LABEL1]]:
-// CHECK:       br label %[[LABEL2:.*]]
-// CHECK:     [[LABEL2]]:
-// CHECK:       ret i32 99
-// CHECK:     [[LABEL3:.*]]:
-// CHECK:       br label %[[LABEL4:.*]]
-// CHECK:     [[LABEL4]]:
-// CHECK:       call void @llvm.trap()
-// CHECK:       unreachable
+// CHECK:   %[[RV:.*]] = alloca i32, i64 1, align 4
+// CHECK:   br label %[[LABEL1:.*]]
+// CHECK: [[LABEL1]]:
+// CHECK:   br label %[[LABEL2:.*]]
+// CHECK: [[LABEL2]]:
+// CHECK:   store i32 99, ptr %[[RV]], align 4
+// CHECK:   br label %[[LABEL3:.*]]
+// CHECK: [[LABEL3]]:
+// CHECK:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:   ret i32 %[[R]]
+// CHECK: [[LABEL4:.*]]:
+// CHECK:   br label %[[LABEL5:.*]]
+// CHECK: [[LABEL5]]:
+// CHECK:   call void @llvm.trap()
+// CHECK:   unreachable
 // CHECK: }
 
 long longfunc() { return 42l; }
 // CHECK: define{{.*}} i64 @longfunc() {
-// CHECK:   ret i64 42
+// CHECK:   %[[RV]] = alloca i64, i64 1, align 8
+// CHECK:   store i64 42, ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i64, ptr %[[RV]], align 4
+// CHECK:   ret i64 %[[R]]
 // CHECK: }
 
 unsigned unsignedfunc() { return 42u; }
 // CHECK: define{{.*}} i32 @unsignedfunc() {
-// CHECK:   ret i32 42
+// CHECK:   %[[RV:.*]] = alloca i32, i64 1, align 4
+// CHECK:   store i32 42, ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i32, ptr %[[RV]], align 4
+// CHECK:   ret i32 %[[R]]
 // CHECK: }
 
 unsigned long long ullfunc() { return 42ull; }
 // CHECK: define{{.*}} i64 @ullfunc() {
-// CHECK:   ret i64 42
+// CHECK:   %[[RV:.*]] = alloca i64, i64 1, align 8
+// CHECK:   store i64 42, ptr %[[RV]], align 4
+// CHECK:   %[[R:.*]] = load i64, ptr %[[RV]], align 4
+// CHECK:   ret i64 %[[R]]
 // CHECK: }
 
 bool boolfunc() { return true; }
 // CHECK: define{{.*}} i1 @boolfunc() {
-// CHECK:   ret i1 true
+// CHECK:   %[[RV:.*]] = alloca i8, i64 1, align 1
+// CHECK:   store i8 1, ptr %[[RV]], align 1
+// CHECK:   %[[R8:.*]] = load i8, ptr %[[RV]], align 1
+// CHECK:   %[[R:.*]] = trunc i8 %[[R8]] to i1
+// CHECK:   ret i1 %[[R]]
 // CHECK: }
diff --git a/clang/test/CIR/func-simple.cpp b/clang/test/CIR/func-simple.cpp
index d37ccc7229f22..a0440a941d388 100644
--- a/clang/test/CIR/func-simple.cpp
+++ b/clang/test/CIR/func-simple.cpp
@@ -8,13 +8,20 @@ void empty() { }
 
 void voidret() { return; }
 // CHECK: cir.func @voidret() {
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
 // CHECK:   cir.return
 // CHECK: }
 
 int intfunc() { return 42; }
 // CHECK: cir.func @intfunc() -> !cir.int<s, 32> {
-// CHECK:   %0 = cir.const #cir.int<42> : !cir.int<s, 32>
-// CHECK:   cir.return %0 : !cir.int<s, 32>
+// CHECK:   %0 = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, 
["__retval"] {alignment = 4 : i64}
+// CHECK:   %1 = cir.const #cir.int<42> : !cir.int<s, 32>
+// CHECK:   cir.store %1, %0 : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CHECK:   cir.return %2 : !cir.int<s, 32>
 // CHECK: }
 
 int scopes() {
@@ -25,10 +32,15 @@ int scopes() {
   }
 }
 // CHECK: cir.func @scopes() -> !cir.int<s, 32> {
+// CHECK:   %0 = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, 
["__retval"] {alignment = 4 : i64}
 // CHECK:   cir.scope {
 // CHECK:     cir.scope {
-// CHECK:       %0 = cir.const #cir.int<99> : !cir.int<s, 32>
-// CHECK:       cir.return %0 : !cir.int<s, 32>
+// CHECK:       %1 = cir.const #cir.int<99> : !cir.int<s, 32>
+// CHECK:       cir.store %1, %0 : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CHECK:       cir.br ^bb1
+// CHECK:     ^bb1:
+// CHECK:       %2 = cir.load %0 : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CHECK:       cir.return %2 : !cir.int<s, 32>
 // CHECK:     }
 // CHECK:   }
 // CHECK:   cir.trap
@@ -36,36 +48,66 @@ int scopes() {
 
 long longfunc() { return 42l; }
 // CHECK: cir.func @longfunc() -> !cir.int<s, 64>
-// CHECK:   %0 = cir.const #cir.int<42> : !cir.int<s, 64>
-// CHECK:   cir.return %0 : !cir.int<s, 64>
+// CHECK:   %0 = cir.alloca !cir.int<s, 64>, !cir.ptr<!cir.int<s, 64>>, 
["__retval"] {alignment = 8 : i64}
+// CHECK:   %1 = cir.const #cir.int<42> : !cir.int<s, 64>
+// CHECK:   cir.store %1, %0 : !cir.int<s, 64>, !cir.ptr<!cir.int<s, 64>>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.int<s, 64>>, !cir.int<s, 64>
+// CHECK:   cir.return %2 : !cir.int<s, 64>
 // CHECK: }
 
 unsigned unsignedfunc() { return 42u; }
 // CHECK: cir.func @unsignedfunc() -> !cir.int<u, 32>
-// CHECK:   %0 = cir.const #cir.int<42> : !cir.int<u, 32>
-// CHECK:   cir.return %0 : !cir.int<u, 32>
+// CHECK:   %0 = cir.alloca !cir.int<u, 32>, !cir.ptr<!cir.int<u, 32>>, 
["__retval"] {alignment = 4 : i64}
+// CHECK:   %1 = cir.const #cir.int<42> : !cir.int<u, 32>
+// CHECK:   cir.store %1, %0 : !cir.int<u, 32>, !cir.ptr<!cir.int<u, 32>>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.int<u, 32>>, !cir.int<u, 32>
+// CHECK:   cir.return %2 : !cir.int<u, 32>
 // CHECK: }
 
 unsigned long long ullfunc() { return 42ull; }
 // CHECK: cir.func @ullfunc() -> !cir.int<u, 64>
-// CHECK:   %0 = cir.const #cir.int<42> : !cir.int<u, 64>
-// CHECK:   cir.return %0 : !cir.int<u, 64>
+// CHECK:   %0 = cir.alloca !cir.int<u, 64>, !cir.ptr<!cir.int<u, 64>>, 
["__retval"] {alignment = 8 : i64}
+// CHECK:   %1 = cir.const #cir.int<42> : !cir.int<u, 64>
+// CHECK:   cir.store %1, %0 : !cir.int<u, 64>, !cir.ptr<!cir.int<u, 64>>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.int<u, 64>>, !cir.int<u, 64>
+// CHECK:   cir.return %2 : !cir.int<u, 64>
 // CHECK: }
 
 bool boolfunc() { return true; }
 // CHECK: cir.func @boolfunc() -> !cir.bool {
-// CHECK:   %0 = cir.const #true
-// CHECK:   cir.return %0 : !cir.bool
+// CHECK:   %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["__retval"] 
{alignment = 1 : i64}
+// CHECK:   %1 = cir.const #true
+// CHECK:   cir.store %1, %0 : !cir.bool, !cir.ptr<!cir.bool>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.bool>, !cir.bool
+// CHECK:   cir.return %2 : !cir.bool
 // CHECK: }
 
 float floatfunc() { return 42.42f; }
 // CHECK: cir.func @floatfunc() -> !cir.float {
-// CHECK:   %0 = cir.const #cir.fp<4.242
-// CHECK:   cir.return %0 : !cir.float
+// CHECK:   %0 = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"] 
{alignment = 4 : i64}
+// CHECK:   %1 = cir.const #cir.fp<4.242
+// CHECK:   cir.store %1, %0 : !cir.float, !cir.ptr<!cir.float>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.float>, !cir.float
+// CHECK:   cir.return %2 : !cir.float
 // CHECK: }
 
 double doublefunc() { return 42.42; }
 // CHECK: cir.func @doublefunc() -> !cir.double {
-// CHECK:   %0 = cir.const #cir.fp<4.242
-// CHECK:   cir.return %0 : !cir.double
+// CHECK:   %0 = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["__retval"] 
{alignment = 8 : i64}
+// CHECK:   %1 = cir.const #cir.fp<4.242
+// CHECK:   cir.store %1, %0 : !cir.double, !cir.ptr<!cir.double>
+// CHECK:   cir.br ^bb1
+// CHECK: ^bb1:
+// CHECK:   %2 = cir.load %0 : !cir.ptr<!cir.double>, !cir.double
+// CHECK:   cir.return %2 : !cir.double
 // CHECK: }

>From 172ea3a0ae17a182e1c2d1e999b152e0241218d4 Mon Sep 17 00:00:00 2001
From: David Olsen <dol...@nvidia.com>
Date: Wed, 19 Mar 2025 08:49:32 -0700
Subject: [PATCH 2/2] Upstream LexicalScope: review feedback

Change `curr` to `cur` in names.

Fix typo in comment.
---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 20 ++++++++++----------
 clang/lib/CIR/CodeGen/CIRGenFunction.h   | 10 +++++-----
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp     |  2 +-
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 5685339c9e637..16547f2401292 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -158,7 +158,7 @@ void CIRGenFunction::declare(mlir::Value addrVal, const 
Decl *var, QualType ty,
 
 void CIRGenFunction::LexicalScope::cleanup() {
   CIRGenBuilderTy &builder = cgf.builder;
-  LexicalScope *localScope = cgf.currLexScope;
+  LexicalScope *localScope = cgf.curLexScope;
 
   if (returnBlock != nullptr) {
     // Write out the return block, which loads the value from `__retval` and
@@ -168,16 +168,16 @@ void CIRGenFunction::LexicalScope::cleanup() {
     (void)emitReturn(*returnLoc);
   }
 
-  mlir::Block *currBlock = builder.getBlock();
-  if (isGlobalInit() && !currBlock)
+  mlir::Block *curBlock = builder.getBlock();
+  if (isGlobalInit() && !curBlock)
     return;
-  if (currBlock->mightHaveTerminator() && currBlock->getTerminator())
+  if (curBlock->mightHaveTerminator() && curBlock->getTerminator())
     return;
 
   // Get rid of any empty block at the end of the scope.
   bool entryBlock = builder.getInsertionBlock()->isEntryBlock();
-  if (!entryBlock && currBlock->empty()) {
-    currBlock->erase();
+  if (!entryBlock && curBlock->empty()) {
+    curBlock->erase();
     if (returnBlock != nullptr && returnBlock->getUses().empty())
       returnBlock->erase();
     return;
@@ -186,7 +186,7 @@ void CIRGenFunction::LexicalScope::cleanup() {
   // Reached the end of the scope.
   {
     mlir::OpBuilder::InsertionGuard guard(builder);
-    builder.setInsertionPointToEnd(currBlock);
+    builder.setInsertionPointToEnd(curBlock);
 
     if (localScope->depth == 0) {
       // Reached the end of the function.
@@ -203,7 +203,7 @@ void CIRGenFunction::LexicalScope::cleanup() {
     }
     // Reached the end of a non-function scope.  Some scopes, such as those
     // used with the ?: operator, can return a value.
-    if (!localScope->isTernary() && !currBlock->mightHaveTerminator()) {
+    if (!localScope->isTernary() && !curBlock->mightHaveTerminator()) {
       !retVal ? builder.create<cir::YieldOp>(localScope->endLoc)
               : builder.create<cir::YieldOp>(localScope->endLoc, retVal);
     }
@@ -223,7 +223,7 @@ cir::ReturnOp 
CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
   return builder.create<cir::ReturnOp>(loc);
 }
 
-// This is copyied from CodeGenModule::MayDropFunctionReturn.  This is a
+// This is copied from CodeGenModule::MayDropFunctionReturn.  This is a
 // candidate for sharing between CIRGen and CodeGen.
 static bool mayDropFunctionReturn(const ASTContext &astContext,
                                   QualType returnType) {
@@ -239,7 +239,7 @@ static bool mayDropFunctionReturn(const ASTContext 
&astContext,
 
 void CIRGenFunction::LexicalScope::emitImplicitReturn() {
   CIRGenBuilderTy &builder = cgf.getBuilder();
-  LexicalScope *localScope = cgf.currLexScope;
+  LexicalScope *localScope = cgf.curLexScope;
 
   const auto *fd = cast<clang::FunctionDecl>(cgf.curGD.getDecl());
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index b52f5ec734f70..ba05fb46a3c46 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -378,11 +378,11 @@ class CIRGenFunction : public CIRGenTypeCache {
     unsigned depth = 0;
 
     LexicalScope(CIRGenFunction &cgf, mlir::Location loc, mlir::Block *eb)
-        : cgf(cgf), entryBlock(eb), parentScope(cgf.currLexScope),
-          beginLoc(loc), endLoc(loc) {
+        : cgf(cgf), entryBlock(eb), parentScope(cgf.curLexScope), 
beginLoc(loc),
+          endLoc(loc) {
 
       assert(entryBlock && "LexicalScope requires an entry block");
-      cgf.currLexScope = this;
+      cgf.curLexScope = this;
       if (parentScope)
         ++depth;
 
@@ -396,7 +396,7 @@ class CIRGenFunction : public CIRGenTypeCache {
     void setRetVal(mlir::Value v) { retVal = v; }
 
     void cleanup();
-    void restore() { cgf.currLexScope = parentScope; }
+    void restore() { cgf.curLexScope = parentScope; }
 
     ~LexicalScope() {
       assert(!cir::MissingFeatures::generateDebugInfo());
@@ -465,7 +465,7 @@ class CIRGenFunction : public CIRGenTypeCache {
     mlir::Block *getEntryBlock() { return entryBlock; }
   };
 
-  LexicalScope *currLexScope = nullptr;
+  LexicalScope *curLexScope = nullptr;
 
   Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,
                            const Twine &name = "tmp");
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index d4bc2db24d95c..bd1aa632da1d0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -274,7 +274,7 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const 
ReturnStmt &s) {
     }
   }
 
-  auto *retBlock = currLexScope->getOrCreateRetBlock(*this, loc);
+  auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc);
   builder.create<cir::BrOp>(loc, retBlock);
   builder.createBlock(builder.getBlock()->getParent());
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to