lvoufo updated this revision to Diff 39464.

http://reviews.llvm.org/D13618

Files:
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCXX/const-invariant.cpp

Index: test/CodeGenCXX/const-invariant.cpp
===================================================================
--- test/CodeGenCXX/const-invariant.cpp
+++ test/CodeGenCXX/const-invariant.cpp
@@ -177,6 +177,8 @@
 
 void foo(const Type* const);
 void bar(Type);
+void foo(const int* const);
+void bar(int);
 #if defined(OBJ)
 void foo_d(const D* const);
 void bar_d(D);
@@ -359,6 +361,22 @@
   // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.end(
 }
 
+// Example 1 with const member of non-const object:
+// collects offsets in invariant_start call.
+void ex1_cm() {
+// CHECK: @_Z6ex1_cmv(
+#ifdef LOCAL
+  Type i(one());
+#endif
+
+  // CHECK-L-CO-OBJ: call void @_ZN1AC{{[0-9]+}}Ei({{.*}}* %i,
+  // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.start(i64 {{[0-9]+}}, i8* {{.*}},
+  bar(i.b);
+  foo(&i.b);  // Does not change i.b.
+  bar(i.b);
+  // CHECK-L-CO-OBJ: call {{.*}}@llvm.invariant.end({{.*}}, i64 {{[0-9]+}}, i8*
+}
+
 #endif  // #if defined(OBJ)
 
 // Example 1 with references and pointers:
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1904,10 +1904,41 @@
 
   llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
   void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
-  CodeGenModule::InvariantArgs EmitInvariantStart(const VarDecl &D,
-                                                  llvm::Value *Addr,
-                                                  bool IsGlobalConstant = true);
-  void EmitInvariantEnd(CodeGenModule::InvariantArgs &Args);
+
+  /// \brief Specifes arguments to invariant_start/end intrinsic calls.
+  struct InvariantArgs {
+    llvm::CallInst *StartInst;  // Contains invariant offsets.
+    llvm::Value *Size;          // TODO: Is this necessary?
+    llvm::Value *Addr;
+
+    InvariantArgs() : StartInst(nullptr), Size(nullptr), Addr(nullptr) {}
+    InvariantArgs(llvm::CallInst *C, llvm::Value *S, llvm::Value *A)
+        : StartInst(C), Size(S), Addr(A) {}
+  };
+
+  /// \brief Specifies type of invariant offsets in a given record.
+  typedef llvm::SmallVector<llvm::Value *, 8> OffsetsType;
+
+private:
+
+  /// \brief Specifies offsets and whether they have already been computed.
+  /// Note: empty offsets may or may not have been computed.
+  struct OffsetsInfoType {
+    bool Computed;
+    OffsetsType Offsets;
+    OffsetsInfoType() : Computed(false) { }
+  };
+
+  /// \brief A collection of invariant offsets per given record.
+  llvm::DenseMap<const CXXRecordDecl *, OffsetsInfoType> InvariantOffsets;
+
+  /// \brief Compute the invariant offsets of a given Record.
+  OffsetsType& ComputeInvariantOffsets(const CXXRecordDecl *Record);
+
+public:
+  InvariantArgs EmitInvariantStart(const VarDecl &D, llvm::Value *Addr,
+                                   bool IsGlobalConstant = true);
+  void EmitInvariantEnd(InvariantArgs &Args);
 
   llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
   void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
@@ -3226,7 +3257,7 @@
   CodeGenFunction &CGF;
   llvm::GlobalVariable *GV;
   llvm::AllocaInst *AI;
-  CodeGenModule::InvariantArgs Args;
+  CodeGenFunction::InvariantArgs Args;
 
  public:
   MarkWriteOnceWrittenRAII(CodeGenFunction &CGF, const VarDecl *D,
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -530,9 +530,9 @@
 
   /// A cleanup to call @llvm.invariant.end.
   class CallInvariantEnd final : public EHScopeStack::Cleanup {
-    CodeGenModule::InvariantArgs Args;
+    CodeGenFunction::InvariantArgs Args;
    public:
-    CallInvariantEnd(CodeGenModule::InvariantArgs &args) : Args(args) {}
+    CallInvariantEnd(CodeGenFunction::InvariantArgs &args) : Args(args) {}
 
     void Emit(CodeGenFunction &CGF, Flags flags) override {
       CGF.EmitInvariantEnd(Args);
@@ -927,74 +927,93 @@
   C->setDoesNotThrow();
 }
 
-/// Collect offsets in bits.
-static bool getInvariantOffsets(const CodeGenFunction &CGF, QualType Ty,
-                                llvm::SmallVectorImpl<llvm::Value *> &Args) {
-  ASTContext &Ctx = CGF.getContext();
-  bool FoundWriteOnce = false;
-  if (const CXXRecordDecl *Record =
-          Ctx.getBaseElementType(Ty)->getAsCXXRecordDecl()) {
-    for (const auto *Field : Record->fields()) {
-      assert(dyn_cast<FieldDecl>(Field) && "Field decls only.");
-      if (Field->getType().isWriteOnce(Ctx)) {
-        FoundWriteOnce = true;
-        CharUnits WidthChars = Ctx.getTypeSizeInChars(Ty);
-        uint64_t Width = WidthChars.getQuantity();
-        Args.push_back(llvm::ConstantInt::get(CGF.Int64Ty, Width));  // Size
-
-        uint64_t Offset = Ctx.getFieldOffset(Field);
-        Args.push_back(llvm::ConstantInt::get(CGF.Int64Ty, Offset));  // Offset
-      } else {
-        FoundWriteOnce |= getInvariantOffsets(CGF, Field->getType(), Args);
-      }
+CodeGenFunction::OffsetsType&
+CodeGenFunction::ComputeInvariantOffsets(const CXXRecordDecl *Record) {
+  ASTContext &Ctx = getContext();
+  auto &OffsetsInfo = InvariantOffsets.FindAndConstruct(Record).second;
+  OffsetsType &Args = OffsetsInfo.Offsets;
+
+  // If this has already been computed, then return the stored value.
+  if (OffsetsInfo.Computed) return Args;
+
+  // Otherwise, mark that this is computed.
+  OffsetsInfo.Computed = true;
+  assert(Args.empty() && "There should be no offset specified yet.");
+
+  // Trace through fields collecting offsets of writeonce candidates.
+  for (const auto *Field : Record->fields()) {
+    assert(dyn_cast<FieldDecl>(Field) && "Field decls only.");
+    QualType FieldType = Field->getType();
+    if (FieldType.isWriteOnce(Ctx)) {
+      CharUnits WidthChars = Ctx.getTypeSizeInChars(FieldType);
+      uint64_t Width = WidthChars.getQuantity();
+      Args.push_back(llvm::ConstantInt::get(Int64Ty, Width));  // Size
+
+      uint64_t Offset = Ctx.getFieldOffset(Field);
+      Args.push_back(llvm::ConstantInt::get(Int64Ty, Offset));  // Offset
+    } else if (const CXXRecordDecl *RecField =
+               Ctx.getBaseElementType(FieldType)->getAsCXXRecordDecl()) {
+      auto &FieldArgs = ComputeInvariantOffsets(RecField);
+      Args.insert(Args.end(), FieldArgs.begin(), FieldArgs.end());
     }
   }
-  return FoundWriteOnce;
+
+  return Args;
 }
 
 /// Emit code to cause the variable at the given address to be considered as
 /// constant from this point onwards.
-CodeGenModule::InvariantArgs CodeGenFunction::EmitInvariantStart(
+CodeGenFunction::InvariantArgs CodeGenFunction::EmitInvariantStart(
     const VarDecl &D, llvm::Value *Addr, bool IsGlobalConstant) {
   // Don't emit the intrinsic if we're not optimizing.
   if (!CGM.getCodeGenOpts().OptimizationLevel)
-    return CodeGenModule::InvariantArgs{};
+    return InvariantArgs{};
 
   assert(Addr && "Cannot emit on non-null address.");
 
   // Collect arguments
   ASTContext &Ctx = getContext();
   QualType Ty = D.getType();
   CharUnits WidthChars = Ctx.getTypeSizeInChars(Ty);
   uint64_t Width = WidthChars.getQuantity();
-  CodeGenModule::InvariantArgs Args;
+  InvariantArgs Args;
+  OffsetsType Offsets;
   llvm::Constant *CAddr = dyn_cast<llvm::Constant>(Addr);
   if (CAddr && IsGlobalConstant) {
     Args.Size = llvm::ConstantInt::getSigned(Int64Ty, Width);
     Args.Addr = llvm::ConstantExpr::getBitCast(CAddr, Int8PtrTy);
-  } else if (Ty.isWriteOnce(Ctx) ||
-             getInvariantOffsets(*this, D.getType(), Args.Offsets)) {
+  } else if (Ty.isWriteOnce(Ctx)) {
     Args.Size = llvm::ConstantInt::get(Int64Ty, Width);
     Args.Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+  } else if (const CXXRecordDecl *Record =
+              Ctx.getBaseElementType(Ty)->getAsCXXRecordDecl()) {
+    Offsets = ComputeInvariantOffsets(Record);
+    // If there are invariant offsets in this non-writeonce record,
+    // then emit the intrinsic call with the offsets. Otherwise,
+    // do not emit anything.
+    if (!Offsets.empty()) {
+      Args.Size = llvm::ConstantInt::get(Int64Ty, Width);
+      Args.Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+    }
   }
 
-  if (!Args.Addr) return CodeGenModule::InvariantArgs{};
+  if (!Args.Addr) return InvariantArgs{};
 
   // Generate llvm.invariant.start intrinsic call.
   llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start;
   llvm::Constant *InvariantStart = CGM.getIntrinsic(InvStartID);
   llvm::SmallVector<llvm::Value *, 8> CallArgs;
   CallArgs.push_back(Args.Size);
   CallArgs.push_back(Args.Addr);
-  CallArgs.insert(CallArgs.end(), Args.Offsets.begin(), Args.Offsets.end());
+  CallArgs.insert(CallArgs.end(), Offsets.begin(), Offsets.end());
   llvm::CallInst *C = Builder.CreateCall(InvariantStart, CallArgs);
   Args.StartInst = C;
   C->setDoesNotThrow();
 
   return Args;
 }
 
-void CodeGenFunction::EmitInvariantEnd(CodeGenModule::InvariantArgs &Args) {
+void CodeGenFunction::EmitInvariantEnd(CodeGenFunction::InvariantArgs &Args) {
   assert(Args.Addr && "Emit on non-null address.");
 
   // Generate the llvm.invariant.end intrinsic call.
@@ -1004,7 +1023,6 @@
   CallArgs.push_back(Args.StartInst);
   CallArgs.push_back(Args.Size);
   CallArgs.push_back(Args.Addr);
-  // CallArgs.insert(CallArgs.end(), Args.Offsets.begin(), Args.Offsets.end());
   llvm::CallInst *C = Builder.CreateCall(InvariantEnd, CallArgs);
   C->setDoesNotThrow();
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to