SILOptimizer: run the GlobalOpt pass in the mandatory pipeline.

Replace the dynamic initialization of trivial globals with statically initialized globals, even in -Onone.
This is required to be able to use global variables in performance-annotated functions.
Also, it's a small performance improvement for -Onone.
This commit is contained in:
Erik Eckstein
2021-10-29 12:10:53 +02:00
parent dd88e0dda6
commit c578c937c8
9 changed files with 46 additions and 14 deletions

View File

@@ -1133,6 +1133,12 @@ static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
if (hasCodeCoverageInstrumentation(f, m))
return false;
// Needed by lldb to print global variables which are propagated by the
// mandatory GlobalOpt.
if (m.getOptions().OptMode == OptimizationMode::NoOptimization &&
f.isGlobalInit())
return false;
return true;
}

View File

@@ -326,6 +326,12 @@ swift::getVariableOfStaticInitializer(SILFunction *InitFunc,
return nullptr;
HasStore = true;
InitVal = cast<SingleValueInstruction>(SI->getSrc());
} else if (auto *mt = dyn_cast<MetatypeInst>(&I)) {
// Unused meta_type instructions are sometimes generated by SILGen.
// Handle this case to not require to run DeadCodeElimination before
// MandatoryGlobalOpt.
if (!mt->use_empty())
return nullptr;
} else if (!SILGlobalVariable::isValidStaticInitializerInst(&I,
I.getModule())) {
return nullptr;

View File

@@ -314,6 +314,10 @@ bool SILGlobalOpt::isAssignedOnlyOnceInInitializer(SILGlobalVariable *SILG,
if (SILG->isLet())
return true;
// Don't replace loads from `var` globals when compiled with -Onone.
if (Module->getOptions().OptMode == OptimizationMode::NoOptimization)
return false;
// If we should skip this, it is probably because there are multiple stores.
// Return false if there are multiple stores or no stores.
if (GlobalVarSkipProcessing.count(SILG) || !GlobalVarStore.count(SILG))
@@ -768,10 +772,6 @@ bool SILGlobalOpt::run() {
do {
changed = false;
for (auto &InitCalls : GlobalInitCallMap) {
// Don't optimize functions that are marked with the opt.never attribute.
if (!InitCalls.first->shouldOptimize())
continue;
// Try to create a static initializer for the global and replace all uses
// of the global by this constant value.
changed |= optimizeInitializer(InitCalls.first, InitCalls.second);
@@ -788,6 +788,10 @@ bool SILGlobalOpt::run() {
optimizeGlobalAccess(Init.first, Init.second);
}
/// Don't perform the remaining optimizations when compiled with -Onone.
if (Module->getOptions().OptMode == OptimizationMode::NoOptimization)
return HasChanged;
SmallVector<SILGlobalVariable *, 8> addrGlobals;
for (auto &addrPair : GlobalAddrMap) {
// Don't optimize functions that are marked with the opt.never attribute.

View File

@@ -181,6 +181,7 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
P.addDiagnoseLifetimeIssues();
}
P.addGlobalOpt();
P.addPerformanceDiagnostics();
// Canonical swift requires all non cond_br critical edges to be split.

View File

@@ -22,13 +22,12 @@ public func use() -> Int {
}
}
// CHECK: define {{.*}} @"$s31force_public_metadata_accessors3useSiyF"()
// CHECK-NOT: define
// CHECK: call {{.*}} %swift.metadata_response @"$s31force_public_metadata_accessors14FixedContainer{{.*}}LLOMa"
// FIXME: From within LLDB, this would be a forward declaration.
// Unfortunately this is difficult to reproduce from source alone.
// Really this should be a check for a non-internal "declare".
// CHECK: define{{.*}} swiftcc %swift.metadata_response @"$s31force_public_metadata_accessors14FixedContainer{{.*}}LLOMa"
// CHECK: define {{.*}} @"$s31force_public_metadata_accessors3useSiyF"()
// CHECK-NOT: define
// CHECK: call {{.*}} %swift.metadata_response @"$s31force_public_metadata_accessors14FixedContainer{{.*}}LLOMa"

View File

@@ -45,7 +45,7 @@ extension A {
// CHECK: @"$s7globals2g3Sbvp" = hidden global [[BOOL]] zeroinitializer, align 1
// CHECK: @"$s7globals2g6Sdvp" = hidden global [[DOUBLE]] zeroinitializer, align 8
// CHECK: @"$s7globals2g7Sfvp" = hidden global [[FLOAT]] zeroinitializer, align 4
// CHECK: @"$s7globals1AV3fooSivpZ" = hidden global [[INT]] zeroinitializer, align 8
// CHECK: @"$s7globals1AV3fooSivpZ" = hidden global [[INT]] <{ i64 5 }>, align 8
// CHECK-NOT: g8
// CHECK-NOT: g9
@@ -53,5 +53,3 @@ extension A {
// CHECK: define{{( dllexport)?}}{{( protected)?}} i32 @main(i32 %0, i8** %1) {{.*}} {
// CHECK: store i64 {{.*}}, i64* getelementptr inbounds ([[INT]], [[INT]]* @"$s7globals2g0Sivp", i32 0, i32 0), align 8
// CHECK: define internal void @"{{.*}}WZ"() {{.*}} {
// CHECK: store i64 5, i64* getelementptr inbounds (%TSi, %TSi* @"$s7globals1AV3fooSivpZ", i32 0, i32 0), align 8

View File

@@ -10,7 +10,7 @@
// optimization passes don't run when compiling a .swiftinterface that was
// generated with -Onone.
// OPT: GlobalOpt
// UNOPT-NOT: GlobalOpt
// OPT: AccessMarkerElimination
// UNOPT-NOT: AccessMarkerElimination
public func f() {}

View File

@@ -10,6 +10,8 @@ open class Cl {
final func finalMethod() {}
}
func initFunc() -> Int { return 3 }
struct Str : P {
let x: Int
@@ -17,6 +19,9 @@ struct Str : P {
return a + x
}
static let s = 27
static var s2 = 10 + s
static var s3 = initFunc() // expected-error {{global/static variable initialization can cause locking}}
}
struct AllocatingStr : P {
@@ -107,3 +112,14 @@ func testRecursion(_ i: Int) -> Int {
}
return 0
}
@_noLocks
func testGlobal() -> Int {
return Str.s + Str.s2
}
@_noLocks
func testGlobalWithComplexInit() -> Int {
return Str.s3 // expected-note {{called from here}}
}

View File

@@ -12,8 +12,10 @@
// The only way to inspect the serialized module is sil-opt. The swift
// driver will only output the SIL that it deserializes.
func initFunc() -> Int { return 42 }
@usableFromInline
let MyConst = 42
let MyConst = initFunc()
@usableFromInline
var MyVar = 3