[AIX] Support init priority attribute

Differential Revision: https://reviews.llvm.org/D99291
This commit is contained in:
Xiangling Liao 2021-04-08 13:40:27 -04:00
parent 3a4c0354b6
commit d508561798
6 changed files with 167 additions and 48 deletions

View File

@ -499,7 +499,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
} else if (PerformInit && ISA) {
EmitPointerToInitFunc(D, Addr, Fn, ISA);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
OrderGlobalInitsOrStermFinalizers Key(IPA->getPriority(),
PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
} else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) ||
getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR) {
@ -566,6 +567,17 @@ static SmallString<128> getTransformedFileName(llvm::Module &M) {
return FileName;
}
static std::string getPrioritySuffix(unsigned int Priority) {
assert(Priority <= 65535 && "Priority should always be <= 65535.");
// Compute the function suffix from priority. Prepend with zeroes to make
// sure the function names are also ordered as priorities.
std::string PrioritySuffix = llvm::utostr(Priority);
PrioritySuffix = std::string(6 - PrioritySuffix.size(), '0') + PrioritySuffix;
return PrioritySuffix;
}
void
CodeGenModule::EmitCXXGlobalInitFunc() {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@ -577,12 +589,8 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
const bool UseSinitAndSterm = getCXXABI().useSinitAndSterm();
// Create our global prioritized initialization function.
if (!PrioritizedCXXGlobalInits.empty()) {
assert(!UseSinitAndSterm && "Prioritized sinit and sterm functions are not"
" supported yet.");
SmallVector<llvm::Function *, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
@ -596,14 +604,10 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
LocalCXXGlobalInits.clear();
unsigned Priority = I->first.priority;
// Compute the function suffix from priority. Prepend with zeroes to make
// sure the function names are also ordered as priorities.
std::string PrioritySuffix = llvm::utostr(Priority);
// Priority is always <= 65535 (enforced by sema).
PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
unsigned int Priority = I->first.priority;
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, "_GLOBAL__I_" + PrioritySuffix, FI);
FTy, "_GLOBAL__I_" + getPrioritySuffix(Priority), FI);
for (; I < PrioE; ++I)
LocalCXXGlobalInits.push_back(I->second);
@ -614,7 +618,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
PrioritizedCXXGlobalInits.clear();
}
if (UseSinitAndSterm && CXXGlobalInits.empty())
if (getCXXABI().useSinitAndSterm() && CXXGlobalInits.empty())
return;
// Include the filename in the symbol name. Including "sub_" matches gcc
@ -649,12 +653,50 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
}
void CodeGenModule::EmitCXXGlobalCleanUpFunc() {
if (CXXGlobalDtorsOrStermFinalizers.empty())
if (CXXGlobalDtorsOrStermFinalizers.empty() &&
PrioritizedCXXStermFinalizers.empty())
return;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
// Create our global prioritized cleanup function.
if (!PrioritizedCXXStermFinalizers.empty()) {
SmallVector<CXXGlobalDtorsOrStermFinalizer_t, 8> LocalCXXStermFinalizers;
llvm::array_pod_sort(PrioritizedCXXStermFinalizers.begin(),
PrioritizedCXXStermFinalizers.end());
// Iterate over "chunks" of dtors with same priority and emit each chunk
// into separate function. Note - everything is sorted first by priority,
// second - by lex order, so we emit dtor functions in proper order.
for (SmallVectorImpl<StermFinalizerData>::iterator
I = PrioritizedCXXStermFinalizers.begin(),
E = PrioritizedCXXStermFinalizers.end();
I != E;) {
SmallVectorImpl<StermFinalizerData>::iterator PrioE =
std::upper_bound(I + 1, E, *I, StermFinalizerPriorityCmp());
LocalCXXStermFinalizers.clear();
unsigned int Priority = I->first.priority;
llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction(
FTy, "_GLOBAL__a_" + getPrioritySuffix(Priority), FI);
for (; I < PrioE; ++I) {
llvm::FunctionCallee DtorFn = I->second;
LocalCXXStermFinalizers.emplace_back(DtorFn.getFunctionType(),
DtorFn.getCallee(), nullptr);
}
CodeGenFunction(*this).GenerateCXXGlobalCleanUpFunc(
Fn, LocalCXXStermFinalizers);
AddGlobalDtor(Fn, Priority);
}
PrioritizedCXXStermFinalizers.clear();
}
if (CXXGlobalDtorsOrStermFinalizers.empty())
return;
// Create our global cleanup function.
llvm::Function *Fn =
CreateGlobalInitOrCleanUpFunction(FTy, "_GLOBAL__D_a", FI);
@ -761,8 +803,9 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
llvm::Function *Fn,
const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>> &DtorsOrStermFinalizers) {
ArrayRef<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>>
DtorsOrStermFinalizers) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,

View File

@ -4369,8 +4369,9 @@ public:
/// variables.
void GenerateCXXGlobalCleanUpFunc(
llvm::Function *Fn,
const std::vector<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>> &DtorsOrStermFinalizers);
ArrayRef<std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>>
DtorsOrStermFinalizers);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,

View File

@ -103,17 +103,17 @@ enum ForDefinition_t : bool {
ForDefinition = true
};
struct OrderGlobalInits {
struct OrderGlobalInitsOrStermFinalizers {
unsigned int priority;
unsigned int lex_order;
OrderGlobalInits(unsigned int p, unsigned int l)
OrderGlobalInitsOrStermFinalizers(unsigned int p, unsigned int l)
: priority(p), lex_order(l) {}
bool operator==(const OrderGlobalInits &RHS) const {
bool operator==(const OrderGlobalInitsOrStermFinalizers &RHS) const {
return priority == RHS.priority && lex_order == RHS.lex_order;
}
bool operator<(const OrderGlobalInits &RHS) const {
bool operator<(const OrderGlobalInitsOrStermFinalizers &RHS) const {
return std::tie(priority, lex_order) <
std::tie(RHS.priority, RHS.lex_order);
}
@ -457,7 +457,8 @@ private:
/// that we don't re-emit the initializer.
llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
GlobalInitData;
struct GlobalInitPriorityCmp {
bool operator()(const GlobalInitData &LHS,
@ -473,10 +474,26 @@ private:
/// Global destructor functions and arguments that need to run on termination.
/// When UseSinitAndSterm is set, it instead contains sterm finalizer
/// functions, which also run on unloading a shared library.
std::vector<
std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH, llvm::Constant *>>
typedef std::tuple<llvm::FunctionType *, llvm::WeakTrackingVH,
llvm::Constant *>
CXXGlobalDtorsOrStermFinalizer_t;
SmallVector<CXXGlobalDtorsOrStermFinalizer_t, 8>
CXXGlobalDtorsOrStermFinalizers;
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
StermFinalizerData;
struct StermFinalizerPriorityCmp {
bool operator()(const StermFinalizerData &LHS,
const StermFinalizerData &RHS) const {
return LHS.first.priority < RHS.first.priority;
}
};
/// Global variables with sterm finalizers whose order of initialization is
/// set by init_priority attribute.
SmallVector<StermFinalizerData, 8> PrioritizedCXXStermFinalizers;
/// The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
@ -1078,6 +1095,14 @@ public:
AddGlobalDtor(StermFinalizer, Priority);
}
void AddCXXPrioritizedStermFinalizerEntry(llvm::Function *StermFinalizer,
int Priority) {
OrderGlobalInitsOrStermFinalizers Key(Priority,
PrioritizedCXXStermFinalizers.size());
PrioritizedCXXStermFinalizers.push_back(
std::make_pair(Key, StermFinalizer));
}
/// Create or return a runtime function declaration with the specified type
/// and name. If \p AssumeConvergent is true, the call will have the
/// convergent attribute added.

View File

@ -4728,16 +4728,17 @@ void XLCXXABI::emitCXXStermFinalizer(const VarDecl &D, llvm::Function *dtorStub,
CGF.FinishFunction();
assert(!D.getAttr<InitPriorityAttr>() &&
"Prioritized sinit and sterm functions are not yet supported.");
if (isTemplateInstantiation(D.getTemplateSpecializationKind()) ||
getContext().GetGVALinkageForVariable(&D) == GVA_DiscardableODR)
if (auto *IPA = D.getAttr<InitPriorityAttr>()) {
CGM.AddCXXPrioritizedStermFinalizerEntry(StermFinalizer,
IPA->getPriority());
} else if (isTemplateInstantiation(D.getTemplateSpecializationKind()) ||
getContext().GetGVALinkageForVariable(&D) == GVA_DiscardableODR) {
// According to C++ [basic.start.init]p2, class template static data
// members (i.e., implicitly or explicitly instantiated specializations)
// have unordered initialization. As a consequence, we can put them into
// their own llvm.global_dtors entry.
CGM.AddCXXStermFinalizerToGlobalDtor(StermFinalizer, 65535);
else
} else {
CGM.AddCXXStermFinalizerEntry(StermFinalizer);
}
}

View File

@ -7926,10 +7926,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleVecTypeHint(S, D, AL);
break;
case ParsedAttr::AT_InitPriority:
if (S.Context.getTargetInfo().getTriple().isOSAIX())
llvm::report_fatal_error(
"'init_priority' attribute is not yet supported on AIX");
else
handleInitPriorityAttr(S, D, AL);
break;
case ParsedAttr::AT_Packed:

View File

@ -1,19 +1,72 @@
// RUN: not %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -x c++ -emit-llvm < %s | \
// RUN: FileCheck %s
// RUN: not %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s \
// RUN: 2>&1 | \
// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -x c++ -emit-llvm < %s | \
// RUN: FileCheck %s
class test {
int a;
public:
test(int c) { a = c; }
~test() { a = 0; }
struct test {
test() {}
~test() {}
};
__attribute__((init_priority(2000)))
test t(1);
__attribute__((init_priority(200)))
test t1;
__attribute__((init_priority(200)))
test t2;
__attribute__((init_priority(300)))
test t3;
__attribute__((init_priority(150)))
test t4;
test t5;
// CHECK: fatal error: error in backend: 'init_priority' attribute is not yet supported on AIX
// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 150, void ()* @_GLOBAL__I_000150, i8* null }, { i32, void ()*, i8* } { i32 200, void ()* @_GLOBAL__I_000200, i8* null }, { i32, void ()*, i8* } { i32 300, void ()* @_GLOBAL__I_000300, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }]
// CHECK: @llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 150, void ()* @_GLOBAL__a_000150, i8* null }, { i32, void ()*, i8* } { i32 200, void ()* @_GLOBAL__a_000200, i8* null }, { i32, void ()*, i8* } { i32 300, void ()* @_GLOBAL__a_000300, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }]
// CHECK: define internal void @_GLOBAL__I_000150() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__cxx_global_var_init.3()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__I_000200() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__cxx_global_var_init()
// CHECK: call void @__cxx_global_var_init.1()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__I_000300() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__cxx_global_var_init.2()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__sub_I__() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__cxx_global_var_init.4()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__a_000150() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__finalize_t4()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__a_000200() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__finalize_t2()
// CHECK: call void @__finalize_t1()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__a_000300() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__finalize_t3()
// CHECK: ret void
// CHECK: }
// CHECK: define internal void @_GLOBAL__D_a() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: call void @__finalize_t5()
// CHECK: ret void
// CHECK: }