forked from OSchip/llvm-project
Revert "Generating assumption loads of vptr after ctor call (fixed)"
It seems that there is small bug, and we can't generate assume loads when some virtual functions have internal visibiliy This reverts commit 982bb7d966947812d216489b3c519c9825cacbf2. llvm-svn: 247332
This commit is contained in:
parent
4eb5d5a02d
commit
4bed31b9bf
|
@ -228,10 +228,8 @@ public:
|
|||
virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0;
|
||||
virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; }
|
||||
|
||||
/// \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 bool canEmitAvailableExternallyVTable(
|
||||
const CXXRecordDecl *RD) const = 0;
|
||||
|
||||
virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;
|
||||
|
||||
|
@ -357,25 +355,13 @@ 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.
|
||||
virtual llvm::Value *
|
||||
getVTableAddressPointInStructor(CodeGenFunction &CGF, const CXXRecordDecl *RD,
|
||||
BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase) = 0;
|
||||
/// 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;
|
||||
|
||||
/// Get the address point of the vtable for the given base subobject while
|
||||
/// building a constexpr.
|
||||
|
|
|
@ -1417,8 +1417,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
|||
|
||||
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
|
||||
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
|
||||
if (FPT && !isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
|
||||
FPT->isNothrow(getContext()))
|
||||
if (FPT && 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,14 +1984,12 @@ 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(ClassDecl));
|
||||
This.getPointer(), getContext().getRecordType(D->getParent()));
|
||||
|
||||
if (D->isTrivial() && D->isDefaultConstructor()) {
|
||||
assert(E->getNumArgs() == 0 && "trivial default ctor with args");
|
||||
|
@ -2007,7 +2005,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(ClassDecl);
|
||||
QualType DestTy = getContext().getTypeDeclType(D->getParent());
|
||||
EmitAggregateCopyCtor(This, Src, DestTy, SrcTy);
|
||||
return;
|
||||
}
|
||||
|
@ -2030,48 +2028,6 @@ 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:
|
||||
// - If vtable is external then it's safe to use it (for available_externally
|
||||
// CGVTables will make sure if it can emit it).
|
||||
// - Otherwise we can refer to vtable if it's safe to speculatively emit.
|
||||
// FIXME: If vtable is used by ctor/dtor, we are always safe to refer to it.
|
||||
if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
|
||||
ClassDecl->isDynamicClass() && Type != Ctor_Base &&
|
||||
(CGM.getVTables().isVTableExternal(ClassDecl) ||
|
||||
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
|
||||
|
@ -2237,12 +2193,24 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, Address Addr) {
|
|||
PushDestructorCleanup(D, Addr);
|
||||
}
|
||||
|
||||
void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
|
||||
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;
|
||||
|
||||
// Compute the address point.
|
||||
bool NeedsVirtualOffset;
|
||||
llvm::Value *VTableAddressPoint =
|
||||
CGM.getCXXABI().getVTableAddressPointInStructor(
|
||||
*this, Vptr.VTableClass, Vptr.Base, Vptr.NearestVBase);
|
||||
|
||||
*this, VTableClass, Base, NearestVBase, NeedsVirtualOffset);
|
||||
if (!VTableAddressPoint)
|
||||
return;
|
||||
|
||||
|
@ -2250,25 +2218,27 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
|
|||
llvm::Value *VirtualOffset = nullptr;
|
||||
CharUnits NonVirtualOffset = CharUnits::Zero();
|
||||
|
||||
if (CGM.getCXXABI().isVirtualOffsetNeededForVTableField(*this, Vptr)) {
|
||||
if (NeedsVirtualOffset) {
|
||||
// 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(), Vptr.VTableClass, Vptr.NearestVBase);
|
||||
NonVirtualOffset = Vptr.OffsetFromNearestVBase;
|
||||
VirtualOffset =
|
||||
CGM.getCXXABI().GetVirtualBaseClassOffset(*this, LoadCXXThisAddress(),
|
||||
VTableClass, NearestVBase);
|
||||
NonVirtualOffset = OffsetFromNearestVBase;
|
||||
} else {
|
||||
// We can just use the base offset in the complete class.
|
||||
NonVirtualOffset = Vptr.Base.getBaseOffset();
|
||||
NonVirtualOffset = Base.getBaseOffset();
|
||||
}
|
||||
|
||||
// Apply the offsets.
|
||||
Address VTableField = LoadCXXThisAddress();
|
||||
|
||||
if (!NonVirtualOffset.isZero() || VirtualOffset)
|
||||
VTableField = ApplyNonVirtualAndVirtualOffset(
|
||||
*this, VTableField, NonVirtualOffset, VirtualOffset, Vptr.VTableClass,
|
||||
Vptr.NearestVBase);
|
||||
VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField,
|
||||
NonVirtualOffset,
|
||||
VirtualOffset,
|
||||
VTableClass,
|
||||
NearestVBase);
|
||||
|
||||
// Finally, store the address point. Use the same LLVM types as the field to
|
||||
// support optimization.
|
||||
|
@ -2278,36 +2248,23 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
|
|||
->getPointerTo();
|
||||
VTableField = Builder.CreateBitCast(VTableField, VTablePtrTy->getPointerTo());
|
||||
VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
|
||||
|
||||
llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
|
||||
CGM.DecorateInstruction(Store, CGM.getTBAAInfoForVTablePtr());
|
||||
}
|
||||
|
||||
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) {
|
||||
void
|
||||
CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy& VBases) {
|
||||
// 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.
|
||||
VPtr Vptr = {Base, NearestVBase, OffsetFromNearestVBase, VTableClass};
|
||||
Vptrs.push_back(Vptr);
|
||||
InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase,
|
||||
VTableClass);
|
||||
}
|
||||
|
||||
const CXXRecordDecl *RD = Base.getBase();
|
||||
|
@ -2345,10 +2302,11 @@ void CodeGenFunction::getVTablePointers(BaseSubobject Base,
|
|||
BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
|
||||
}
|
||||
|
||||
getVTablePointers(
|
||||
BaseSubobject(BaseDecl, BaseOffset),
|
||||
I.isVirtual() ? BaseDecl : NearestVBase, BaseOffsetFromNearestVBase,
|
||||
BaseDeclIsNonVirtualPrimaryBase, VTableClass, VBases, Vptrs);
|
||||
InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
|
||||
I.isVirtual() ? BaseDecl : NearestVBase,
|
||||
BaseOffsetFromNearestVBase,
|
||||
BaseDeclIsNonVirtualPrimaryBase,
|
||||
VTableClass, VBases);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2358,9 +2316,11 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
|
|||
return;
|
||||
|
||||
// Initialize the vtable pointers for this class and all of its bases.
|
||||
if (CGM.getCXXABI().doStructorsInitializeVPtrs(RD))
|
||||
for (const VPtr &Vptr : getVTablePointers(RD))
|
||||
InitializeVTablePointer(Vptr);
|
||||
VisitedVirtualBasesSetTy VBases;
|
||||
InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()),
|
||||
/*NearestVBase=*/nullptr,
|
||||
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
|
||||
/*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
|
||||
|
||||
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().canSpeculativelyEmitVTable(RD);
|
||||
CGM.getCXXABI().canEmitAvailableExternallyVTable(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,27 +1354,21 @@ public:
|
|||
void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init,
|
||||
ArrayRef<VarDecl *> ArrayIndexes);
|
||||
|
||||
/// 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;
|
||||
/// InitializeVTablePointer - Initialize the vtable pointer of the given
|
||||
/// subobject.
|
||||
///
|
||||
void InitializeVTablePointer(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
const CXXRecordDecl *VTableClass);
|
||||
|
||||
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
|
||||
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(BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase,
|
||||
CharUnits OffsetFromNearestVBase,
|
||||
bool BaseIsNonVirtualPrimaryBase,
|
||||
const CXXRecordDecl *VTableClass,
|
||||
VisitedVirtualBasesSetTy& VBases);
|
||||
|
||||
void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
|
||||
|
||||
|
@ -1842,18 +1836,10 @@ 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,24 +243,10 @@ 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) override;
|
||||
|
||||
llvm::Value *getVTableAddressPointInStructorWithVTT(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase);
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
|
||||
bool &NeedsVirtualOffset) override;
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPointForConstExpr(BaseSubobject Base,
|
||||
|
@ -281,7 +267,7 @@ public:
|
|||
|
||||
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
|
||||
|
||||
bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override;
|
||||
bool canEmitAvailableExternallyVTable(const CXXRecordDecl *RD) const override;
|
||||
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
|
||||
bool ReturnAdjustment) override {
|
||||
|
@ -1473,29 +1459,41 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
|
|||
CGM.EmitVTableBitSetEntries(VTable, VTLayout);
|
||||
}
|
||||
|
||||
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
|
||||
CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) {
|
||||
if (Vptr.NearestVBase == nullptr)
|
||||
return false;
|
||||
return NeedsVTTParameter(CGF.CurGD);
|
||||
}
|
||||
|
||||
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
|
||||
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
|
||||
const CXXRecordDecl *NearestVBase) {
|
||||
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
|
||||
bool NeedsVTTParam = CGM.getCXXABI().NeedsVTTParameter(CGF.CurGD);
|
||||
NeedsVirtualOffset = (NeedsVTTParam && NearestVBase);
|
||||
|
||||
if ((Base.getBase()->getNumVBases() || NearestVBase != nullptr) &&
|
||||
NeedsVTTParameter(CGF.CurGD)) {
|
||||
return getVTableAddressPointInStructorWithVTT(CGF, VTableClass, Base,
|
||||
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 getVTableAddressPoint(Base, VTableClass);
|
||||
|
||||
return VTableAddressPoint;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) {
|
||||
llvm::GlobalValue *VTable = getAddrOfVTable(VTableClass, CharUnits());
|
||||
llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
auto *VTable = getAddrOfVTable(VTableClass, CharUnits());
|
||||
|
||||
// Find the appropriate vtable within the vtable group.
|
||||
uint64_t AddressPoint = CGM.getItaniumVTableContext()
|
||||
|
@ -1510,30 +1508,6 @@ ItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base,
|
|||
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");
|
||||
|
@ -1609,7 +1583,8 @@ void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
|
|||
VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
|
||||
}
|
||||
|
||||
bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
|
||||
bool ItaniumCXXABI::canEmitAvailableExternallyVTable(
|
||||
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)
|
||||
|
|
|
@ -127,7 +127,8 @@ public:
|
|||
QualType DestTy) override;
|
||||
|
||||
bool EmitBadCastCall(CodeGenFunction &CGF) override;
|
||||
bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override {
|
||||
bool canEmitAvailableExternallyVTable(
|
||||
const CXXRecordDecl *RD) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -235,22 +236,10 @@ 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) override;
|
||||
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
|
||||
bool &NeedsVirtualOffset) override;
|
||||
|
||||
llvm::Constant *
|
||||
getVTableAddressPointForConstExpr(BaseSubobject Base,
|
||||
|
@ -1619,15 +1608,14 @@ 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) {
|
||||
llvm::Constant *VTableAddressPoint = getVTableAddressPoint(Base, VTableClass);
|
||||
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
|
||||
NeedsVirtualOffset = (NearestVBase != nullptr);
|
||||
|
||||
(void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
|
||||
VFTableIdTy ID(VTableClass, Base.getBaseOffset());
|
||||
llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
|
||||
if (!VTableAddressPoint) {
|
||||
assert(Base.getBase()->getNumVBases() &&
|
||||
!getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
|
||||
|
@ -1642,17 +1630,11 @@ static void mangleVFTableName(MicrosoftMangleContext &MangleContext,
|
|||
MangleContext.mangleCXXVFTable(RD, VFPtr->MangledPath, Out);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::getVTableAddressPoint(BaseSubobject Base,
|
||||
const CXXRecordDecl *VTableClass) {
|
||||
(void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
|
||||
VFTableIdTy ID(VTableClass, Base.getBaseOffset());
|
||||
return VFTablesMap[ID];
|
||||
}
|
||||
|
||||
llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
|
||||
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
|
||||
llvm::Constant *VFTable = getVTableAddressPoint(Base, VTableClass);
|
||||
(void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
|
||||
VFTableIdTy ID(VTableClass, Base.getBaseOffset());
|
||||
llvm::GlobalValue *VFTable = VFTablesMap[ID];
|
||||
assert(VFTable && "Couldn't find a vftable for the given base?");
|
||||
return VFTable;
|
||||
}
|
||||
|
@ -1662,7 +1644,6 @@ 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;
|
||||
|
@ -1716,11 +1697,10 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
|||
if (llvm::GlobalValue *VFTable =
|
||||
CGM.getModule().getNamedGlobal(VFTableName)) {
|
||||
VFTablesMap[ID] = VFTable;
|
||||
VTable = VTableAliasIsRequred
|
||||
? cast<llvm::GlobalVariable>(
|
||||
cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
|
||||
: cast<llvm::GlobalVariable>(VFTable);
|
||||
return VTable;
|
||||
return VTableAliasIsRequred
|
||||
? cast<llvm::GlobalVariable>(
|
||||
cast<llvm::GlobalAlias>(VFTable)->getBaseObject())
|
||||
: cast<llvm::GlobalVariable>(VFTable);
|
||||
}
|
||||
|
||||
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 -O2 | opt - -S -globalopt -o - | FileCheck %s --check-prefix=O1
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s -O1 | 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 -O2 | opt - -S -globalopt -o - | FileCheck %s --check-prefix=O1
|
||||
// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s -O1 | 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,9 +1,5 @@
|
|||
// 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
|
||||
// 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
|
||||
|
||||
namespace Test1 {
|
||||
|
||||
|
@ -384,25 +380,13 @@ 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-NONOPT-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
|
||||
// CHECK-LABEL: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
|
||||
// CHECK-NOT: comdat
|
||||
// CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
|
||||
|
||||
// This is from Test10:
|
||||
// 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-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
|
||||
// CHECK-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 | opt - -S -globalopt -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - -O2 | FileCheck %s
|
||||
|
||||
struct B;
|
||||
extern B x;
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
// 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
|
||||
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 {
|
||||
// CHECK6: @_ZTVN5test61AE = external
|
||||
struct A {
|
||||
A();
|
||||
virtual void foo();
|
||||
virtual ~A() {}
|
||||
};
|
||||
struct B : A {
|
||||
B();
|
||||
};
|
||||
// Because A's vtable is external, it's safe to generate assumption loads.
|
||||
// CHECK6-LABEL: define void @_ZN5test61gEv()
|
||||
// CHECK6: call void @_ZN5test61AC1Ev(
|
||||
// CHECK6: 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() {}
|
||||
|
||||
// CHECK8-DAG: @_ZTVN5test81DE = external unnamed_addr constant
|
||||
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();
|
||||
}
|
||||
|
||||
// CHECK8-LABEL: define void @_ZN5test81dEv()
|
||||
// CHECK8: 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();
|
||||
}
|
||||
}
|
|
@ -184,10 +184,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-DAG: @_ZTVN5Test91AE = available_externally unnamed_addr constant
|
||||
// CHECK-TEST9-DAG: @_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: @_ZTVN5Test91AE = available_externally unnamed_addr constant
|
||||
// CHECK-TEST9: @_ZTVN5Test91BE = available_externally unnamed_addr constant
|
||||
struct A {
|
||||
virtual void foo();
|
||||
virtual void bar();
|
||||
|
@ -210,22 +210,22 @@ void g() {
|
|||
namespace Test10 {
|
||||
|
||||
// because A's key function is defined here, vtable is generated in this TU
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101AE = unnamed_addr constant
|
||||
// CHECK-TEST10: @_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-DAG: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant
|
||||
// Because key function is inline we will generate vtable as linkonce_odr
|
||||
// CHECK-TEST10: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant
|
||||
struct D : A {
|
||||
void bar();
|
||||
};
|
||||
inline void D::bar() {}
|
||||
|
||||
// Because B has outline all virtual functions, we can refer to them.
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101BE = available_externally unnamed_addr constant
|
||||
// because B has outline key function then we can refer to
|
||||
// CHECK-TEST10: @_ZTVN6Test101BE = available_externally unnamed_addr constant
|
||||
struct B : A {
|
||||
void foo();
|
||||
void bar();
|
||||
|
@ -233,8 +233,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-DAG: @_ZTVN6Test101CE = external unnamed_addr constant
|
||||
// so (at the moment) we can't emit vtable available_externally
|
||||
// CHECK-TEST10: @_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 +242,7 @@ struct C : A {
|
|||
};
|
||||
|
||||
// no key function, vtable will be generated everywhere it will be used
|
||||
// CHECK-TEST10-DAG: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant
|
||||
// CHECK-TEST10: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant
|
||||
struct E : A {};
|
||||
|
||||
void g(A& a) {
|
||||
|
@ -365,3 +365,4 @@ void test() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue