mirror of https://github.com/microsoft/clang.git
Generating assumption loads of vptr after ctor call (fixed)
Generating call assume(icmp %vtable, %global_vtable) after constructor call for devirtualization purposes. For more info go to: http://lists.llvm.org/pipermail/cfe-dev/2015-July/044227.html Edit: Fixed version because of PR24479 and other bug caused in chrome. After this patch got reverted because of ScalarEvolution bug (D12719) Merged after John McCall big patch (Added Address). http://reviews.llvm.org/D11859 http://reviews.llvm.org/D12865 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247646 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
65721268c6
commit
81654dc1dd
|
@ -122,7 +122,7 @@ public:
|
|||
}
|
||||
|
||||
const CXXRecordDecl *getRTTIDecl() const {
|
||||
assert(getKind() == CK_RTTI && "Invalid component kind!");
|
||||
assert(isRTTIKind() && "Invalid component kind!");
|
||||
return reinterpret_cast<CXXRecordDecl *>(getPointer());
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,8 @@ public:
|
|||
return isFunctionPointerKind(getKind());
|
||||
}
|
||||
|
||||
bool isRTTIKind() const { return isRTTIKind(getKind()); }
|
||||
|
||||
private:
|
||||
static bool isFunctionPointerKind(Kind ComponentKind) {
|
||||
return isUsedFunctionPointerKind(ComponentKind) ||
|
||||
|
@ -166,6 +168,9 @@ private:
|
|||
return ComponentKind == CK_CompleteDtorPointer ||
|
||||
ComponentKind == CK_DeletingDtorPointer;
|
||||
}
|
||||
static bool isRTTIKind(Kind ComponentKind) {
|
||||
return ComponentKind == CK_RTTI;
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, CharUnits Offset) {
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
|
@ -178,7 +183,7 @@ private:
|
|||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
|
||||
assert((ComponentKind == CK_RTTI || isFunctionPointerKind(ComponentKind)) &&
|
||||
assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) &&
|
||||
"Invalid component kind!");
|
||||
|
||||
assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
|
||||
|
|
|
@ -224,8 +224,10 @@ public:
|
|||
virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0;
|
||||
virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; }
|
||||
|
||||
virtual bool canEmitAvailableExternallyVTable(
|
||||
const CXXRecordDecl *RD) const = 0;
|
||||
/// \brief Determine whether it's possible to emit a vtable for \p RD, even
|
||||
/// though we do not know that the vtable has been marked as used by semantic
|
||||
/// analysis.
|
||||
virtual bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const = 0;
|
||||
|
||||
virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;
|
||||
|
||||
|
@ -351,13 +353,25 @@ public:
|
|||
virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
const CXXRecordDecl *RD) = 0;
|
||||
|
||||
/// Checks if ABI requires extra virtual offset for vtable field.
|
||||
virtual bool
|
||||
isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
|
||||
CodeGenFunction::VPtr Vptr) = 0;
|
||||
|
||||
/// Checks if ABI requires to initilize vptrs for given dynamic class.
|
||||
virtual bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) = 0;
|
||||
|
||||
/// Get the address point of the vtable for the given base subobject.
|
||||
virtual llvm::Constant *
|
||||
getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) = 0;
|
||||
|
||||
/// Get the address point of the vtable for the given base subobject while
|
||||
/// building a constructor or a destructor. On return, NeedsVirtualOffset
|
||||
/// tells if a virtual base adjustment is needed in order to get the offset
|
||||
/// of the base subobject.
|
||||
virtual llvm::Value *getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *RD, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) = 0;
|
||||
/// building a constructor or a destructor.
|
||||
virtual llvm::Value *
|
||||
getVTableAddressPointInStructor(CodeGenFunction &CGF, const CXXRecordDecl *RD,
|
||||
BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase) = 0;
|
||||
|
||||
/// Get the address point of the vtable for the given base subobject while
|
||||
/// building a constexpr.
|
||||
|
|
|
@ -1417,7 +1417,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
|||
|
||||
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
|
||||
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
|
||||
if (FPT && FPT->isNothrow(getContext()))
|
||||
if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
|
||||
FPT->isNothrow(getContext()))
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
|
||||
// Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
|
||||
// These attributes are not inherited by overloads.
|
||||
|
|
|
@ -1984,12 +1984,14 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
|||
bool ForVirtualBase,
|
||||
bool Delegating, Address This,
|
||||
const CXXConstructExpr *E) {
|
||||
const CXXRecordDecl *ClassDecl = D->getParent();
|
||||
|
||||
// C++11 [class.mfct.non-static]p2:
|
||||
// If a non-static member function of a class X is called for an object that
|
||||
// is not of type X, or of a type derived from X, the behavior is undefined.
|
||||
// FIXME: Provide a source location here.
|
||||
EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, SourceLocation(),
|
||||
This.getPointer(), getContext().getRecordType(D->getParent()));
|
||||
This.getPointer(), getContext().getRecordType(ClassDecl));
|
||||
|
||||
if (D->isTrivial() && D->isDefaultConstructor()) {
|
||||
assert(E->getNumArgs() == 0 && "trivial default ctor with args");
|
||||
|
@ -2005,7 +2007,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
|||
const Expr *Arg = E->getArg(0);
|
||||
QualType SrcTy = Arg->getType();
|
||||
Address Src = EmitLValue(Arg).getAddress();
|
||||
QualType DestTy = getContext().getTypeDeclType(D->getParent());
|
||||
QualType DestTy = getContext().getTypeDeclType(ClassDecl);
|
||||
EmitAggregateCopyCtor(This, Src, DestTy, SrcTy);
|
||||
return;
|
||||
}
|
||||
|
@ -2028,6 +2030,47 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
|||
const CGFunctionInfo &Info =
|
||||
CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs);
|
||||
EmitCall(Info, Callee, ReturnValueSlot(), Args, D);
|
||||
|
||||
// Generate vtable assumptions if we're constructing a complete object
|
||||
// with a vtable. We don't do this for base subobjects for two reasons:
|
||||
// first, it's incorrect for classes with virtual bases, and second, we're
|
||||
// about to overwrite the vptrs anyway.
|
||||
// We also have to make sure if we can refer to vtable:
|
||||
// - Otherwise we can refer to vtable if it's safe to speculatively emit.
|
||||
// FIXME: If vtable is used by ctor/dtor, or if vtable is external and we are
|
||||
// sure that definition of vtable is not hidden,
|
||||
// then we are always safe to refer to it.
|
||||
if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
|
||||
ClassDecl->isDynamicClass() && Type != Ctor_Base &&
|
||||
CGM.getCXXABI().canSpeculativelyEmitVTable(ClassDecl))
|
||||
EmitVTableAssumptionLoads(ClassDecl, This);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitVTableAssumptionLoad(const VPtr &Vptr, Address This) {
|
||||
llvm::Value *VTableGlobal =
|
||||
CGM.getCXXABI().getVTableAddressPoint(Vptr.Base, Vptr.VTableClass);
|
||||
if (!VTableGlobal)
|
||||
return;
|
||||
|
||||
// We can just use the base offset in the complete class.
|
||||
CharUnits NonVirtualOffset = Vptr.Base.getBaseOffset();
|
||||
|
||||
if (!NonVirtualOffset.isZero())
|
||||
This =
|
||||
ApplyNonVirtualAndVirtualOffset(*this, This, NonVirtualOffset, nullptr,
|
||||
Vptr.VTableClass, Vptr.NearestVBase);
|
||||
|
||||
llvm::Value *VPtrValue = GetVTablePtr(This, VTableGlobal->getType());
|
||||
llvm::Value *Cmp =
|
||||
Builder.CreateICmpEQ(VPtrValue, VTableGlobal, "cmp.vtables");
|
||||
Builder.CreateAssumption(Cmp);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl,
|
||||
Address This) {
|
||||
if (CGM.getCXXABI().doStructorsInitializeVPtrs(ClassDecl))
|
||||
for (const VPtr &Vptr : getVTablePointers(ClassDecl))
|
||||
EmitVTableAssumptionLoad(Vptr, This);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2193,24 +2236,12 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, Address Addr) {
|
|||
PushDestructorCleanup(D, Addr);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
const CXXRecordDecl *VTableClass) {
|
||||
const CXXRecordDecl *RD = Base.getBase();
|
||||
|
||||
// Don't initialize the vtable pointer if the class is marked with the
|
||||
// 'novtable' attribute.
|
||||
if ((RD == VTableClass || RD == NearestVBase) &&
|
||||
VTableClass->hasAttr<MSNoVTableAttr>())
|
||||
return;
|
||||
|
||||
void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
|
||||
// Compute the address point.
|
||||
bool NeedsVirtualOffset;
|
||||
llvm::Value *VTableAddressPoint =
|
||||
CGM.getCXXABI().getVTableAddressPointInStructor(
|
||||
*this, VTableClass, Base, NearestVBase, NeedsVirtualOffset);
|
||||
*this, Vptr.VTableClass, Vptr.Base, Vptr.NearestVBase);
|
||||
|
||||
if (!VTableAddressPoint)
|
||||
return;
|
||||
|
||||
|
@ -2218,27 +2249,25 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
|
|||
llvm::Value *VirtualOffset = nullptr;
|
||||
CharUnits NonVirtualOffset = CharUnits::Zero();
|
||||
|
||||
if (NeedsVirtualOffset) {
|
||||
if (CGM.getCXXABI().isVirtualOffsetNeededForVTableField(*this, Vptr)) {
|
||||
// We need to use the virtual base offset offset because the virtual base
|
||||
// might have a different offset in the most derived class.
|
||||
VirtualOffset =
|
||||
CGM.getCXXABI().GetVirtualBaseClassOffset(*this, LoadCXXThisAddress(),
|
||||
VTableClass, NearestVBase);
|
||||
NonVirtualOffset = OffsetFromNearestVBase;
|
||||
|
||||
VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(
|
||||
*this, LoadCXXThisAddress(), Vptr.VTableClass, Vptr.NearestVBase);
|
||||
NonVirtualOffset = Vptr.OffsetFromNearestVBase;
|
||||
} else {
|
||||
// We can just use the base offset in the complete class.
|
||||
NonVirtualOffset = Base.getBaseOffset();
|
||||
NonVirtualOffset = Vptr.Base.getBaseOffset();
|
||||
}
|
||||
|
||||
// Apply the offsets.
|
||||
Address VTableField = LoadCXXThisAddress();
|
||||
|
||||
if (!NonVirtualOffset.isZero() || VirtualOffset)
|
||||
VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField,
|
||||
NonVirtualOffset,
|
||||
VirtualOffset,
|
||||
VTableClass,
|
||||
NearestVBase);
|
||||
VTableField = ApplyNonVirtualAndVirtualOffset(
|
||||
*this, VTableField, NonVirtualOffset, VirtualOffset, Vptr.VTableClass,
|
||||
Vptr.NearestVBase);
|
||||
|
||||
// Finally, store the address point. Use the same LLVM types as the field to
|
||||
// support optimization.
|
||||
|
@ -2248,23 +2277,36 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
|
|||
->getPointerTo();
|
||||
VTableField = Builder.CreateBitCast(VTableField, VTablePtrTy->getPointerTo());
|
||||
VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
|
||||
|
||||
llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
|
||||
CGM.DecorateInstruction(Store, CGM.getTBAAInfoForVTablePtr());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy& VBases) {
|
||||
CodeGenFunction::VPtrsVector
|
||||
CodeGenFunction::getVTablePointers(const CXXRecordDecl *VTableClass) {
|
||||
CodeGenFunction::VPtrsVector VPtrsResult;
|
||||
VisitedVirtualBasesSetTy VBases;
|
||||
getVTablePointers(BaseSubobject(VTableClass, CharUnits::Zero()),
|
||||
/*NearestVBase=*/nullptr,
|
||||
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
|
||||
/*BaseIsNonVirtualPrimaryBase=*/false, VTableClass, VBases,
|
||||
VPtrsResult);
|
||||
return VPtrsResult;
|
||||
}
|
||||
|
||||
void CodeGenFunction::getVTablePointers(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy &VBases,
|
||||
VPtrsVector &Vptrs) {
|
||||
// If this base is a non-virtual primary base the address point has already
|
||||
// been set.
|
||||
if (!BaseIsNonVirtualPrimaryBase) {
|
||||
// Initialize the vtable pointer for this base.
|
||||
InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase,
|
||||
VTableClass);
|
||||
VPtr Vptr = {Base, NearestVBase, OffsetFromNearestVBase, VTableClass};
|
||||
Vptrs.push_back(Vptr);
|
||||
}
|
||||
|
||||
const CXXRecordDecl *RD = Base.getBase();
|
||||
|
@ -2302,11 +2344,10 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
|
|||
BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
|
||||
}
|
||||
|
||||
InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
|
||||
I.isVirtual() ? BaseDecl : NearestVBase,
|
||||
BaseOffsetFromNearestVBase,
|
||||
BaseDeclIsNonVirtualPrimaryBase,
|
||||
VTableClass, VBases);
|
||||
getVTablePointers(
|
||||
BaseSubobject(BaseDecl, BaseOffset),
|
||||
I.isVirtual() ? BaseDecl : NearestVBase, BaseOffsetFromNearestVBase,
|
||||
BaseDeclIsNonVirtualPrimaryBase, VTableClass, VBases, Vptrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2316,11 +2357,9 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
|
|||
return;
|
||||
|
||||
// Initialize the vtable pointers for this class and all of its bases.
|
||||
VisitedVirtualBasesSetTy VBases;
|
||||
InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()),
|
||||
/*NearestVBase=*/nullptr,
|
||||
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
|
||||
/*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
|
||||
if (CGM.getCXXABI().doStructorsInitializeVPtrs(RD))
|
||||
for (const VPtr &Vptr : getVTablePointers(RD))
|
||||
InitializeVTablePointer(Vptr);
|
||||
|
||||
if (RD->getNumVBases())
|
||||
CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD);
|
||||
|
|
|
@ -696,7 +696,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
|
|||
static bool shouldEmitAvailableExternallyVTable(const CodeGenModule &CGM,
|
||||
const CXXRecordDecl *RD) {
|
||||
return CGM.getCodeGenOpts().OptimizationLevel > 0 &&
|
||||
CGM.getCXXABI().canEmitAvailableExternallyVTable(RD);
|
||||
CGM.getCXXABI().canSpeculativelyEmitVTable(RD);
|
||||
}
|
||||
|
||||
/// Compute the required linkage of the v-table for the given class.
|
||||
|
@ -846,11 +846,11 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
|
|||
/// we define that v-table?
|
||||
static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
|
||||
const CXXRecordDecl *RD) {
|
||||
// If vtable is internal then it has to be done
|
||||
// If vtable is internal then it has to be done.
|
||||
if (!CGM.getVTables().isVTableExternal(RD))
|
||||
return true;
|
||||
|
||||
// If it's external then maybe we will need it as available_externally
|
||||
// If it's external then maybe we will need it as available_externally.
|
||||
return shouldEmitAvailableExternallyVTable(CGM, RD);
|
||||
}
|
||||
|
||||
|
|
|
@ -1354,21 +1354,27 @@ public:
|
|||
void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init,
|
||||
ArrayRef<VarDecl *> ArrayIndexes);
|
||||
|
||||
/// InitializeVTablePointer - Initialize the vtable pointer of the given
|
||||
/// subobject.
|
||||
///
|
||||
void InitializeVTablePointer(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
const CXXRecordDecl *VTableClass);
|
||||
/// Struct with all informations about dynamic [sub]class needed to set vptr.
|
||||
struct VPtr {
|
||||
BaseSubobject Base;
|
||||
const CXXRecordDecl *NearestVBase;
|
||||
CharUnits OffsetFromNearestVBase;
|
||||
const CXXRecordDecl *VTableClass;
|
||||
};
|
||||
|
||||
/// Initialize the vtable pointer of the given subobject.
|
||||
void InitializeVTablePointer(const VPtr &vptr);
|
||||
|
||||
typedef llvm::SmallVector<VPtr, 4> VPtrsVector;
|
||||
|
||||
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
|
||||
void InitializeVTablePointers(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy& VBases);
|
||||
VPtrsVector getVTablePointers(const CXXRecordDecl *VTableClass);
|
||||
|
||||
void getVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy &VBases, VPtrsVector &vptrs);
|
||||
|
||||
void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
|
||||
|
||||
|
@ -1836,10 +1842,18 @@ public:
|
|||
// they are substantially the same.
|
||||
void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
|
||||
const FunctionArgList &Args);
|
||||
|
||||
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
bool ForVirtualBase, bool Delegating,
|
||||
Address This, const CXXConstructExpr *E);
|
||||
|
||||
/// Emit assumption load for all bases. Requires to be be called only on
|
||||
/// most-derived class and not under construction of the object.
|
||||
void EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl, Address This);
|
||||
|
||||
/// Emit assumption that vptr load == global vtable.
|
||||
void EmitVTableAssumptionLoad(const VPtr &vptr, Address This);
|
||||
|
||||
void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
|
||||
Address This, Address Src,
|
||||
const CXXConstructExpr *E);
|
||||
|
|
|
@ -243,10 +243,24 @@ public:
|
|||
void emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
const CXXRecordDecl *RD) override;
|
||||
|
||||
bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
|
||||
CodeGenFunction::VPtr Vptr) override;
|
||||
|
||||
bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) override;
|
||||
|
||||
llvm::Value *getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
|
||||
bool &NeedsVirtualOffset) override;
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase) override;
|
||||
|
||||
llvm::Value *getVTableAddressPointInStructorWithVTT(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase);
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPointForConstExpr(BaseSubobject Base,
|
||||
|
@ -267,7 +281,7 @@ public:
|
|||
|
||||
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
|
||||
|
||||
bool canEmitAvailableExternallyVTable(const CXXRecordDecl *RD) const override;
|
||||
bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override;
|
||||
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
|
||||
bool ReturnAdjustment) override {
|
||||
|
@ -372,6 +386,25 @@ public:
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isVTableHidden(const CXXRecordDecl *RD) const {
|
||||
const auto &VtableLayout =
|
||||
CGM.getItaniumVTableContext().getVTableLayout(RD);
|
||||
|
||||
for (const auto &VtableComponent : VtableLayout.vtable_components()) {
|
||||
if (VtableComponent.isRTTIKind()) {
|
||||
const CXXRecordDecl *RTTIDecl = VtableComponent.getRTTIDecl();
|
||||
if (RTTIDecl->getVisibility() == Visibility::HiddenVisibility)
|
||||
return true;
|
||||
} else if (VtableComponent.isUsedFunctionPointerKind()) {
|
||||
const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
|
||||
if (Method->getVisibility() == Visibility::HiddenVisibility &&
|
||||
!Method->isDefined())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class ARMCXXABI : public ItaniumCXXABI {
|
||||
|
@ -1459,41 +1492,29 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
|||
CGM.EmitVTableBitSetEntries(VTable, VTLayout);
|
||||
}
|
||||
|
||||
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
|
||||
bool NeedsVTTParam = CGM.getCXXABI().NeedsVTTParameter(CGF.CurGD);
|
||||
NeedsVirtualOffset = (NeedsVTTParam && NearestVBase);
|
||||
|
||||
llvm::Value *VTableAddressPoint;
|
||||
if (NeedsVTTParam && (Base.getBase()->getNumVBases() || NearestVBase)) {
|
||||
// Get the secondary vpointer index.
|
||||
uint64_t VirtualPointerIndex =
|
||||
CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
|
||||
|
||||
/// Load the VTT.
|
||||
llvm::Value *VTT = CGF.LoadCXXVTT();
|
||||
if (VirtualPointerIndex)
|
||||
VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
|
||||
|
||||
// And load the address point from the VTT.
|
||||
VTableAddressPoint = CGF.Builder.CreateAlignedLoad(VTT, CGF.getPointerAlign());
|
||||
} else {
|
||||
llvm::Constant *VTable =
|
||||
CGM.getCXXABI().getAddrOfVTable(VTableClass, CharUnits());
|
||||
uint64_t AddressPoint = CGM.getItaniumVTableContext()
|
||||
.getVTableLayout(VTableClass)
|
||||
.getAddressPoint(Base);
|
||||
VTableAddressPoint =
|
||||
CGF.Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
|
||||
}
|
||||
|
||||
return VTableAddressPoint;
|
||||
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
|
||||
CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {
|
||||
if (Vptr.NearestVBase == nullptr)
|
||||
return false;
|
||||
return NeedsVTTParameter(CGF.CurGD);
|
||||
}
|
||||
|
||||
llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
auto *VTable = getAddrOfVTable(VTableClass, CharUnits());
|
||||
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase) {
|
||||
|
||||
if ((Base.getBase()->getNumVBases() || NearestVBase != nullptr) &&
|
||||
NeedsVTTParameter(CGF.CurGD)) {
|
||||
return getVTableAddressPointInStructorWithVTT(CGF, VTableClass, Base,
|
||||
NearestVBase);
|
||||
}
|
||||
return getVTableAddressPoint(Base, VTableClass);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) {
|
||||
llvm::GlobalValue *VTable = getAddrOfVTable(VTableClass, CharUnits());
|
||||
|
||||
// Find the appropriate vtable within the vtable group.
|
||||
uint64_t AddressPoint = CGM.getItaniumVTableContext()
|
||||
|
@ -1508,6 +1529,30 @@ llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
|
|||
VTable, Indices);
|
||||
}
|
||||
|
||||
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase) {
|
||||
assert((Base.getBase()->getNumVBases() || NearestVBase != nullptr) &&
|
||||
NeedsVTTParameter(CGF.CurGD) && "This class doesn't have VTT");
|
||||
|
||||
// Get the secondary vpointer index.
|
||||
uint64_t VirtualPointerIndex =
|
||||
CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
|
||||
|
||||
/// Load the VTT.
|
||||
llvm::Value *VTT = CGF.LoadCXXVTT();
|
||||
if (VirtualPointerIndex)
|
||||
VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
|
||||
|
||||
// And load the address point from the VTT.
|
||||
return CGF.Builder.CreateAlignedLoad(VTT, CGF.getPointerAlign());
|
||||
}
|
||||
|
||||
llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
return getVTableAddressPoint(Base, VTableClass);
|
||||
}
|
||||
|
||||
llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
||||
CharUnits VPtrOffset) {
|
||||
assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
|
||||
|
@ -1583,18 +1628,17 @@ void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
|
|||
VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
|
||||
}
|
||||
|
||||
bool ItaniumCXXABI::canEmitAvailableExternallyVTable(
|
||||
const CXXRecordDecl *RD) const {
|
||||
bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
|
||||
// We don't emit available_externally vtables if we are in -fapple-kext mode
|
||||
// because kext mode does not permit devirtualization.
|
||||
if (CGM.getLangOpts().AppleKext)
|
||||
return false;
|
||||
|
||||
// If we don't have any inline virtual functions,
|
||||
// If we don't have any inline virtual functions, and if vtable is not hidden,
|
||||
// then we are safe to emit available_externally copy of vtable.
|
||||
// FIXME we can still emit a copy of the vtable if we
|
||||
// can emit definition of the inline functions.
|
||||
return !hasAnyUsedVirtualInlineFunction(RD);
|
||||
return !hasAnyUsedVirtualInlineFunction(RD) && !isVTableHidden(RD);
|
||||
}
|
||||
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
|
||||
Address InitialPtr,
|
||||
|
|
|
@ -127,8 +127,7 @@ public:
|
|||
QualType DestTy) override;
|
||||
|
||||
bool EmitBadCastCall(CodeGenFunction &CGF) override;
|
||||
bool canEmitAvailableExternallyVTable(
|
||||
const CXXRecordDecl *RD) const override {
|
||||
bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -236,10 +235,22 @@ public:
|
|||
void emitVTableDefinitions(CodeGenVTables &CGVT,
|
||||
const CXXRecordDecl *RD) override;
|
||||
|
||||
bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
|
||||
CodeGenFunction::VPtr Vptr) override;
|
||||
|
||||
/// Don't initialize vptrs if dynamic class
|
||||
/// is marked with with the 'novtable' attribute.
|
||||
bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override {
|
||||
return !VTableClass->hasAttr<MSNoVTableAttr>();
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) override;
|
||||
|
||||
llvm::Value *getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
|
||||
bool &NeedsVirtualOffset) override;
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase) override;
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPointForConstExpr(BaseSubobject Base,
|
||||
|
@ -1597,14 +1608,15 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
|||
}
|
||||
}
|
||||
|
||||
bool MicrosoftCXXABI::isVirtualOffsetNeededForVTableField(
|
||||
CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {
|
||||
return Vptr.NearestVBase != nullptr;
|
||||
}
|
||||
|
||||
llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
|
||||
NeedsVirtualOffset = (NearestVBase != nullptr);
|
||||
|
||||
(void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
|
||||
VFTableIdTy ID(VTableClass, Base.getBaseOffset());
|
||||
llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
|
||||
const CXXRecordDecl *NearestVBase) {
|
||||
llvm::Constant *VTableAddressPoint = getVTableAddressPoint(Base, VTableClass);
|
||||
if (!VTableAddressPoint) {
|
||||
assert(Base.getBase()->getNumVBases() &&
|
||||
!getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
|
||||
|
@ -1619,11 +1631,17 @@ static void mangleVFTableName(MicrosoftMangleContext &MangleContext,
|
|||
MangleContext.mangleCXXVFTable(RD, VFPtr->MangledPath, Out);
|
||||
}
|
||||
|
||||
llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) {
|
||||
(void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
|
||||
VFTableIdTy ID(VTableClass, Base.getBaseOffset());
|
||||
llvm::GlobalValue *VFTable = VFTablesMap[ID];
|
||||
return VFTablesMap[ID];
|
||||
}
|
||||
|
||||
llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
llvm::Constant *VFTable = getVTableAddressPoint(Base, VTableClass);
|
||||
assert(VFTable && "Couldn't find a vftable for the given base?");
|
||||
return VFTable;
|
||||
}
|
||||
|
@ -1633,6 +1651,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
|||
// getAddrOfVTable may return 0 if asked to get an address of a vtable which
|
||||
// shouldn't be used in the given record type. We want to cache this result in
|
||||
// VFTablesMap, thus a simple zero check is not sufficient.
|
||||
|
||||
VFTableIdTy ID(RD, VPtrOffset);
|
||||
VTablesMapTy::iterator I;
|
||||
bool Inserted;
|
||||
|
@ -1686,10 +1705,11 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
|||
if (llvm::GlobalValue *VFTable =
|
||||
CGM.getModule().getNamedGlobal(VFTableName)) {
|
||||
VFTablesMap[ID] = VFTable;
|
||||
return VTableAliasIsRequred
|
||||
? cast<llvm::GlobalVariable>(
|
||||
cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
|
||||
: cast<llvm::GlobalVariable>(VFTable);
|
||||
VTable = VTableAliasIsRequred
|
||||
? cast<llvm::GlobalVariable>(
|
||||
cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
|
||||
: cast<llvm::GlobalVariable>(VFTable);
|
||||
return VTable;
|
||||
}
|
||||
|
||||
uint64_t NumVTableSlots =
|
||||
|
|
|
@ -27,6 +27,6 @@ class TestSyncMessageFilter : public SyncMessageFilter {
|
|||
};
|
||||
|
||||
int main() {
|
||||
TestSyncMessageFilter* f = new TestSyncMessageFilter;
|
||||
TestSyncMessageFilter *f = new TestSyncMessageFilter;
|
||||
f->Send(new Message);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s -O1 | FileCheck %s --check-prefix=O1
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s -O2 | opt - -S -globalopt -o - | FileCheck %s --check-prefix=O1
|
||||
// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s -O1 | FileCheck %s --check-prefix=O1
|
||||
// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s -O2 | opt - -S -globalopt -o - | FileCheck %s --check-prefix=O1
|
||||
|
||||
// Check that GlobalOpt can eliminate static constructors for simple implicit
|
||||
// constructors. This is a targeted integration test to make sure that LLVM's
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o - -O1 -disable-llvm-optzns | FileCheck %s
|
||||
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o %t
|
||||
// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -munwind-tables -emit-llvm -o %t.opt -O1 -disable-llvm-optzns
|
||||
// RUN: FileCheck %s < %t
|
||||
// RUN: FileCheck %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-NONOPT %s < %t
|
||||
// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt
|
||||
|
||||
namespace Test1 {
|
||||
|
||||
|
@ -380,13 +384,25 @@ D::~D() {}
|
|||
|
||||
/**** The following has to go at the end of the file ****/
|
||||
|
||||
// checking without opt
|
||||
// CHECK-NONOPT-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
|
||||
// CHECK-NONOPT-NOT: comdat
|
||||
|
||||
// This is from Test5:
|
||||
// CHECK-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
|
||||
// CHECK-NOT: comdat
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
|
||||
// CHECK-NONOPT-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
|
||||
|
||||
// This is from Test10:
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
|
||||
// CHECK-NONOPT-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
|
||||
// CHECK-NONOPT-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
|
||||
|
||||
// Checking with opt
|
||||
// CHECK-OPT-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(%"struct.Test4B::(anonymous namespace)::C"* %this) unnamed_addr #0 align 2
|
||||
|
||||
// This is from Test5:
|
||||
// CHECK-OPT-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
|
||||
|
||||
// This is from Test10:
|
||||
// CHECK-OPT-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
|
||||
// CHECK-OPT-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
|
||||
|
||||
// CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - -O2 | FileCheck %s
|
||||
// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - -O2 | opt - -S -globalopt -o - | FileCheck %s
|
||||
|
||||
struct B;
|
||||
extern B x;
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o %t.ll -O1 -disable-llvm-optzns -fms-extensions
|
||||
// RUN: %clang_cc1 %s -triple i686-pc-win32 -emit-llvm -o %t.ms.ll -O1 -disable-llvm-optzns -fms-extensions
|
||||
|
||||
// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK-MS --input-file=%t.ms.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s
|
||||
// RUN: FileCheck --check-prefix=CHECK9 --input-file=%t.ll %s
|
||||
namespace test1 {
|
||||
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
void g(A *a) { a->foo(); }
|
||||
|
||||
// CHECK1-LABEL: define void @_ZN5test14fooAEv()
|
||||
// CHECK1: call void @_ZN5test11AC1Ev(%"struct.test1::A"*
|
||||
// CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
|
||||
// CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11AE, i64 0, i64 2)
|
||||
// CHECK1: call void @llvm.assume(i1 %[[CMP]])
|
||||
// CHECK1-LABEL: }
|
||||
|
||||
void fooA() {
|
||||
A a;
|
||||
g(&a);
|
||||
}
|
||||
|
||||
// CHECK1-LABEL: define void @_ZN5test14fooBEv()
|
||||
// CHECK1: call void @_ZN5test11BC1Ev(%"struct.test1::B"* %{{.*}})
|
||||
// CHECK1: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
|
||||
// CHECK1: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([3 x i8*], [3 x i8*]* @_ZTVN5test11BE, i64 0, i64 2)
|
||||
// CHECK1: call void @llvm.assume(i1 %[[CMP]])
|
||||
// CHECK1-LABEL: }
|
||||
|
||||
void fooB() {
|
||||
B b;
|
||||
g(&b);
|
||||
}
|
||||
// there should not be any assumes in the ctor that calls base ctor
|
||||
// CHECK1-LABEL: define linkonce_odr void @_ZN5test11BC2Ev(%"struct.test1::B"*
|
||||
// CHECK1-NOT: @llvm.assume(
|
||||
// CHECK1-LABEL: }
|
||||
}
|
||||
namespace test2 {
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
struct B {
|
||||
B();
|
||||
virtual void bar();
|
||||
};
|
||||
|
||||
struct C : A, B {
|
||||
C();
|
||||
virtual void foo();
|
||||
};
|
||||
void g(A *a) { a->foo(); }
|
||||
void h(B *b) { b->bar(); }
|
||||
|
||||
// CHECK2-LABEL: define void @_ZN5test24testEv()
|
||||
// CHECK2: call void @_ZN5test21CC1Ev(%"struct.test2::C"*
|
||||
// CHECK2: %[[VTABLE:.*]] = load i8**, i8*** {{.*}}
|
||||
// CHECK2: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i64 0, i64 2)
|
||||
// CHECK2: call void @llvm.assume(i1 %[[CMP]])
|
||||
|
||||
// CHECK2: %[[V2:.*]] = bitcast %"struct.test2::C"* %{{.*}} to i8*
|
||||
// CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, i8* %[[V2]], i64 8
|
||||
// CHECK2: %[[V3:.*]] = bitcast i8* %[[ADD_PTR]] to i8***
|
||||
// CHECK2: %[[VTABLE2:.*]] = load i8**, i8*** %[[V3]]
|
||||
// CHECK2: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([6 x i8*], [6 x i8*]* @_ZTVN5test21CE, i64 0, i64 5)
|
||||
// CHECK2: call void @llvm.assume(i1 %[[CMP2]])
|
||||
|
||||
// CHECK2: call void @_ZN5test21gEPNS_1AE(
|
||||
// CHECK2-LABEL: }
|
||||
|
||||
void test() {
|
||||
C c;
|
||||
g(&c);
|
||||
h(&c);
|
||||
}
|
||||
}
|
||||
|
||||
namespace test3 {
|
||||
struct A {
|
||||
A();
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
B();
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
struct C : virtual A, B {
|
||||
C();
|
||||
virtual void foo();
|
||||
};
|
||||
void g(B *a) { a->foo(); }
|
||||
|
||||
// CHECK3-LABEL: define void @_ZN5test34testEv()
|
||||
// CHECK3: call void @_ZN5test31CC1Ev(%"struct.test3::C"*
|
||||
// CHECK3: %[[CMP:.*]] = icmp eq i8** %{{.*}}, getelementptr inbounds ([4 x i8*], [4 x i8*]* @_ZTVN5test31CE, i64 0, i64 3)
|
||||
// CHECK3: call void @llvm.assume(i1 %[[CMP]])
|
||||
// CHECK3-LABLEL: }
|
||||
void test() {
|
||||
C c;
|
||||
g(&c);
|
||||
}
|
||||
} // test3
|
||||
|
||||
namespace test4 {
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
struct B : virtual A {
|
||||
B();
|
||||
virtual void foo();
|
||||
};
|
||||
struct C : B {
|
||||
C();
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
void g(C *c) { c->foo(); }
|
||||
|
||||
// CHECK4-LABEL: define void @_ZN5test44testEv()
|
||||
// CHECK4: call void @_ZN5test41CC1Ev(%"struct.test4::C"*
|
||||
// CHECK4: %[[VTABLE:.*]] = load i8**, i8*** %{{.*}}
|
||||
// CHECK4: %[[CMP:.*]] = icmp eq i8** %[[VTABLE]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i64 0, i64 4)
|
||||
// CHECK4: call void @llvm.assume(i1 %[[CMP]]
|
||||
|
||||
// CHECK4: %[[VTABLE2:.*]] = load i8**, i8*** %{{.*}}
|
||||
// CHECK4: %[[CMP2:.*]] = icmp eq i8** %[[VTABLE2]], getelementptr inbounds ([5 x i8*], [5 x i8*]* @_ZTVN5test41CE, i64 0, i64 4)
|
||||
// CHECK4: call void @llvm.assume(i1 %[[CMP2]])
|
||||
// CHECK4-LABEL: }
|
||||
|
||||
void test() {
|
||||
C c;
|
||||
g(&c);
|
||||
}
|
||||
} // test4
|
||||
|
||||
namespace testMS {
|
||||
|
||||
struct __declspec(novtable) S {
|
||||
virtual void foo();
|
||||
};
|
||||
|
||||
void g(S &s) { s.foo(); }
|
||||
|
||||
// if struct has novtable specifier, then we can't generate assumes
|
||||
// CHECK-MS-LABEL: define void @"\01?test@testMS@@YAXXZ"()
|
||||
// CHECK-MS: call x86_thiscallcc %"struct.testMS::S"* @"\01??0S@testMS@@QAE@XZ"(
|
||||
// CHECK-MS-NOT: @llvm.assume
|
||||
// CHECK-MS-LABEL: }
|
||||
|
||||
void test() {
|
||||
S s;
|
||||
g(s);
|
||||
}
|
||||
|
||||
} // testMS
|
||||
|
||||
namespace test6 {
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
virtual ~A() {}
|
||||
};
|
||||
struct B : A {
|
||||
B();
|
||||
};
|
||||
// FIXME: Because A's vtable is external, and no virtual functions are hidden,
|
||||
// it's safe to generate assumption loads.
|
||||
// CHECK6-LABEL: define void @_ZN5test61gEv()
|
||||
// CHECK6: call void @_ZN5test61AC1Ev(
|
||||
// CHECK6-NOT: call void @llvm.assume(
|
||||
|
||||
// We can't emit assumption loads for B, because if we would refer to vtable
|
||||
// it would refer to functions that will not be able to find (like implicit
|
||||
// inline destructor).
|
||||
|
||||
// CHECK6-LABEL: call void @_ZN5test61BC1Ev(
|
||||
// CHECK6-NOT: call void @llvm.assume(
|
||||
// CHECK6-LABEL: }
|
||||
void g() {
|
||||
A *a = new A;
|
||||
B *b = new B;
|
||||
}
|
||||
}
|
||||
|
||||
namespace test7 {
|
||||
// Because A's key function is defined here, vtable is generated in this TU
|
||||
// CHECK7: @_ZTVN5test71AE = unnamed_addr constant
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
virtual void bar();
|
||||
};
|
||||
void A::foo() {}
|
||||
|
||||
// CHECK7-LABEL: define void @_ZN5test71gEv()
|
||||
// CHECK7: call void @_ZN5test71AC1Ev(
|
||||
// CHECK7: call void @llvm.assume(
|
||||
// CHECK7-LABEL: }
|
||||
void g() {
|
||||
A *a = new A();
|
||||
a->bar();
|
||||
}
|
||||
}
|
||||
|
||||
namespace test8 {
|
||||
|
||||
struct A {
|
||||
virtual void foo();
|
||||
virtual void bar();
|
||||
};
|
||||
|
||||
// CHECK8-DAG: @_ZTVN5test81BE = available_externally unnamed_addr constant
|
||||
struct B : A {
|
||||
B();
|
||||
void foo();
|
||||
void bar();
|
||||
};
|
||||
|
||||
// CHECK8-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr constant
|
||||
struct C : A {
|
||||
C();
|
||||
void bar();
|
||||
void foo() {}
|
||||
};
|
||||
inline void C::bar() {}
|
||||
|
||||
struct D : A {
|
||||
D();
|
||||
void foo();
|
||||
void inline bar();
|
||||
};
|
||||
void D::bar() {}
|
||||
|
||||
// CHECK8-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr constant
|
||||
struct E : A {
|
||||
E();
|
||||
};
|
||||
|
||||
// CHECK8-LABEL: define void @_ZN5test81bEv()
|
||||
// CHECK8: call void @llvm.assume(
|
||||
// CHECK8-LABEL: }
|
||||
void b() {
|
||||
B b;
|
||||
b.bar();
|
||||
}
|
||||
|
||||
// FIXME: C has inline virtual functions which prohibits as from generating
|
||||
// assumption loads, but because vtable is generated in this TU (key function
|
||||
// defined here) it would be correct to refer to it.
|
||||
// CHECK8-LABEL: define void @_ZN5test81cEv()
|
||||
// CHECK8-NOT: call void @llvm.assume(
|
||||
// CHECK8-LABEL: }
|
||||
void c() {
|
||||
C c;
|
||||
c.bar();
|
||||
}
|
||||
|
||||
// FIXME: We could generate assumption loads here.
|
||||
// CHECK8-LABEL: define void @_ZN5test81dEv()
|
||||
// CHECK8-NOT: call void @llvm.assume(
|
||||
// CHECK8-LABEL: }
|
||||
void d() {
|
||||
D d;
|
||||
d.bar();
|
||||
}
|
||||
|
||||
// CHECK8-LABEL: define void @_ZN5test81eEv()
|
||||
// CHECK8: call void @llvm.assume(
|
||||
// CHECK8-LABEL: }
|
||||
void e() {
|
||||
E e;
|
||||
e.bar();
|
||||
}
|
||||
}
|
||||
|
||||
namespace test9 {
|
||||
|
||||
struct S {
|
||||
__attribute__((visibility("hidden"))) S();
|
||||
virtual void doStuff();
|
||||
};
|
||||
|
||||
// CHECK9-LABEL: define void @_ZN5test94testEv()
|
||||
// CHECK9-NOT: @llvm.assume(
|
||||
// CHECK9: }
|
||||
void test() {
|
||||
S *s = new S();
|
||||
s->doStuff();
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
// RUN: FileCheck --check-prefix=CHECK-TEST13 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST14 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST15 %s < %t.opt
|
||||
// RUN: FileCheck --check-prefix=CHECK-TEST16 %s < %t.opt
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
|
@ -184,10 +185,10 @@ void f() {
|
|||
} // Test8
|
||||
|
||||
namespace Test9 {
|
||||
// all virtual functions are outline, so we can assume that it will
|
||||
// be generated in translation unit where foo is defined
|
||||
// CHECK-TEST9: @_ZTVN5Test91AE = available_externally unnamed_addr constant
|
||||
// CHECK-TEST9: @_ZTVN5Test91BE = available_externally unnamed_addr constant
|
||||
// All virtual functions are outline, so we can assume that it will
|
||||
// be generated in translation unit where foo is defined.
|
||||
// CHECK-TEST9-DAG: @_ZTVN5Test91AE = available_externally unnamed_addr constant
|
||||
// CHECK-TEST9-DAG: @_ZTVN5Test91BE = available_externally unnamed_addr constant
|
||||
struct A {
|
||||
virtual void foo();
|
||||
virtual void bar();
|
||||
|
@ -210,22 +211,22 @@ void g() {
|
|||
namespace Test10 {
|
||||
|
||||
// because A's key function is defined here, vtable is generated in this TU
|
||||
// CHECK-TEST10: @_ZTVN6Test101AE = unnamed_addr constant
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101AE = unnamed_addr constant
|
||||
struct A {
|
||||
virtual void foo();
|
||||
virtual void bar();
|
||||
};
|
||||
void A::foo() {}
|
||||
|
||||
// Because key function is inline we will generate vtable as linkonce_odr
|
||||
// CHECK-TEST10: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant
|
||||
// Because key function is inline we will generate vtable as linkonce_odr.
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant
|
||||
struct D : A {
|
||||
void bar();
|
||||
};
|
||||
inline void D::bar() {}
|
||||
|
||||
// because B has outline key function then we can refer to
|
||||
// CHECK-TEST10: @_ZTVN6Test101BE = available_externally unnamed_addr constant
|
||||
// Because B has outline all virtual functions, we can refer to them.
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101BE = available_externally unnamed_addr constant
|
||||
struct B : A {
|
||||
void foo();
|
||||
void bar();
|
||||
|
@ -233,8 +234,8 @@ struct B : A {
|
|||
|
||||
// C's key function (car) is outline, but C has inline virtual function so we
|
||||
// can't guarantee that we will be able to refer to bar from name
|
||||
// so (at the moment) we can't emit vtable available_externally
|
||||
// CHECK-TEST10: @_ZTVN6Test101CE = external unnamed_addr constant
|
||||
// so (at the moment) we can't emit vtable available_externally.
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101CE = external unnamed_addr constant
|
||||
struct C : A {
|
||||
void bar() {} // defined in body - not key function
|
||||
virtual inline void gar(); // inline in body - not key function
|
||||
|
@ -242,7 +243,7 @@ struct C : A {
|
|||
};
|
||||
|
||||
// no key function, vtable will be generated everywhere it will be used
|
||||
// CHECK-TEST10: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant
|
||||
struct E : A {};
|
||||
|
||||
void g(A& a) {
|
||||
|
@ -365,4 +366,28 @@ void test() {
|
|||
}
|
||||
}
|
||||
|
||||
namespace Test16 {
|
||||
// S has virtual method that is hidden, because of it we can't
|
||||
// generate available_externally vtable for it.
|
||||
// CHECK-TEST16-DAG: @_ZTVN6Test161SE = external unnamed_addr constant
|
||||
// CHECK-TEST16-DAG: @_ZTVN6Test162S2E = available_externally
|
||||
|
||||
struct S {
|
||||
__attribute__((visibility("hidden"))) virtual void doStuff();
|
||||
};
|
||||
|
||||
struct S2 {
|
||||
virtual void doStuff();
|
||||
__attribute__((visibility("hidden"))) void unused();
|
||||
|
||||
};
|
||||
|
||||
void test() {
|
||||
S *s = new S;
|
||||
s->doStuff();
|
||||
|
||||
S2 *s2 = new S2;
|
||||
s2->doStuff();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue