================
@@ -3055,47 +3056,139 @@ Address
CIRGenFunction::createDefaultAlignTempAlloca(mlir::Type ty,
return createTempAlloca(ty, align, loc, name);
}
+/// Given an object of the given canonical type, can we safely copy a
+/// value out of it based on its initializer?
+static bool isConstantEmittableObjectType(QualType type) {
+ assert(type.isCanonical());
+ assert(!type->isReferenceType());
+
+ // Must be const-qualified but non-volatile.
+ Qualifiers qs = type.getLocalQualifiers();
+ if (!qs.hasConst() || qs.hasVolatile())
+ return false;
+
+ // Otherwise, all object types satisfy this except C++ classes with
+ // mutable subobjects or non-trivial copy/destroy behavior.
+ if (const auto *rt = dyn_cast<clang::RecordType>(type))
+ if (const auto *rd = dyn_cast<CXXRecordDecl>(rt->getDecl())) {
+ rd = rd->getDefinitionOrSelf();
+ if (rd->hasMutableFields() || !rd->isTrivial())
+ return false;
+ }
+
+ return true;
+}
+
+/// Can we constant-emit a load of a reference to a variable of the
+/// given type? This is different from predicates like
+/// Decl::mightBeUsableInConstantExpressions because we do want it to apply
+/// in situations that don't necessarily satisfy the language's rules
+/// for this (e.g. C++'s ODR-use rules). For example, we want to able
+/// to do this with const float variables even if those variables
+/// aren't marked 'constexpr'.
+enum ConstantEmissionKind {
+ CEK_None,
+ CEK_AsReferenceOnly,
+ CEK_AsValueOrReference,
+ CEK_AsValueOnly
+};
+static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) {
+ type = type.getCanonicalType();
+ if (const auto *ref = dyn_cast<ReferenceType>(type)) {
+ if (isConstantEmittableObjectType(ref->getPointeeType()))
+ return CEK_AsValueOrReference;
+ return CEK_AsReferenceOnly;
+ }
+ if (isConstantEmittableObjectType(type))
+ return CEK_AsValueOnly;
+ return CEK_None;
+}
+
/// Try to emit a reference to the given value without producing it as
-/// an l-value. For many cases, this is just an optimization, but it avoids
-/// us needing to emit global copies of variables if they're named without
-/// triggering a formal use in a context where we can't emit a direct
-/// reference to them, for instance if a block or lambda or a member of a
-/// local class uses a const int variable or constexpr variable from an
-/// enclosing function.
-///
-/// For named members of enums, this is the only way they are emitted.
+/// an l-value. This is just an optimization, but it avoids us needing
+/// to emit global copies of variables if they're named without triggering
+/// a formal use in a context where we can't emit a direct reference to them,
+/// for instance if a block or lambda or a member of a local class uses a
+/// const int variable or constexpr variable from an enclosing function.
CIRGenFunction::ConstantEmission
CIRGenFunction::tryEmitAsConstant(const DeclRefExpr *refExpr) {
const ValueDecl *value = refExpr->getDecl();
- // There is a lot more to do here, but for now only EnumConstantDecl is
- // supported.
- assert(!cir::MissingFeatures::tryEmitAsConstant());
-
// The value needs to be an enum constant or a constant variable.
- if (!isa<EnumConstantDecl>(value))
+ ConstantEmissionKind cek;
+ if (isa<ParmVarDecl>(value))
+ cek = CEK_None;
+ else if (const auto *var = dyn_cast<VarDecl>(value))
+ cek = checkVarTypeForConstantEmission(var->getType());
+ else if (isa<EnumConstantDecl>(value))
+ cek = CEK_AsValueOnly;
+ else
+ cek = CEK_None;
+ if (cek == CEK_None)
return ConstantEmission();
Expr::EvalResult result;
- if (!refExpr->EvaluateAsRValue(result, getContext()))
+ bool resultIsReference;
+ QualType resultType;
+
+ // It's best to evaluate all the way as an r-value if that's permitted.
+ if (cek != CEK_AsReferenceOnly &&
+ refExpr->EvaluateAsRValue(result, getContext())) {
+ resultIsReference = false;
+ resultType = refExpr->getType().getUnqualifiedType();
+
+ // Otherwise, try to evaluate as an l-value.
+ } else if (cek != CEK_AsValueOnly &&
+ refExpr->EvaluateAsLValue(result, getContext())) {
+ resultIsReference = true;
+ resultType = value->getType();
+
+ // Failure.
----------------
koparasy wrote:
Done in f3296ce
https://github.com/llvm/llvm-project/pull/231689
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits