[clang] d508561 - [AIX] Support init priority attribute
Xiangling Liao via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 8 12:40:42 PDT 2021
Author: Xiangling Liao
Date: 2021-04-08T15:40:09-04:00
New Revision: d5085617986e8ceabe7af02eb9c50f5350b3f980
URL: https://github.com/llvm/llvm-project/commit/d5085617986e8ceabe7af02eb9c50f5350b3f980
DIFF: https://github.com/llvm/llvm-project/commit/d5085617986e8ceabe7af02eb9c50f5350b3f980.diff
LOG: [AIX] Support init priority attribute
Differential Revision: https://reviews.llvm.org/D99291
Added:
Modified:
clang/lib/CodeGen/CGDeclCXX.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/CodeGen/CodeGenModule.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/aix-init-priority-attribute.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index c551901acc43..8131b5285075 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -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,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index c14918912323..f14a1c248396 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4369,8 +4369,9 @@ class CodeGenFunction : public CodeGenTypeCache {
/// 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,
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index ad432445e315..83230dbd3dee 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -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 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
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.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index e0cbcb238d1c..c10ee0446912 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -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);
+ }
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 138b9f0132b5..550fa503bf56 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -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:
diff --git a/clang/test/CodeGen/aix-init-priority-attribute.cpp b/clang/test/CodeGen/aix-init-priority-attribute.cpp
index a19a54247e69..0aa2bc2c3985 100644
--- a/clang/test/CodeGen/aix-init-priority-attribute.cpp
+++ b/clang/test/CodeGen/aix-init-priority-attribute.cpp
@@ -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: @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: fatal error: error in backend: 'init_priority' attribute is not yet supported on AIX
+// CHECK: define internal void @_GLOBAL__D_a() [[ATTR:#[0-9]+]] {
+// CHECK: entry:
+// CHECK: call void @__finalize_t5()
+// CHECK: ret void
+// CHECK: }
More information about the cfe-commits
mailing list