#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
if (getCodeGenOpts().OptimizationLevel == 0)
return true;
if (getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
!D->getParent()->field_empty())
return true;
if (!D->hasTrivialBody())
return true;
const CXXRecordDecl *Class = D->getParent();
if (Class->mayInsertExtraPadding())
return true;
if (Class->getNumVBases()) {
return true;
}
for (const auto *I : Class->fields())
if (I->getType().isDestructedType())
return true;
const CXXRecordDecl *UniqueBase = nullptr;
for (const auto &I : Class->bases()) {
if (I.isVirtual()) continue;
const auto *Base =
cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
if (Base->hasTrivialDestructor()) continue;
if (UniqueBase) return true;
UniqueBase = Base;
}
if (!UniqueBase)
return true;
const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
return true;
const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
D->getType()->getAs<FunctionType>()->getCallConv())
return true;
return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
GlobalDecl(BaseD, Dtor_Base),
false);
}
bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
GlobalDecl TargetDecl,
bool InEveryTU) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
llvm::GlobalValue::LinkageTypes TargetLinkage =
getFunctionLinkage(TargetDecl);
StringRef MangledName = getMangledName(AliasDecl);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry && !Entry->isDeclaration())
return false;
if (Replacements.count(MangledName))
return false;
llvm::Type *AliasValueType = getTypes().GetFunctionType(AliasDecl);
llvm::PointerType *AliasType = AliasValueType->getPointerTo();
auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
llvm::Constant *Aliasee = Ref;
if (Ref->getType() != AliasType)
Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
(TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
!TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
Replacements[MangledName] = Aliasee;
return false;
}
if (llvm::GlobalValue::isWeakForLinker(Linkage) &&
getTriple().isOSBinFormatCOFF()) {
return true;
}
if (!InEveryTU) {
if (Ref->isDeclaration())
return true;
}
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
return true;
auto *Alias = llvm::GlobalAlias::create(AliasValueType, 0, Linkage, "",
Aliasee, &getModule());
if (Entry) {
assert(Entry->getType() == AliasType &&
"declaration exists with different type");
Alias->takeName(Entry);
Entry->replaceAllUsesWith(Alias);
Entry->eraseFromParent();
} else {
Alias->setName(MangledName);
}
setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);
return false;
}
llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD,
StructorType Type) {
const CGFunctionInfo &FnInfo =
getTypes().arrangeCXXStructorDeclaration(MD, Type);
auto *Fn = cast<llvm::Function>(
getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr,
true, true));
GlobalDecl GD;
if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
GD = GlobalDecl(DD, toCXXDtorType(Type));
} else {
const auto *CD = cast<CXXConstructorDecl>(MD);
GD = GlobalDecl(CD, toCXXCtorType(Type));
}
setFunctionLinkage(GD, Fn);
setFunctionDLLStorageClass(GD, Fn);
CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
setFunctionDefinitionAttributes(MD, Fn);
SetLLVMFunctionAttributesForDefinition(MD, Fn);
return Fn;
}
llvm::Constant *CodeGenModule::getAddrOfCXXStructor(
const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo,
llvm::FunctionType *FnType, bool DontDefer, bool IsForDefinition) {
GlobalDecl GD;
if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
GD = GlobalDecl(CD, toCXXCtorType(Type));
} else {
GD = GlobalDecl(cast<CXXDestructorDecl>(MD), toCXXDtorType(Type));
}
if (!FnType) {
if (!FnInfo)
FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type);
FnType = getTypes().GetFunctionType(*FnInfo);
}
return GetOrCreateLLVMFunction(
getMangledName(GD), FnType, GD, false, DontDefer,
false, llvm::AttributeSet(), IsForDefinition);
}
static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
GlobalDecl GD,
llvm::Type *Ty,
const CXXRecordDecl *RD) {
assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
"No kext in Microsoft ABI");
GD = GD.getCanonicalDecl();
CodeGenModule &CGM = CGF.CGM;
llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
Ty = Ty->getPointerTo()->getPointerTo();
VTable = CGF.Builder.CreateBitCast(VTable, Ty);
assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
uint64_t AddressPoint =
CGM.getItaniumVTableContext().getVTableLayout(RD)
.getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
VTableIndex += AddressPoint;
llvm::Value *VFuncPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
return CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.PointerAlignInBytes);
}
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
llvm::Type *Ty) {
assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
"BuildAppleKextVirtualCall - bad Qual kind");
const Type *QTy = Qual->getAsType();
QualType T = QualType(QTy, 0);
const RecordType *RT = T->getAs<RecordType>();
assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
const auto *RD = cast<CXXRecordDecl>(RT->getDecl());
if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);
return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
}
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualDestructorCall(
const CXXDestructorDecl *DD,
CXXDtorType Type,
const CXXRecordDecl *RD) {
const auto *MD = cast<CXXMethodDecl>(DD);
if (MD->isVirtual() && Type != Dtor_Base) {
const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
DD, StructorType::Complete);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
}
return nullptr;
}