================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits