[clang] [CIR] Emit init of local variables (PR #130164)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 6 12:38:58 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);
----------------
andykaylor wrote:
I should probably have looked at this a bit closer. I think the idea is that validateAndPopAbstract might need to do some kind of clean up and could possibly fail, but that isn't happening, even in the LLVM IR codegen that this was modeled after. In the original codegen, it asserts that the placeholder list size hasn't changed, but it doesn't do anything with the constant. I don't see any problem with making this an RAII.
https://github.com/llvm/llvm-project/pull/130164
More information about the cfe-commits
mailing list