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(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); } 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(E)); + Ret = EmitObjCSelectorLValue(cast(E)); + break; case Expr::ObjCIsaExprClass: - return EmitObjCIsaExpr(cast(E)); + Ret = EmitObjCIsaExpr(cast(E)); + break; case Expr::BinaryOperatorClass: - return EmitBinaryOperatorLValue(cast(E)); + Ret = EmitBinaryOperatorLValue(cast(E)); + break; case Expr::CompoundAssignOperatorClass: { QualType Ty = E->getType(); if (const AtomicType *AT = Ty->getAs()) Ty = AT->getValueType(); if (!Ty->isAnyComplexType()) - return EmitCompoundAssignmentLValue(cast(E)); - return EmitComplexCompoundAssignmentLValue(cast(E)); + Ret = EmitCompoundAssignmentLValue(cast(E)); + else + Ret = + EmitComplexCompoundAssignmentLValue(cast(E)); + break; } case Expr::CallExprClass: case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: case Expr::UserDefinedLiteralClass: - return EmitCallExprLValue(cast(E)); + Ret = EmitCallExprLValue(cast(E)); + break; case Expr::CXXRewrittenBinaryOperatorClass: - return EmitLValue(cast(E)->getSemanticForm()); + Ret = EmitLValue(cast(E)->getSemanticForm()); + break; case Expr::VAArgExprClass: - return EmitVAArgExprLValue(cast(E)); + Ret = EmitVAArgExprLValue(cast(E)); + break; case Expr::DeclRefExprClass: - return EmitDeclRefLValue(cast(E)); + Ret = EmitDeclRefLValue(cast(E)); + break; case Expr::ConstantExprClass: - return EmitLValue(cast(E)->getSubExpr()); + Ret = EmitLValue(cast(E)->getSubExpr()); + break; case Expr::ParenExprClass: - return EmitLValue(cast(E)->getSubExpr()); + Ret = EmitLValue(cast(E)->getSubExpr()); + break; case Expr::GenericSelectionExprClass: - return EmitLValue(cast(E)->getResultExpr()); + Ret = EmitLValue(cast(E)->getResultExpr()); + break; case Expr::PredefinedExprClass: - return EmitPredefinedLValue(cast(E)); + Ret = EmitPredefinedLValue(cast(E)); + break; case Expr::StringLiteralClass: - return EmitStringLiteralLValue(cast(E)); + Ret = EmitStringLiteralLValue(cast(E)); + break; case Expr::ObjCEncodeExprClass: - return EmitObjCEncodeExprLValue(cast(E)); + Ret = EmitObjCEncodeExprLValue(cast(E)); + break; case Expr::PseudoObjectExprClass: - return EmitPseudoObjectLValue(cast(E)); + Ret = EmitPseudoObjectLValue(cast(E)); + break; case Expr::InitListExprClass: - return EmitInitListLValue(cast(E)); + Ret = EmitInitListLValue(cast(E)); + break; case Expr::CXXTemporaryObjectExprClass: case Expr::CXXConstructExprClass: - return EmitCXXConstructLValue(cast(E)); + Ret = EmitCXXConstructLValue(cast(E)); + break; case Expr::CXXBindTemporaryExprClass: - return EmitCXXBindTemporaryLValue(cast(E)); + Ret = EmitCXXBindTemporaryLValue(cast(E)); + break; case Expr::CXXUuidofExprClass: - return EmitCXXUuidofLValue(cast(E)); + Ret = EmitCXXUuidofLValue(cast(E)); + break; case Expr::LambdaExprClass: - return EmitAggExprToLValue(E); + Ret = EmitAggExprToLValue(E); + break; case Expr::ExprWithCleanupsClass: { const auto *cleanups = cast(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(E); CXXDefaultArgExprScope Scope(*this, DAE); - return EmitLValue(DAE->getExpr()); + Ret = EmitLValue(DAE->getExpr()); + break; } case Expr::CXXDefaultInitExprClass: { auto *DIE = cast(E); CXXDefaultInitExprScope Scope(*this, DIE); - return EmitLValue(DIE->getExpr()); + Ret = EmitLValue(DIE->getExpr()); + break; } case Expr::CXXTypeidExprClass: - return EmitCXXTypeidLValue(cast(E)); + Ret = EmitCXXTypeidLValue(cast(E)); + break; case Expr::ObjCMessageExprClass: - return EmitObjCMessageExprLValue(cast(E)); + Ret = EmitObjCMessageExprLValue(cast(E)); + break; case Expr::ObjCIvarRefExprClass: - return EmitObjCIvarRefLValue(cast(E)); + Ret = EmitObjCIvarRefLValue(cast(E)); + break; case Expr::StmtExprClass: - return EmitStmtExprLValue(cast(E)); + Ret = EmitStmtExprLValue(cast(E)); + break; case Expr::UnaryOperatorClass: - return EmitUnaryOpLValue(cast(E)); + Ret = EmitUnaryOpLValue(cast(E)); + break; case Expr::ArraySubscriptExprClass: - return EmitArraySubscriptExpr(cast(E)); + Ret = EmitArraySubscriptExpr(cast(E)); + break; case Expr::OMPArraySectionExprClass: - return EmitOMPArraySectionExpr(cast(E)); + Ret = EmitOMPArraySectionExpr(cast(E)); + break; case Expr::ExtVectorElementExprClass: - return EmitExtVectorElementExpr(cast(E)); + Ret = EmitExtVectorElementExpr(cast(E)); + break; case Expr::MemberExprClass: - return EmitMemberExpr(cast(E)); + Ret = EmitMemberExpr(cast(E)); + break; case Expr::CompoundLiteralExprClass: - return EmitCompoundLiteralLValue(cast(E)); + Ret = EmitCompoundLiteralLValue(cast(E)); + break; case Expr::ConditionalOperatorClass: - return EmitConditionalOperatorLValue(cast(E)); + Ret = EmitConditionalOperatorLValue(cast(E)); + break; case Expr::BinaryConditionalOperatorClass: - return EmitConditionalOperatorLValue(cast(E)); + Ret = EmitConditionalOperatorLValue(cast(E)); + break; case Expr::ChooseExprClass: - return EmitLValue(cast(E)->getChosenSubExpr()); + Ret = EmitLValue(cast(E)->getChosenSubExpr()); + break; case Expr::OpaqueValueExprClass: - return EmitOpaqueValueLValue(cast(E)); + Ret = EmitOpaqueValueLValue(cast(E)); + break; case Expr::SubstNonTypeTemplateParmExprClass: - return EmitLValue(cast(E)->getReplacement()); + Ret = EmitLValue(cast(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(E)); + Ret = EmitCastLValue(cast(E)); + break; case Expr::MaterializeTemporaryExprClass: - return EmitMaterializeTemporaryExpr(cast(E)); + Ret = EmitMaterializeTemporaryExpr(cast(E)); + break; case Expr::CoawaitExprClass: - return EmitCoawaitLValue(cast(E)); + Ret = EmitCoawaitLValue(cast(E)); + break; case Expr::CoyieldExprClass: - return EmitCoyieldLValue(cast(E)); + Ret = EmitCoyieldLValue(cast(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(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/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(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/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/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; +}