[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