https://github.com/andykaylor updated 
https://github.com/llvm/llvm-project/pull/129167

>From d1fa2629b5786befa8ca8f839cf948df4644d615 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akay...@nvidia.com>
Date: Tue, 25 Feb 2025 16:52:18 -0800
Subject: [PATCH 1/2] [CIR] Upstream func args alloca handling

This change adds support for collecting function arguments and storing
them in alloca memory slots.
---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  5 ++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 39 ++++++++++
 clang/include/clang/CIR/MissingFeatures.h     |  1 +
 clang/lib/CIR/CodeGen/Address.h               |  8 ++
 clang/lib/CIR/CodeGen/CIRGenCall.h            | 28 +++++++
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp          |  2 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      | 76 +++++++++++++++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.h        | 11 ++-
 clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp    | 33 ++++++++
 clang/test/CIR/CodeGen/basic.cpp              | 20 +++++
 10 files changed, 212 insertions(+), 11 deletions(-)
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenCall.h

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 14afdfc2758ea..b65797e40d5f9 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -69,6 +69,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return create<cir::LoadOp>(loc, ptr);
   }
 
+  cir::StoreOp createStore(mlir::Location loc, mlir::Value val,
+                           mlir::Value dst) {
+    return create<cir::StoreOp>(loc, val, dst);
+  }
+
   //
   // Block handling helpers
   // ----------------------
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 083cf46a93ae6..48178b0ff247d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -228,6 +228,45 @@ def LoadOp : CIR_Op<"load", [
   // FIXME: add verifier.
 }
 
+//===----------------------------------------------------------------------===//
+// StoreOp
+//===----------------------------------------------------------------------===//
+
+def StoreOp : CIR_Op<"store", [
+  TypesMatchWith<"type of 'value' matches pointee type of 'addr'",
+                 "addr", "value",
+                 "cast<PointerType>($_self).getPointee()">,
+                 DeclareOpInterfaceMethods<PromotableMemOpInterface>]> {
+
+  let summary = "Store value to memory address";
+  let description = [{
+    `cir.store` stores a value (first operand) to the memory address specified
+    in the second operand. A unit attribute `volatile` can be used to indicate
+    a volatile store. Store's can be marked atomic by using
+    `atomic(<mem_order>)`.
+
+    `align` can be used to specify an alignment that's different from the
+    default, which is computed from `result`'s type ABI data layout.
+
+    Example:
+
+    ```mlir
+    // Store a function argument to local storage, address in %0.
+    cir.store %arg0, %0 : i32, !cir.ptr<i32>
+    ```
+  }];
+
+  let arguments = (ins CIR_AnyType:$value,
+                       Arg<CIR_PointerType, "the address to store the value",
+                           [MemWrite]>:$addr);
+
+  let assemblyFormat = [{
+    $value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr))
+  }];
+
+  // FIXME: add verifier.
+}
+
 
//===----------------------------------------------------------------------===//
 // ReturnOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 5c7e10d018809..9b416ef61055e 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -59,6 +59,7 @@ struct MissingFeatures {
   // Misc
   static bool scalarConversionOpts() { return false; }
   static bool tryEmitAsConstant() { return false; }
+  static bool constructABIArgDirectExtend() { return false; }
 };
 
 } // namespace cir
diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h
index 72e7e1dcf1560..fba1ffd90877b 100644
--- a/clang/lib/CIR/CodeGen/Address.h
+++ b/clang/lib/CIR/CodeGen/Address.h
@@ -52,6 +52,14 @@ class Address {
            elementType);
   }
 
+  Address(mlir::Value pointer, clang::CharUnits alignment)
+      : Address(pointer,
+                mlir::cast<cir::PointerType>(pointer.getType()).getPointee(),
+                alignment) {
+    assert((!alignment.isZero() || pointer == nullptr) &&
+           "creating valid address with invalid alignment");
+  }
+
   static Address invalid() { return Address(nullptr); }
   bool isValid() const {
     return pointerAndKnownNonNull.getPointer() != nullptr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h 
b/clang/lib/CIR/CodeGen/CIRGenCall.h
new file mode 100644
index 0000000000000..0996167feeef6
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_CODEGEN_CIRGENCALL_H
+#define CLANG_LIB_CODEGEN_CIRGENCALL_H
+
+#include "clang/AST/GlobalDecl.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang::CIRGen {
+
+/// Type for representing both the decl and type of parameters to a function.
+/// The decl must be either a ParmVarDecl or ImplicitParamDecl.
+class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> 
{};
+
+} // namespace clang::CIRGen
+
+#endif // CLANG_LIB_CODEGEN_CIRGENCALL_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index e44cad559d509..c34d42eff6966 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -44,7 +44,7 @@ void CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
   mlir::Type allocaTy = convertTypeForMem(ty);
   // Create the temp alloca and declare variable using it.
   address = createTempAlloca(allocaTy, alignment, loc, d.getName());
-  declare(address, &d, ty, getLoc(d.getSourceRange()), alignment);
+  declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
 
   setAddrOfLocalVar(&d, address);
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 86986b5847e98..76912d412fd06 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -12,6 +12,8 @@
 
 #include "CIRGenFunction.h"
 
+#include "CIRGenCall.h"
+#include "mlir/IR/Location.h"
 #include "clang/AST/GlobalDecl.h"
 #include "clang/CIR/MissingFeatures.h"
 
@@ -132,15 +134,17 @@ mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, 
mlir::Location rhs) {
   return mlir::FusedLoc::get(locs, metadata, &getMLIRContext());
 }
 
-mlir::LogicalResult CIRGenFunction::declare(Address addr, const Decl *var,
-                                            QualType ty, mlir::Location loc,
-                                            CharUnits alignment) {
+mlir::LogicalResult CIRGenFunction::declare(mlir::Value addrVal,
+                                            const Decl *var, QualType ty,
+                                            mlir::Location loc,
+                                            CharUnits alignment, bool isParam) 
{
   const auto *namedVar = dyn_cast_or_null<NamedDecl>(var);
   assert(namedVar && "Needs a named decl");
   assert(!cir::MissingFeatures::cgfSymbolTable());
 
-  mlir::Value addrVal = addr.getPointer();
   auto allocaOp = cast<cir::AllocaOp>(addrVal.getDefiningOp());
+  if (isParam)
+    allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
   if (ty->isReferenceType() || ty.isConstQualified())
     allocaOp.setConstantAttr(mlir::UnitAttr::get(&getMLIRContext()));
 
@@ -149,7 +153,7 @@ mlir::LogicalResult CIRGenFunction::declare(Address addr, 
const Decl *var,
 
 void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
                                    cir::FuncOp fn, cir::FuncType funcType,
-                                   SourceLocation loc,
+                                   FunctionArgList args, SourceLocation loc,
                                    SourceLocation startLoc) {
   assert(!curFn &&
          "CIRGenFunction can only be used for one function at a time");
@@ -157,8 +161,41 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType 
returnType,
   fnRetTy = returnType;
   curFn = fn;
 
+  const auto *fd = dyn_cast_or_null<FunctionDecl>(gd.getDecl());
+
   mlir::Block *entryBB = &fn.getBlocks().front();
   builder.setInsertionPointToStart(entryBB);
+
+  // TODO(cir): this should live in `emitFunctionProlog
+  // Declare all the function arguments in the symbol table.
+  for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
+    auto *paramVar = std::get<0>(nameValue);
+    mlir::Value paramVal = std::get<1>(nameValue);
+    auto alignment = getContext().getDeclAlign(paramVar);
+    auto paramLoc = getLoc(paramVar->getSourceRange());
+    paramVal.setLoc(paramLoc);
+
+    mlir::Value addrVal =
+        emitAlloca(cast<NamedDecl>(paramVar)->getName(),
+                   convertType(paramVar->getType()), paramLoc, alignment);
+
+    declare(addrVal, paramVar, paramVar->getType(), paramLoc, alignment,
+            /*isParam=*/true);
+
+    setAddrOfLocalVar(paramVar, Address(addrVal, alignment));
+
+    bool isPromoted = isa<ParmVarDecl>(paramVar) &&
+                      cast<ParmVarDecl>(paramVar)->isKNRPromoted();
+    assert(!cir::MissingFeatures::constructABIArgDirectExtend());
+    if (isPromoted)
+      cgm.errorNYI(fd->getSourceRange(), "Function argument demotion");
+
+    // Location of the store to the param storage tracked as beginning of
+    // the function body.
+    mlir::Location fnBodyBegin = getLoc(fd->getBody()->getBeginLoc());
+    builder.CIRBaseBuilderTy::createStore(fnBodyBegin, paramVal, addrVal);
+  }
+  assert(builder.getInsertionBlock() && "Should be valid");
 }
 
 void CIRGenFunction::finishFunction(SourceLocation endLoc) {}
@@ -187,8 +224,10 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl 
gd, cir::FuncOp fn,
   // This will be used once more code is upstreamed.
   [[maybe_unused]] mlir::Block *entryBB = fn.addEntryBlock();
 
-  startFunction(gd, funcDecl->getReturnType(), fn, funcType, loc,
-                bodyRange.getBegin());
+  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");
@@ -234,6 +273,29 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl 
gd, cir::FuncOp fn,
   return fn;
 }
 
+clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
+                                                     FunctionArgList &args) {
+  const auto *fd = cast<FunctionDecl>(gd.getDecl());
+  QualType retTy = fd->getReturnType();
+
+  const auto *md = dyn_cast<CXXMethodDecl>(fd);
+  if (md && md->isInstance())
+    cgm.errorNYI(fd->getSourceRange(), "buildFunctionArgList: CXXMethodDecl");
+
+  if (isa<CXXConstructorDecl>(fd))
+    cgm.errorNYI(fd->getSourceRange(),
+                 "buildFunctionArgList: CXXConstructorDecl");
+
+  for (auto *param : fd->parameters())
+    args.push_back(param);
+
+  if (md && (isa<CXXConstructorDecl>(md) || isa<CXXDestructorDecl>(md)))
+    cgm.errorNYI(fd->getSourceRange(),
+                 "buildFunctionArgList: implicit structor params");
+
+  return retTy;
+}
+
 /// Emit code to compute a designator that specifies the location
 /// of the expression.
 /// FIXME: document this function better.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index e0888acdc3dce..6b383378ae764 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -14,6 +14,7 @@
 #define CLANG_LIB_CIR_CODEGEN_CIRGENFUNCTION_H
 
 #include "CIRGenBuilder.h"
+#include "CIRGenCall.h"
 #include "CIRGenModule.h"
 #include "CIRGenTypeCache.h"
 #include "CIRGenValue.h"
@@ -96,9 +97,9 @@ class CIRGenFunction : public CIRGenTypeCache {
 private:
   /// Declare a variable in the current scope, return success if the variable
   /// wasn't declared yet.
-  mlir::LogicalResult declare(Address addr, const clang::Decl *var,
+  mlir::LogicalResult declare(mlir::Value addrVal, const clang::Decl *var,
                               clang::QualType ty, mlir::Location loc,
-                              clang::CharUnits alignment);
+                              clang::CharUnits alignment, bool isParam = 
false);
 
 public:
   mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,
@@ -196,12 +197,16 @@ class CIRGenFunction : public CIRGenTypeCache {
   cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
                            cir::FuncType funcType);
 
+  clang::QualType buildFunctionArgList(clang::GlobalDecl gd,
+                                       FunctionArgList &args);
+
   /// 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.
   void startFunction(clang::GlobalDecl gd, clang::QualType retTy,
                      cir::FuncOp fn, cir::FuncType funcType,
-                     clang::SourceLocation loc, clang::SourceLocation 
startLoc);
+                     FunctionArgList args, clang::SourceLocation loc,
+                     clang::SourceLocation startLoc);
 
   Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,
                            const Twine &name = "tmp");
diff --git a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp 
b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
index af6b5e4fbd9f6..5e44837979af3 100644
--- a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp
@@ -75,3 +75,36 @@ DeletionKind cir::LoadOp::removeBlockingUses(
   getResult().replaceAllUsesWith(reachingDefinition);
   return DeletionKind::Delete;
 }
+
+//===----------------------------------------------------------------------===//
+// Interfaces for StoreOp
+//===----------------------------------------------------------------------===//
+
+bool cir::StoreOp::loadsFrom(const MemorySlot &slot) { return false; }
+
+bool cir::StoreOp::storesTo(const MemorySlot &slot) {
+  return getAddr() == slot.ptr;
+}
+
+Value cir::StoreOp::getStored(const MemorySlot &slot, OpBuilder &builder,
+                              Value reachingDef, const DataLayout &dataLayout) 
{
+  return getValue();
+}
+
+bool cir::StoreOp::canUsesBeRemoved(
+    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
+    SmallVectorImpl<OpOperand *> &newBlockingUses,
+    const DataLayout &dataLayout) {
+  if (blockingUses.size() != 1)
+    return false;
+  Value blockingUse = (*blockingUses.begin())->get();
+  return blockingUse == slot.ptr && getAddr() == slot.ptr &&
+         getValue() != slot.ptr && slot.elemType == getValue().getType();
+}
+
+DeletionKind cir::StoreOp::removeBlockingUses(
+    const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
+    OpBuilder &builder, Value reachingDefinition,
+    const DataLayout &dataLayout) {
+  return DeletionKind::Delete;
+}
diff --git a/clang/test/CIR/CodeGen/basic.cpp b/clang/test/CIR/CodeGen/basic.cpp
index 210afcd541159..6a2faa725a34d 100644
--- a/clang/test/CIR/CodeGen/basic.cpp
+++ b/clang/test/CIR/CodeGen/basic.cpp
@@ -25,3 +25,23 @@ int f2() {
 // CHECK:    %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 
32>>, ["i", const] {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>
+
+int f3(int i) {
+    return 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:   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>
+
+int f4(const int i) {
+  return 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:   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>

>From 9f548a1492a3da5d9f1d4358916f88531e0dc9e7 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akay...@nvidia.com>
Date: Fri, 28 Feb 2025 10:39:09 -0800
Subject: [PATCH 2/2] Replace auto with correct types

---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 76912d412fd06..7861a48c93244 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -169,10 +169,10 @@ void CIRGenFunction::startFunction(GlobalDecl gd, 
QualType returnType,
   // TODO(cir): this should live in `emitFunctionProlog
   // Declare all the function arguments in the symbol table.
   for (const auto nameValue : llvm::zip(args, entryBB->getArguments())) {
-    auto *paramVar = std::get<0>(nameValue);
+    const VarDecl *paramVar = std::get<0>(nameValue);
     mlir::Value paramVal = std::get<1>(nameValue);
-    auto alignment = getContext().getDeclAlign(paramVar);
-    auto paramLoc = getLoc(paramVar->getSourceRange());
+    CharUnits alignment = getContext().getDeclAlign(paramVar);
+    mlir::Location paramLoc = getLoc(paramVar->getSourceRange());
     paramVal.setLoc(paramLoc);
 
     mlir::Value addrVal =

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

Reply via email to