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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits