For unused constexpr aggregates that make it into codegen - emit them as 
temporary variables as suggested by Eli Friedman.

  All tests seems to pass.

  Thoughts?

  Thanks!

Hi rsmith, rjmccall, doug.gregor,

http://llvm-reviews.chandlerc.com/D1140

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D1140?vs=2805&id=6114#toc

Files:
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  test/CodeGenCXX/value-init.cpp
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -100,9 +100,11 @@
 /// EmitIgnoredExpr - Emit code to compute the specified expression,
 /// ignoring the result.
 void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
+  llvm::APSInt Value;
   if (E->isRValue())
     return (void) EmitAnyExpr(E, AggValueSlot::ignored(), true);
-
+  else if (E->EvaluateAsInt(Value, getContext(), Expr::SE_AllowSideEffects))
+    return (void) EmitAnyExpr(E, AggValueSlot::ignored(), true);
   // Just emit it as an l-value and drop the result.
   EmitLValue(E);
 }
@@ -1734,6 +1736,16 @@
   return CGF.EmitLValueForField(LV, FD);
 }
 
+// This requires the variable to be non-dependent and the initializer
+// to not be value dependent.
+inline bool isVariableAConstantExpression(const VarDecl *Var,
+                                          ASTContext &Context) {
+  const VarDecl *DefVD = 0;
+  return !isa<ParmVarDecl>(Var) &&
+         Var->isUsableInConstantExpressions(Context) &&
+         Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE();
+}
+
 LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
   const NamedDecl *ND = E->getDecl();
   CharUnits Alignment = getContext().getDeclAlign(ND);
@@ -1752,6 +1764,17 @@
       // FIXME: Eventually we will want to emit vector element references.
       return MakeAddrLValue(Val, T, Alignment);
     }
+    // If a variable is not used - and it is an aggregate type - it better
+    // be a constant expression - and if so, emit it as a temporary variable.
+    // We must use the NameDecl here - the VarDecl gives the wrong result!
+    // FVQUESTION? Why must we used the NamedDecl to check for use?
+    if (!ND->isUsed(false) && E->getLocation().isValid()) {
+      assert(isVariableAConstantExpression(VD, getContext()) && 
+        "A variable that is not used must be a constant");
+      assert(Init);
+      assert(hasAggregateEvaluationKind(VD->getType()));
+      return EmitAggExprToLValue(Init);
+    }
   }
 
   // FIXME: We should be able to assert this for FunctionDecls as well!
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -502,9 +502,21 @@
   Value *VisitBinLOr        (const BinaryOperator *E);
   Value *VisitBinComma      (const BinaryOperator *E);
 
-  Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); }
-  Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); }
+  Value *VisitBinPtrMemD(const BinaryOperator *E, bool IsArrow = false) { 
+    ASTContext &Context = CGF.getContext();
+    llvm::APSInt Result;
+    const Expr *ObjExpr = E->getLHS();
+    if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) {
+      if (!IsArrow && ObjExpr->isCXX11ConstantExpr(CGF.getContext())) 
+        return Builder.getInt(Result);
+    }
+    return EmitLoadOfLValue(E); 
+  }
 
+  Value *VisitBinPtrMemI(const BinaryOperator *E) {
+    return VisitBinPtrMemD(E, true);
+  }
+
   // Other Operators.
   Value *VisitBlockExpr(const BlockExpr *BE);
   Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *);
@@ -1044,16 +1056,23 @@
   return Res;
 }
 
+
 Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
   llvm::APSInt Value;
   if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
     if (E->isArrow())
       CGF.EmitScalarExpr(E->getBase());
-    else
+    else {
+      // FVQUESTION: If we can do the constant folding, and our base object is a
+      // constexpr then we can ignore any side-effects and just use the folded
+      // constant?
+
+      if (E->getBase()->isCXX11ConstantExpr(CGF.getContext()))
+        return Builder.getInt(Value);
       EmitLValue(E->getBase());
+    }
     return Builder.getInt(Value);
   }
-
   return EmitLoadOfLValue(E);
 }
 
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -12019,30 +12019,85 @@
   return IsVariableAConstantExpression(Var, Context); 
 }
 
+namespace {
+struct PotentialResultsSetFinder : ConstStmtVisitor<PotentialResultsSetFinder> {
+  llvm::SmallPtrSet<Expr *, 2> &MaybeODRUseExprs;
+  LambdaScopeInfo *CurLambdaLSI;
+  ASTContext &Context;
+  PotentialResultsSetFinder(llvm::SmallPtrSet<Expr *, 2> &MaybeODRUseExprs,
+                            LambdaScopeInfo *LSI, ASTContext &Context)
+      : MaybeODRUseExprs(MaybeODRUseExprs), CurLambdaLSI(LSI),
+        Context(Context) {}
+  // C++1y DR712 3.2 para 2
+  // The set of potential results of an expression e is defined as follows:
 
+  // -- If e is an id-expression (5.1.1), the set contains only e.
+  void VisitDeclRefExpr(const DeclRefExpr *E) {
+    MaybeODRUseExprs.erase(const_cast<DeclRefExpr *>(E));
+    // If we are in a lambda, check if this DeclRefExpr refers
+    // to a variable that is a constant expression, and if so, identify it as
+    // a reference to a variable that does not involve an odr-use of that
+    // variable.
+    if (CurLambdaLSI) {
+      const VarDecl *Var = dyn_cast<VarDecl>(E->getFoundDecl());
+      if (Var && IsVariableNonDependentAndAConstantExpression(
+                     const_cast<VarDecl *>(Var), Context))
+        CurLambdaLSI->markVariableExprAsNonODRUsed(
+            const_cast<DeclRefExpr *>(E));
+    }
+  }
+  //  -- If e is a class member access expression (5.2.5), the set contains
+  //     the potential results of the object expression.
+  void VisitMemberExpr(const MemberExpr *E) {
+    Expr *ObjectExpression = E->getBase();
+    // The c++ standard states that the following is not a constant
+    // expression:
+    //  struct A { mutable int x; };
+    //  constexpr A a{10}; 
+    //  int i = a.k; // a.k can not be a constant expression!
+
+    const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+    
+    if (!FD || !FD->isMutable())
+      Visit(ObjectExpression);
+  }
+  // -- If e is a pointer-to-member expression (5.5) whose second operand
+  //    is a constant expression, the set contains the potential results of
+  //    the object expression.
+  void VisitBinPtrMemD(const BinaryOperator *E) {
+    Expr *SecondOperand = E->getRHS();
+    if (SecondOperand->isCXX11ConstantExpr(Context))
+      Visit(E->getLHS());
+  }
+  void VisitBinPtrMemI(const BinaryOperator *E) { VisitBinPtrMemD(E); }
+
+  // -- If e has the form (e1), the set contains the potential results of e1.
+  void VisitParenExpr(const ParenExpr *E) { Visit(E->getSubExpr()); }
+  // -- If e is a glvalue conditional expression (5.16), the set is the
+  //    union of the sets of potential results of the second and third
+  //    operands.
+  void VisitConditionalOperator(const ConditionalOperator *CO) {
+    if (CO->isGLValue()) {
+      Visit(CO->getTrueExpr());
+      Visit(CO->getFalseExpr());
+    }
+  }
+
+  // -- If e is a comma expression (5.18), the set contains the potential
+  //    results of the right operand.
+  void VisitBinComma(const BinaryOperator *E) { Visit(E->getRHS()); }
+  // -- Otherwise, the set is empty.
+  void VisitStmt(const Stmt *) { return; }
+};
+}
+
 void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
   // Per C++11 [basic.def.odr], a variable is odr-used "unless it is 
   // an object that satisfies the requirements for appearing in a
   // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
   // is immediately applied."  This function handles the lvalue-to-rvalue
   // conversion part.
-  MaybeODRUseExprs.erase(E->IgnoreParens());
-  
-  // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
-  // to a variable that is a constant expression, and if so, identify it as
-  // a reference to a variable that does not involve an odr-use of that 
-  // variable. 
-  if (LambdaScopeInfo *LSI = getCurLambda()) {
-    Expr *SansParensExpr = E->IgnoreParens();
-    VarDecl *Var = 0;
-    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr)) 
-      Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
-    else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
-      Var = dyn_cast<VarDecl>(ME->getMemberDecl());
-    
-    if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context)) 
-      LSI->markVariableExprAsNonODRUsed(SansParensExpr);    
-  }
+  PotentialResultsSetFinder(MaybeODRUseExprs, getCurLambda(), Context).Visit(E);
 }
 
 ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5768,9 +5768,9 @@
 
   if (getLangOpts().CPlusPlus)  {
     // The C++11 standard defines the notion of a discarded-value expression;
-    // normally, we don't need to do anything to handle it, but if it is a
-    // volatile lvalue with a special form, we perform an lvalue-to-rvalue
-    // conversion.
+    // normally, we don't need to do any additional conversions to handle it, 
+    // but if it is a volatile lvalue with a special form, we perform an 
+    // lvalue-to-rvalue conversion. 
     if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
         E->getType().isVolatileQualified() &&
         IsSpecialDiscardedValue(E)) {
@@ -5778,7 +5778,12 @@
       if (Res.isInvalid())
         return Owned(E);
       E = Res.take();
-    } 
+    } else if (getLangOpts().CPlusPlus11 && E->isGLValue()) {
+      // Even if we do not perform an lvalue-to-rvalue conversion, 
+      // we pretend that one was performed when checking for odr-uses
+      // of variables.
+      UpdateMarkingForLValueToRValue(E);
+    }
     return Owned(E);
   }
 
Index: test/CodeGenCXX/value-init.cpp
===================================================================
--- test/CodeGenCXX/value-init.cpp
+++ test/CodeGenCXX/value-init.cpp
@@ -133,7 +133,7 @@
 
   // CHECK-LABEL: define i32 @_ZN8zeroinit4testEv()
   int test() {
-    // CHECK: call void @llvm.memset.p0i8.i64
+    // Should be folded, dont need to call void @llvm.memset.p0i8.i64
     // CHECK: ret i32 0
     return S().i;
   }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to