Xiangling_L created this revision.
Xiangling_L added reviewers: jasonliu, hubert.reinterpretcast, ZarkoCA, xingxue.
Herald added a reviewer: aaron.ballman.
Xiangling_L requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D99291
Files:
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
Index: clang/test/CodeGen/aix-init-priority-attribute.cpp
===================================================================
--- clang/test/CodeGen/aix-init-priority-attribute.cpp
+++ 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: }
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8058,10 +8058,6 @@
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:
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4728,16 +4728,17 @@
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);
+ }
}
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -103,17 +103,17 @@
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 @@
/// 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 @@
/// 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 @@
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.
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4368,8 +4368,9 @@
/// 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,
Index: clang/lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- clang/lib/CodeGen/CGDeclCXX.cpp
+++ clang/lib/CodeGen/CGDeclCXX.cpp
@@ -499,7 +499,8 @@
} 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,16 @@
return FileName;
}
+static std::string getPrioritySuffix(unsigned int 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;
+
+ return PrioritySuffix;
+}
+
void
CodeGenModule::EmitCXXGlobalInitFunc() {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@@ -577,12 +588,8 @@
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 +603,10 @@
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 +617,7 @@
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 +652,50 @@
}
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 +802,9 @@
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,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits