================
@@ -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.
----------------
andykaylor wrote:

I see that this is copied from classic codegen, but it bothers me that this 
comment is in the scope above the one to which it applies. I don't think this 
comment is generally useful anyway.

https://github.com/llvm/llvm-project/pull/231689
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to