lvoufo created this revision.
lvoufo added reviewers: dberlin, chandlerc, majnemer, nlewycky.
lvoufo added a subscriber: cfe-commits.
Continued from D13603...
http://reviews.llvm.org/D13618
Files:
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.h
test/CodeGenCXX/const-invariant.cpp
Index: test/CodeGenCXX/const-invariant.cpp
===================================================================
--- test/CodeGenCXX/const-invariant.cpp
+++ test/CodeGenCXX/const-invariant.cpp
@@ -37,8 +37,8 @@
#if defined(OBJ)
struct A {
int a;
- int b;
- A(int a) : a(a) {}
+ Const int b;
+ A(int a) : a(a), b(a) {}
};
// A with explicit destructor
@@ -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/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -260,12 +260,14 @@
typedef std::vector<Structor> CtorList;
struct InvariantArgs {
- llvm::CallInst *StartInst;
- llvm::Value *Size;
+ llvm::CallInst *StartInst; // TODO: Is this necessary?
+ llvm::Value *Size; // TODO: Is this necessary?
llvm::Value *Addr;
+ llvm::SmallVector<llvm::Value*, 8> Offsets;
+
InvariantArgs() : StartInst(nullptr), Size(nullptr), Addr(nullptr) {}
InvariantArgs(llvm::CallInst *C, llvm::Value *S, llvm::Value *A)
- : StartInst(C), Size(S), Addr(A) {}
+ : StartInst(C), Size(S), Addr(A) {}
};
private:
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1904,10 +1904,10 @@
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);
- void EmitInvariantEnd(llvm::CallInst *C, llvm::Value *Size,
- llvm::Value *Addr);
+ CodeGenModule::InvariantArgs
+ EmitInvariantStart(const VarDecl &D, llvm::Value* Addr,
+ bool IsGlobalConstant = true);
+ void EmitInvariantEnd(CodeGenModule::InvariantArgs &Args);
llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -530,15 +530,12 @@
/// A cleanup to call @llvm.invariant.end.
class CallInvariantEnd final : public EHScopeStack::Cleanup {
- llvm::CallInst *StartInst;
- llvm::Value *Addr;
- llvm::Value *Size; // TODO: Is this even necessary?
+ CodeGenModule::InvariantArgs Args;
public:
- CallInvariantEnd(llvm::CallInst *C, llvm::Value *addr, llvm::Value *size)
- : StartInst(C), Addr(addr), Size(size) {}
+ CallInvariantEnd(CodeGenModule::InvariantArgs &args) : Args(args) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitInvariantEnd(StartInst, Size, Addr);
+ CGF.EmitInvariantEnd(Args);
}
};
}
@@ -881,16 +878,15 @@
// If the address is writeonce, then emit @llvm.invariant.start() intrinsic.
// Then, for non-global variables, push the emission of the
// @llvm.invariant.end() intrinsic onto the cleanup stack.
- if ((AI || !GV->isConstant()) && D->getType().isWriteOnce(CGF.getContext()))
- Args = CGF.EmitInvariantStart(*D, AddrPtr);
+ if (AI || !GV->isConstant())
+ Args = CGF.EmitInvariantStart(*D, AddrPtr, /*IsGlobalConstant =*/false);
}
MarkWriteOnceWrittenRAII::~MarkWriteOnceWrittenRAII() {
- if (AI && Args.StartInst) {
- assert(!GV && "Can't have it both ways!");
- CGF.EHStack.pushCleanup<CallInvariantEnd>(NormalCleanup, Args.StartInst,
- Args.Addr, Args.Size);
- }
+ if (Args.Addr &&
+ dyn_cast<llvm::AllocaInst>(Args.Addr->stripPointerCasts()) &&
+ Args.StartInst)
+ CGF.EHStack.pushCleanup<CallInvariantEnd>(NormalCleanup, Args);
}
/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a
@@ -932,44 +928,87 @@
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);
+ }
+ }
+ }
+ return FoundWriteOnce;
+}
+
/// Emit code to cause the variable at the given address to be considered as
/// constant from this point onwards.
CodeGenModule::InvariantArgs CodeGenFunction::EmitInvariantStart(
- const VarDecl &D, llvm::Value *Addr) {
+ 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{};
- // Grab the llvm.invariant.start intrinsic.
- llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start;
- llvm::Constant *InvariantStart = CGM.getIntrinsic(InvStartID);
+ assert(Addr && "Cannot emit on non-null address.");
- // Emit a call with the size in bytes of the object.
- CharUnits WidthChars = getContext().getTypeSizeInChars(D.getType());
+ // Collect arguments
+ ASTContext &Ctx = getContext();
+ QualType Ty = D.getType();
+ CharUnits WidthChars = Ctx.getTypeSizeInChars(Ty);
uint64_t Width = WidthChars.getQuantity();
-
- llvm::Value *Size;
- if (llvm::Constant *CAddr = dyn_cast<llvm::Constant>(Addr)) {
- Size = llvm::ConstantInt::getSigned(Int64Ty, Width);
- Addr = llvm::ConstantExpr::getBitCast(CAddr, Int8PtrTy);
- } else {
- Size = llvm::ConstantInt::get(Int64Ty, Width);
- Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+ CodeGenModule::InvariantArgs Args;
+ 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)) {
+ Args.Size = llvm::ConstantInt::get(Int64Ty, Width);
+ Args.Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
}
- llvm::CallInst *C = Builder.CreateCall(InvariantStart, {Size, Addr});
+
+ if (!Args.Addr)
+ return CodeGenModule::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());
+ llvm::CallInst *C = Builder.CreateCall(InvariantStart, CallArgs);
+ Args.StartInst = C;
C->setDoesNotThrow();
- return CodeGenModule::InvariantArgs{C, Size, Addr};
+ return Args;
}
-void CodeGenFunction::EmitInvariantEnd(llvm::CallInst *Start, llvm::Value *Size,
- llvm::Value *Addr) {
- // Grab the llvm.invariant.end intrinsic.
+void CodeGenFunction::EmitInvariantEnd(CodeGenModule::InvariantArgs &Args) {
+ assert(Args.Addr && "Emit on non-null address.");
+
+ // Generate the llvm.invariant.end intrinsic call.
llvm::Intrinsic::ID InvEndID = llvm::Intrinsic::invariant_end;
llvm::Constant *InvariantEnd = CGM.getIntrinsic(InvEndID);
-
- // Emit a call with the size in bytes of the object.
- llvm::CallInst *C = Builder.CreateCall(InvariantEnd, {Start, Size, Addr});
+ llvm::SmallVector<llvm::Value*, 8> CallArgs;
+ 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