yaxunl created this revision.
yaxunl added a reviewer: rjmccall.

We saw users intend to use `const int* restrict` to indicate the memory pointed 
to by the pointer is invariant.

This makes sense since restrict means the memory is not aliased by any other 
pointers whereas const
means the memory does not change.

Mark such pointer or reference as invariant allows more optimization 
opportunities.

This gives users a way to mark something as invariant.


https://reviews.llvm.org/D75285

Files:
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/test/CodeGenCXX/invariant.cpp

Index: clang/test/CodeGenCXX/invariant.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/invariant.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -O3 -emit-llvm -o - %s | FileCheck %s
+
+typedef struct {
+  int a;
+  char b;
+} X;
+
+const int* __restrict p;
+
+// CHECK-LABEL: test1
+// CHECK: llvm.invariant.start
+int test1() {
+  return *p;
+}
+
+// CHECK-LABEL: test2
+// CHECK: llvm.invariant.start
+char test2(X *x) {
+  const char* __restrict p = &(x->b);
+  return *p;
+}
+
+// CHECK-LABEL: test3
+// CHECK: llvm.invariant.start
+char test3(X &x) {
+  const char& __restrict p = x.b;
+  return p;
+}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4070,7 +4070,7 @@
                                 llvm::GlobalVariable *GV);
 
   // Emit an @llvm.invariant.start call for the given memory region.
-  void EmitInvariantStart(llvm::Constant *Addr, CharUnits Size);
+  void EmitInvariantStart(llvm::Value *Addr, CharUnits Size);
 
   /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
   /// variable with global storage.
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -308,6 +308,20 @@
                                 E->getExprLoc());
 
     EmitLValueAlignmentAssumption(E, V);
+
+    // Mark a restrict pointer or to const as invariant.
+    if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+      const ValueDecl *VD = DRE->getDecl();
+      auto QT = VD->getType();
+      if (QT->isPointerType()) {
+        auto PointeeTy = QT->getPointeeType();
+        if (PointeeTy.isConstQualified() && QT.isRestrictQualified()) {
+          CGF.EmitInvariantStart(
+              V, CGF.getContext().getTypeSizeInChars(PointeeTy));
+        }
+      }
+    }
+
     return V;
   }
 
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -1252,62 +1252,88 @@
 ///
 LValue CodeGenFunction::EmitLValue(const Expr *E) {
   ApplyDebugLocation DL(*this, E);
+  LValue Ret;
   switch (E->getStmtClass()) {
-  default: return EmitUnsupportedLValue(E, "l-value expression");
+  default:
+    Ret = EmitUnsupportedLValue(E, "l-value expression");
+    break;
 
   case Expr::ObjCPropertyRefExprClass:
     llvm_unreachable("cannot emit a property reference directly");
+    break;
 
   case Expr::ObjCSelectorExprClass:
-    return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
+    Ret = EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
+    break;
   case Expr::ObjCIsaExprClass:
-    return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
+    Ret = EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
+    break;
   case Expr::BinaryOperatorClass:
-    return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
+    Ret = EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
+    break;
   case Expr::CompoundAssignOperatorClass: {
     QualType Ty = E->getType();
     if (const AtomicType *AT = Ty->getAs<AtomicType>())
       Ty = AT->getValueType();
     if (!Ty->isAnyComplexType())
-      return EmitCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
-    return EmitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
+      Ret = EmitCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
+    else
+      Ret =
+          EmitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
+    break;
   }
   case Expr::CallExprClass:
   case Expr::CXXMemberCallExprClass:
   case Expr::CXXOperatorCallExprClass:
   case Expr::UserDefinedLiteralClass:
-    return EmitCallExprLValue(cast<CallExpr>(E));
+    Ret = EmitCallExprLValue(cast<CallExpr>(E));
+    break;
   case Expr::CXXRewrittenBinaryOperatorClass:
-    return EmitLValue(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
+    Ret = EmitLValue(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
+    break;
   case Expr::VAArgExprClass:
-    return EmitVAArgExprLValue(cast<VAArgExpr>(E));
+    Ret = EmitVAArgExprLValue(cast<VAArgExpr>(E));
+    break;
   case Expr::DeclRefExprClass:
-    return EmitDeclRefLValue(cast<DeclRefExpr>(E));
+    Ret = EmitDeclRefLValue(cast<DeclRefExpr>(E));
+    break;
   case Expr::ConstantExprClass:
-    return EmitLValue(cast<ConstantExpr>(E)->getSubExpr());
+    Ret = EmitLValue(cast<ConstantExpr>(E)->getSubExpr());
+    break;
   case Expr::ParenExprClass:
-    return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+    Ret = EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+    break;
   case Expr::GenericSelectionExprClass:
-    return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
+    Ret = EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
+    break;
   case Expr::PredefinedExprClass:
-    return EmitPredefinedLValue(cast<PredefinedExpr>(E));
+    Ret = EmitPredefinedLValue(cast<PredefinedExpr>(E));
+    break;
   case Expr::StringLiteralClass:
-    return EmitStringLiteralLValue(cast<StringLiteral>(E));
+    Ret = EmitStringLiteralLValue(cast<StringLiteral>(E));
+    break;
   case Expr::ObjCEncodeExprClass:
-    return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
+    Ret = EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
+    break;
   case Expr::PseudoObjectExprClass:
-    return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
+    Ret = EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
+    break;
   case Expr::InitListExprClass:
-    return EmitInitListLValue(cast<InitListExpr>(E));
+    Ret = EmitInitListLValue(cast<InitListExpr>(E));
+    break;
   case Expr::CXXTemporaryObjectExprClass:
   case Expr::CXXConstructExprClass:
-    return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
+    Ret = EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
+    break;
   case Expr::CXXBindTemporaryExprClass:
-    return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+    Ret = EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+    break;
   case Expr::CXXUuidofExprClass:
-    return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E));
+    Ret = EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E));
+    break;
   case Expr::LambdaExprClass:
-    return EmitAggExprToLValue(E);
+    Ret = EmitAggExprToLValue(E);
+    break;
 
   case Expr::ExprWithCleanupsClass: {
     const auto *cleanups = cast<ExprWithCleanups>(E);
@@ -1319,55 +1345,74 @@
       // cleanups.
       llvm::Value *V = LV.getPointer(*this);
       Scope.ForceCleanup({&V});
-      return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
-                              getContext(), LV.getBaseInfo(), LV.getTBAAInfo());
+      Ret = LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
+                             getContext(), LV.getBaseInfo(), LV.getTBAAInfo());
     }
     // FIXME: Is it possible to create an ExprWithCleanups that produces a
     // bitfield lvalue or some other non-simple lvalue?
-    return LV;
+    else
+      Ret = LV;
+    break;
   }
 
   case Expr::CXXDefaultArgExprClass: {
     auto *DAE = cast<CXXDefaultArgExpr>(E);
     CXXDefaultArgExprScope Scope(*this, DAE);
-    return EmitLValue(DAE->getExpr());
+    Ret = EmitLValue(DAE->getExpr());
+    break;
   }
   case Expr::CXXDefaultInitExprClass: {
     auto *DIE = cast<CXXDefaultInitExpr>(E);
     CXXDefaultInitExprScope Scope(*this, DIE);
-    return EmitLValue(DIE->getExpr());
+    Ret = EmitLValue(DIE->getExpr());
+    break;
   }
   case Expr::CXXTypeidExprClass:
-    return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
+    Ret = EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
+    break;
 
   case Expr::ObjCMessageExprClass:
-    return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
+    Ret = EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
+    break;
   case Expr::ObjCIvarRefExprClass:
-    return EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
+    Ret = EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
+    break;
   case Expr::StmtExprClass:
-    return EmitStmtExprLValue(cast<StmtExpr>(E));
+    Ret = EmitStmtExprLValue(cast<StmtExpr>(E));
+    break;
   case Expr::UnaryOperatorClass:
-    return EmitUnaryOpLValue(cast<UnaryOperator>(E));
+    Ret = EmitUnaryOpLValue(cast<UnaryOperator>(E));
+    break;
   case Expr::ArraySubscriptExprClass:
-    return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
+    Ret = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
+    break;
   case Expr::OMPArraySectionExprClass:
-    return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
+    Ret = EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
+    break;
   case Expr::ExtVectorElementExprClass:
-    return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
+    Ret = EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
+    break;
   case Expr::MemberExprClass:
-    return EmitMemberExpr(cast<MemberExpr>(E));
+    Ret = EmitMemberExpr(cast<MemberExpr>(E));
+    break;
   case Expr::CompoundLiteralExprClass:
-    return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
+    Ret = EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
+    break;
   case Expr::ConditionalOperatorClass:
-    return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
+    Ret = EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
+    break;
   case Expr::BinaryConditionalOperatorClass:
-    return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
+    Ret = EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
+    break;
   case Expr::ChooseExprClass:
-    return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
+    Ret = EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
+    break;
   case Expr::OpaqueValueExprClass:
-    return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
+    Ret = EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
+    break;
   case Expr::SubstNonTypeTemplateParmExprClass:
-    return EmitLValue(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
+    Ret = EmitLValue(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
+    break;
   case Expr::ImplicitCastExprClass:
   case Expr::CStyleCastExprClass:
   case Expr::CXXFunctionalCastExprClass:
@@ -1376,16 +1421,36 @@
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXConstCastExprClass:
   case Expr::ObjCBridgedCastExprClass:
-    return EmitCastLValue(cast<CastExpr>(E));
+    Ret = EmitCastLValue(cast<CastExpr>(E));
+    break;
 
   case Expr::MaterializeTemporaryExprClass:
-    return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
+    Ret = EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
+    break;
 
   case Expr::CoawaitExprClass:
-    return EmitCoawaitLValue(cast<CoawaitExpr>(E));
+    Ret = EmitCoawaitLValue(cast<CoawaitExpr>(E));
+    break;
   case Expr::CoyieldExprClass:
-    return EmitCoyieldLValue(cast<CoyieldExpr>(E));
+    Ret = EmitCoyieldLValue(cast<CoyieldExpr>(E));
+    break;
   }
+
+  // Mark a restrict reference to const as invariant.
+  // ToDo: Now we only handle DeclRefExpr. We should handle more cases later.
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+    const ValueDecl *VD = DRE->getDecl();
+    auto QT = VD->getType();
+    if (QT->isReferenceType()) {
+      auto PointeeTy = QT->getPointeeType();
+      if (PointeeTy.isConstQualified() && QT.isRestrictQualified()) {
+        EmitInvariantStart(Ret.getPointer(*this),
+                           getContext().getTypeSizeInChars(PointeeTy));
+      }
+    }
+  }
+
+  return Ret;
 }
 
 /// Given an object of the given canonical type, can we safely copy a
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -153,7 +153,7 @@
       Addr, CGF.getContext().getTypeSizeInChars(D.getType()));
 }
 
-void CodeGenFunction::EmitInvariantStart(llvm::Constant *Addr, CharUnits Size) {
+void CodeGenFunction::EmitInvariantStart(llvm::Value *Addr, CharUnits Size) {
   // Do not emit the intrinsic if we're not optimizing.
   if (!CGM.getCodeGenOpts().OptimizationLevel)
     return;
@@ -166,8 +166,12 @@
 
   // Emit a call with the size in bytes of the object.
   uint64_t Width = Size.getQuantity();
-  llvm::Value *Args[2] = { llvm::ConstantInt::getSigned(Int64Ty, Width),
-                           llvm::ConstantExpr::getBitCast(Addr, Int8PtrTy)};
+  llvm::Value *Cast;
+  if (llvm::Constant *C = dyn_cast<llvm::Constant>(Addr))
+    Cast = llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+  else
+    Cast = Builder.CreateBitCast(Addr, Int8PtrTy);
+  llvm::Value *Args[2] = {llvm::ConstantInt::getSigned(Int64Ty, Width), Cast};
   Builder.CreateCall(InvariantStart, Args);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to