[clang] [CIR] Emit init of local variables (PR #130164)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 6 11:43:02 PST 2025


================
@@ -0,0 +1,322 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Constant Expr nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Address.h"
+#include "CIRGenConstantEmitter.h"
+#include "CIRGenFunction.h"
+#include "CIRGenModule.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/BuiltinAttributeInterfaces.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+//===----------------------------------------------------------------------===//
+//                             ConstExprEmitter
+//===----------------------------------------------------------------------===//
+
+// This class only needs to handle arrays, structs and unions.
+//
+// In LLVM codegen, when outside C++11 mode, those types are not constant
+// folded, while all other types are handled by constant folding.
+//
+// In CIR codegen, instead of folding things here, we should defer that work
+// to MLIR: do not attempt to do much here.
+class ConstExprEmitter
+    : public StmtVisitor<ConstExprEmitter, mlir::Attribute, QualType> {
+  CIRGenModule &cgm;
+  LLVM_ATTRIBUTE_UNUSED ConstantEmitter &emitter;
+
+public:
+  ConstExprEmitter(ConstantEmitter &emitter)
+      : cgm(emitter.cgm), emitter(emitter) {}
+
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  mlir::Attribute VisitStmt(Stmt *S, QualType T) { return {}; }
+
+  mlir::Attribute VisitConstantExpr(ConstantExpr *ce, QualType t) {
+    if (mlir::Attribute result = emitter.tryEmitConstantExpr(ce))
+      return result;
+    return Visit(ce->getSubExpr(), t);
+  }
+
+  mlir::Attribute VisitParenExpr(ParenExpr *pe, QualType t) {
+    return Visit(pe->getSubExpr(), t);
+  }
+
+  mlir::Attribute
+  VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *pe,
+                                    QualType t) {
+    return Visit(pe->getReplacement(), t);
+  }
+
+  mlir::Attribute VisitGenericSelectionExpr(GenericSelectionExpr *ge,
+                                            QualType t) {
+    return Visit(ge->getResultExpr(), t);
+  }
+
+  mlir::Attribute VisitChooseExpr(ChooseExpr *ce, QualType t) {
+    return Visit(ce->getChosenSubExpr(), t);
+  }
+
+  mlir::Attribute VisitCompoundLiteralExpr(CompoundLiteralExpr *e, QualType t) {
+    return Visit(e->getInitializer(), t);
+  }
+
+  mlir::Attribute VisitCastExpr(CastExpr *e, QualType destType) {
+    cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitCastExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitCXXDefaultInitExpr(CXXDefaultInitExpr *die, QualType t) {
+    cgm.errorNYI(die->getBeginLoc(),
+                 "ConstExprEmitter::VisitCXXDefaultInitExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitExprWithCleanups(ExprWithCleanups *e, QualType t) {
+    // Since this about constant emission no need to wrap this under a scope.
+    return Visit(e->getSubExpr(), t);
+  }
+
+  mlir::Attribute VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e,
+                                                QualType t) {
+    return Visit(e->getSubExpr(), t);
+  }
+
+  mlir::Attribute VisitImplicitValueInitExpr(ImplicitValueInitExpr *E,
+                                             QualType T) {
+    cgm.errorNYI(E->getBeginLoc(),
+                 "ConstExprEmitter::VisitImplicitValueInitExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitInitListExpr(InitListExpr *ile, QualType t) {
+    cgm.errorNYI(ile->getBeginLoc(), "ConstExprEmitter::VisitInitListExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *e,
+                                                QualType destType) {
+    mlir::Attribute c = Visit(e->getBase(), destType);
+    if (!c)
+      return {};
+
+    cgm.errorNYI(e->getBeginLoc(),
+                 "ConstExprEmitter::VisitDesignatedInitUpdateExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitCXXConstructExpr(CXXConstructExpr *e, QualType ty) {
+    cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitCXXConstructExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitStringLiteral(StringLiteral *e, QualType t) {
+    cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitStringLiteral");
+    return {};
+  }
+
+  mlir::Attribute VisitObjCEncodeExpr(ObjCEncodeExpr *e, QualType t) {
+    cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitObjCEncodeExpr");
+    return {};
+  }
+
+  mlir::Attribute VisitUnaryExtension(const UnaryOperator *e, QualType t) {
+    return Visit(e->getSubExpr(), t);
+  }
+
+  // Utility methods
+  mlir::Type convertType(QualType t) { return cgm.convertType(t); }
+};
+
+// TODO(cir): this can be shared with LLVM's codegen
+static QualType getNonMemoryType(CIRGenModule &cgm, QualType type) {
+  if (auto at = type->getAs<AtomicType>()) {
+    return cgm.getASTContext().getQualifiedType(at->getValueType(),
+                                                type.getQualifiers());
+  }
+  return type;
+}
+
+//===----------------------------------------------------------------------===//
+//                             ConstantEmitter
+//===----------------------------------------------------------------------===//
+
+mlir::Attribute ConstantEmitter::validateAndPopAbstract(mlir::Attribute c,
+                                                        AbstractState saved) {
+  abstract = saved.oldValue;
+
+  // No validation necessary for now.
+  // No cleanup to do for now.
+  return c;
+}
+
+mlir::Attribute
+ConstantEmitter::tryEmitAbstractForInitializer(const VarDecl &d) {
+  AbstractState state = pushAbstract();
+  mlir::Attribute c = tryEmitPrivateForVarInit(d);
+  return validateAndPopAbstract(c, state);
+}
+
+mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &d) {
+  // Make a quick check if variable can be default NULL initialized
+  // and avoid going through rest of code which may do, for c++11,
+  // initialization of memory to all NULLs.
+  if (!d.hasLocalStorage()) {
+    QualType ty = cgm.getASTContext().getBaseElementType(d.getType());
+    if (ty->isRecordType())
+      if (d.getInit() && isa<CXXConstructExpr>(d.getInit())) {
+        cgm.errorNYI(d.getInit()->getBeginLoc(),
+                     "tryEmitPrivateForVarInit CXXConstructExpr");
+        return {};
+      }
+  }
+  inConstantContext = d.hasConstantInitialization();
+
+  const Expr *e = d.getInit();
+  assert(e && "No initializer to emit");
+
+  QualType destType = d.getType();
+
+  if (!destType->isReferenceType()) {
+    QualType nonMemoryDestType = getNonMemoryType(cgm, destType);
+    if (mlir::Attribute c = ConstExprEmitter(*this).Visit(const_cast<Expr *>(e),
+                                                          nonMemoryDestType))
+      return emitForMemory(c, destType);
+  }
+
+  // Try to emit the initializer.  Note that this can allow some things that
+  // are not allowed by tryEmitPrivateForMemory alone.
+  if (APValue *value = d.evaluateValue())
+    return tryEmitPrivateForMemory(*value, destType);
+
+  return {};
+}
+
+mlir::Attribute ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *ce) {
+  if (!ce->hasAPValueResult())
+    return {};
+
+  QualType retType = ce->getType();
+  if (ce->isGLValue())
+    retType = cgm.getASTContext().getLValueReferenceType(retType);
+
+  return emitAbstract(ce->getBeginLoc(), ce->getAPValueResult(), retType);
+}
+
+mlir::Attribute ConstantEmitter::tryEmitPrivateForMemory(const APValue &value,
+                                                         QualType destType) {
+  QualType nonMemoryDestType = getNonMemoryType(cgm, destType);
+  mlir::Attribute c = tryEmitPrivate(value, nonMemoryDestType);
+  return (c ? emitForMemory(c, destType) : nullptr);
+}
+
+mlir::Attribute ConstantEmitter::emitAbstract(SourceLocation loc,
+                                              const APValue &value,
+                                              QualType destType) {
+  AbstractState state = pushAbstract();
+  mlir::Attribute c = tryEmitPrivate(value, destType);
+  c = validateAndPopAbstract(c, state);
----------------
erichkeane wrote:

BOTH cases we're doing `pushAbstract` and `validateAndPopAbstract`.  It seems to me that this should be a RAII container for push/pop, and have `validateAttribute` function instead. 

https://github.com/llvm/llvm-project/pull/130164


More information about the cfe-commits mailing list