Skip to content

Commit d3ac588

Browse files
Merge pull request #11720 from aschwaighofer/osize_4.0
Add an Osize option
2 parents 148b57b + f1498aa commit d3ac588

32 files changed

+1785
-1523
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class IRGenOptions {
9696
/// Whether or not to run optimization passes.
9797
unsigned Optimize : 1;
9898

99+
/// Whether or not to optimize for code size.
100+
unsigned OptimizeForSize : 1;
101+
99102
/// Which sanitizer is turned on.
100103
SanitizerKind Sanitize : 2;
101104

@@ -172,7 +175,8 @@ class IRGenOptions {
172175

173176
IRGenOptions()
174177
: DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly),
175-
Verify(true), Optimize(false), Sanitize(SanitizerKind::None),
178+
Verify(true), Optimize(false), OptimizeForSize(false),
179+
Sanitize(SanitizerKind::None),
176180
DebugInfoKind(IRGenDebugInfoKind::None), UseJIT(false),
177181
DisableLLVMOptzns(false), DisableLLVMARCOpts(false),
178182
DisableLLVMSLPVectorizer(false), DisableFPElim(true), Playground(false),
@@ -196,6 +200,7 @@ class IRGenOptions {
196200
unsigned getLLVMCodeGenOptionsHash() {
197201
unsigned Hash = 0;
198202
Hash = (Hash << 1) | Optimize;
203+
Hash = (Hash << 1) | OptimizeForSize;
199204
Hash = (Hash << 1) | DisableLLVMOptzns;
200205
Hash = (Hash << 1) | DisableLLVMARCOpts;
201206
return Hash;

include/swift/AST/SILOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class SILOptions {
5151
None,
5252
Debug,
5353
Optimize,
54+
OptimizeForSize,
5455
OptimizeUnchecked
5556
};
5657

include/swift/Option/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ def Onone : Flag<["-"], "Onone">, Group<O_Group>, Flags<[FrontendOption]>,
374374
HelpText<"Compile without any optimization">;
375375
def O : Flag<["-"], "O">, Group<O_Group>, Flags<[FrontendOption]>,
376376
HelpText<"Compile with optimizations">;
377+
def Osize : Flag<["-"], "Osize">, Group<O_Group>, Flags<[FrontendOption]>,
378+
HelpText<"Compile with optimizations and target small code size">;
377379
def Ounchecked : Flag<["-"], "Ounchecked">, Group<O_Group>,
378380
Flags<[FrontendOption]>,
379381
HelpText<"Compile with optimizations and remove runtime safety checks">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,23 +1373,34 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
13731373
Args.hasArg(OPT_sil_serialize_witness_tables);
13741374

13751375
// Parse the optimization level.
1376+
// Default to Onone settings if no option is passed.
1377+
IRGenOpts.Optimize = false;
1378+
IRGenOpts.OptimizeForSize = false;
1379+
Opts.Optimization = SILOptions::SILOptMode::None;
13761380
if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
13771381
if (A->getOption().matches(OPT_Onone)) {
13781382
IRGenOpts.Optimize = false;
13791383
Opts.Optimization = SILOptions::SILOptMode::None;
13801384
} else if (A->getOption().matches(OPT_Ounchecked)) {
13811385
// Turn on optimizations and remove all runtime checks.
13821386
IRGenOpts.Optimize = true;
1387+
IRGenOpts.OptimizeForSize = false;
13831388
Opts.Optimization = SILOptions::SILOptMode::OptimizeUnchecked;
13841389
// Removal of cond_fail (overflow on binary operations).
13851390
Opts.RemoveRuntimeAsserts = true;
13861391
Opts.AssertConfig = SILOptions::Unchecked;
13871392
} else if (A->getOption().matches(OPT_Oplayground)) {
13881393
// For now -Oplayground is equivalent to -Onone.
13891394
IRGenOpts.Optimize = false;
1395+
IRGenOpts.OptimizeForSize = false;
13901396
Opts.Optimization = SILOptions::SILOptMode::None;
1397+
} else if (A->getOption().matches(OPT_Osize)) {
1398+
IRGenOpts.Optimize = true;
1399+
IRGenOpts.OptimizeForSize = true;
1400+
Opts.Optimization = SILOptions::SILOptMode::OptimizeForSize;
13911401
} else {
13921402
assert(A->getOption().matches(OPT_O));
1403+
IRGenOpts.OptimizeForSize = false;
13931404
IRGenOpts.Optimize = true;
13941405
Opts.Optimization = SILOptions::SILOptMode::Optimize;
13951406
}

lib/FrontendTool/FrontendTool.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,7 @@ static bool emitIndexData(SourceFile *PrimarySourceFile,
10241024
isDebugCompilation = true;
10251025
break;
10261026
case SILOptions::SILOptMode::Optimize:
1027+
case SILOptions::SILOptMode::OptimizeForSize:
10271028
case SILOptions::SILOptMode::OptimizeUnchecked:
10281029
isDebugCompilation = false;
10291030
break;
@@ -1123,6 +1124,8 @@ silOptModeArgStr(SILOptions::SILOptMode mode) {
11231124
return "O";
11241125
case SILOptions::SILOptMode::OptimizeUnchecked:
11251126
return "Ounchecked";
1127+
case SILOptions::SILOptMode::OptimizeForSize:
1128+
return "Osize";
11261129
default:
11271130
return "Onone";
11281131
}

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,9 @@ static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM,
13851385
if (!isTypeMetadataAccessTrivial(IGM, type)) {
13861386
cacheVariable = cast<llvm::GlobalVariable>(
13871387
IGM.getAddrOfTypeMetadataLazyCacheVariable(type, ForDefinition));
1388+
1389+
if (IGM.IRGen.Opts.OptimizeForSize)
1390+
accessor->addFnAttr(llvm::Attribute::NoInline);
13881391
}
13891392

13901393
emitLazyCacheAccessFunction(IGM, accessor, cacheVariable,
@@ -1427,6 +1430,9 @@ static llvm::Function *getGenericTypeMetadataAccessFunction(IRGenModule &IGM,
14271430
if (!shouldDefine || !accessor->empty())
14281431
return accessor;
14291432

1433+
if (IGM.IRGen.Opts.OptimizeForSize)
1434+
accessor->addFnAttr(llvm::Attribute::NoInline);
1435+
14301436
emitLazyCacheAccessFunction(IGM, accessor, /*cacheVariable=*/nullptr,
14311437
[&](IRGenFunction &IGF) -> llvm::Value* {
14321438
return emitGenericMetadataAccessFunction(IGF, nominal, genericArgs);

lib/IRGen/GenProto.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,9 @@ getWitnessTableLazyAccessFunction(IRGenModule &IGM,
990990
if (!accessor->empty())
991991
return accessor;
992992

993+
if (IGM.IRGen.Opts.OptimizeForSize)
994+
accessor->addFnAttr(llvm::Attribute::NoInline);
995+
993996
// Okay, define the accessor.
994997
auto cacheVariable = cast<llvm::GlobalVariable>(
995998
IGM.getAddrOfWitnessTableLazyCacheVariable(conformance, conformingType,
@@ -1318,6 +1321,8 @@ getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement,
13181321
llvm::Function *accessor =
13191322
IGM.getAddrOfAssociatedTypeMetadataAccessFunction(&Conformance,
13201323
requirement);
1324+
if (IGM.IRGen.Opts.OptimizeForSize)
1325+
accessor->addFnAttr(llvm::Attribute::NoInline);
13211326

13221327
IRGenFunction IGF(IGM, accessor);
13231328
if (IGM.DebugInfo)
@@ -1428,6 +1433,9 @@ getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType,
14281433
if (IGM.DebugInfo)
14291434
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
14301435

1436+
if (IGM.IRGen.Opts.OptimizeForSize)
1437+
accessor->addFnAttr(llvm::Attribute::NoInline);
1438+
14311439
Explosion parameters = IGF.collectParameters();
14321440

14331441
llvm::Value *associatedTypeMetadata = parameters.claimNext();

lib/IRGen/IRGenModule.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,11 @@ llvm::AttributeSet IRGenModule::constructInitialAttributes() {
828828
llvm::AttributeSet::FunctionIndex, "target-features",
829829
allFeatures);
830830
}
831+
832+
if (IRGen.Opts.OptimizeForSize)
833+
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
834+
llvm::AttributeSet::FunctionIndex,
835+
llvm::Attribute::OptimizeForSize);
831836
return attrsUpdated;
832837
}
833838

lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2292,9 +2292,16 @@ class SwiftArrayOptPass : public SILFunctionTransform {
22922292
if (!ShouldSpecializeArrayProps)
22932293
return;
22942294

2295+
auto *Fn = getFunction();
2296+
2297+
// Don't hoist array property calls at Osize.
2298+
auto OptMode = Fn->getModule().getOptions().Optimization;
2299+
if (OptMode == SILOptions::SILOptMode::OptimizeForSize)
2300+
return;
2301+
22952302
DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
22962303
SILLoopAnalysis *LA = PM->getAnalysis<SILLoopAnalysis>();
2297-
SILLoopInfo *LI = LA->get(getFunction());
2304+
SILLoopInfo *LI = LA->get(Fn);
22982305

22992306
bool HasChanged = false;
23002307

lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,11 @@ class FunctionSignatureOpts : public SILFunctionTransform {
11401140
void run() override {
11411141
auto *F = getFunction();
11421142

1143+
// Don't run function signature optimizations at -Os.
1144+
if (F->getModule().getOptions().Optimization ==
1145+
SILOptions::SILOptMode::OptimizeForSize)
1146+
return;
1147+
11431148
// Don't optimize callees that should not be optimized.
11441149
if (!F->shouldOptimize())
11451150
return;

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class SILPerformanceInliner {
108108
DefaultApplyLength = 10
109109
};
110110

111+
SILOptions::SILOptMode OptMode;
112+
111113
#ifndef NDEBUG
112114
SILFunction *LastPrintedCaller = nullptr;
113115
void dumpCaller(SILFunction *Caller) {
@@ -146,8 +148,10 @@ class SILPerformanceInliner {
146148

147149
public:
148150
SILPerformanceInliner(InlineSelection WhatToInline, DominanceAnalysis *DA,
149-
SILLoopAnalysis *LA, SideEffectAnalysis *SEA)
150-
: WhatToInline(WhatToInline), DA(DA), LA(LA), SEA(SEA), CBI(DA) {}
151+
SILLoopAnalysis *LA, SideEffectAnalysis *SEA,
152+
SILOptions::SILOptMode OptMode)
153+
: WhatToInline(WhatToInline), DA(DA), LA(LA), SEA(SEA), CBI(DA),
154+
OptMode(OptMode) {}
151155

152156
bool inlineCallsIntoFunction(SILFunction *F);
153157
};
@@ -170,6 +174,26 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
170174

171175
assert(EnableSILInliningOfGenerics || !IsGeneric);
172176

177+
// Start with a base benefit.
178+
int BaseBenefit = RemovedCallBenefit;
179+
180+
// Osize heuristic.
181+
if (OptMode == SILOptions::SILOptMode::OptimizeForSize) {
182+
// Don't inline into thunks.
183+
if (AI.getFunction()->isThunk())
184+
return false;
185+
186+
// Don't inline class methods.
187+
if (Callee->hasSelfParam()) {
188+
auto SelfTy = Callee->getLoweredFunctionType()->getSelfInstanceType();
189+
if (SelfTy->mayHaveSuperclass() &&
190+
Callee->getRepresentation() == SILFunctionTypeRepresentation::Method)
191+
return false;
192+
}
193+
194+
BaseBenefit = BaseBenefit / 2;
195+
}
196+
173197
// Bail out if this generic call can be optimized by means of
174198
// the generic specialization, because we prefer generic specialization
175199
// to inlining of generics.
@@ -190,21 +214,16 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
190214
int CalleeCost = 0;
191215
int Benefit = 0;
192216

193-
// Start with a base benefit.
194-
int BaseBenefit = RemovedCallBenefit;
195-
196217
SubstitutionMap CalleeSubstMap;
197218
if (IsGeneric) {
198219
CalleeSubstMap = Callee->getLoweredFunctionType()
199220
->getGenericSignature()
200221
->getSubstitutionMap(AI.getSubstitutions());
201222
}
202223

203-
const SILOptions &Opts = Callee->getModule().getOptions();
204-
205224
// For some reason -Ounchecked can accept a higher base benefit without
206225
// increasing the code size too much.
207-
if (Opts.Optimization == SILOptions::SILOptMode::OptimizeUnchecked)
226+
if (OptMode == SILOptions::SILOptMode::OptimizeUnchecked)
208227
BaseBenefit *= 2;
209228

210229
CallerWeight.updateBenefit(Benefit, BaseBenefit);
@@ -696,7 +715,9 @@ class SILPerformanceInlinerPass : public SILFunctionTransform {
696715
return;
697716
}
698717

699-
SILPerformanceInliner Inliner(WhatToInline, DA, LA, SEA);
718+
auto OptMode = getFunction()->getModule().getOptions().Optimization;
719+
720+
SILPerformanceInliner Inliner(WhatToInline, DA, LA, SEA, OptMode);
700721

701722
assert(getFunction()->isDefinition() &&
702723
"Expected only functions with bodies!");

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,13 @@ namespace {
556556
~SpeculativeDevirtualization() override {}
557557

558558
void run() override {
559+
560+
auto &CurFn = *getFunction();
561+
// Don't perform speculative devirtualization at -Os.
562+
if (CurFn.getModule().getOptions().Optimization ==
563+
SILOptions::SILOptMode::OptimizeForSize)
564+
return;
565+
559566
ClassHierarchyAnalysis *CHA = PM->getAnalysis<ClassHierarchyAnalysis>();
560567

561568
bool Changed = false;

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ set(profdata_merge_worker
135135
"${CMAKE_CURRENT_SOURCE_DIR}/../utils/profdata_merge/main.py")
136136

137137
set(TEST_MODES
138-
optimize_none optimize optimize_unchecked
138+
optimize_none optimize optimize_unchecked optimize_size
139139
only_executable only_non_executable
140140
)
141141
set(TEST_SUBSETS

test/DebugInfo/dbgvalue-insertpt.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ for i in 0 ..< 3 {
66
// CHECK-NEXT: call void @llvm.dbg.declare(metadata i{{32|64}}* %i.addr,
77
// CHECK-SAME: metadata ![[I:[0-9]+]],
88
// CHECK: %[[CAST:[0-9]+]] = bitcast %TSiSg* %[[ALLOCA]] to i{{32|64}}*
9+
// CHECK: %[[CAST:[0-9]+]] = bitcast %TSiSg* %[[ALLOCA]] to i{{32|64}}*
910
// CHECK: %[[LD:[0-9]+]] = load i{{32|64}}, i{{32|64}}* %[[CAST]]
1011
// CHECK: br i1 {{%.*}}, label %[[FAIL:.*]], label %[[SUCCESS:.*]],
1112
//

test/IDE/Inputs/foo_swift_module.printed.comments.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import SwiftOnoneSupport
12

23
precedencegroup High {
34
associativity: left

test/IRGen/generic_classes.sil

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
2+
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s --check-prefix=OSIZE
23

34
// REQUIRES: CPU=x86_64
45

@@ -366,3 +367,6 @@ entry(%c : $RootGeneric<Int32>):
366367
// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]])
367368
// CHECK: ret %swift.type* [[METADATA]]
368369
// CHECK: }
370+
371+
// OSIZE: define hidden %swift.type* @_T015generic_classes11RootGenericCMa(%swift.type*) [[ATTRS:#[0-9]+]] {
372+
// OSIZE: [[ATTRS]] = {{{.*}}noinline

test/IRGen/optimize_for_size.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -O -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s --check-prefix=O
3+
sil_stage canonical
4+
5+
import Builtin
6+
7+
// CHECK-LABEL: define{{.*}} swiftcc void @optimize_for_size_attribute({{.*}}) #0 {
8+
// O-LABEL: define{{.*}} swiftcc void @optimize_for_size_attribute({{.*}}) #0 {
9+
sil @optimize_for_size_attribute : $@convention(thin) (Builtin.Int32) -> () {
10+
bb0(%0 : $Builtin.Int32):
11+
%1 = tuple ()
12+
return %1 : $()
13+
}
14+
15+
// O-NOT: attributes #0 = {{{.*}}optsize
16+
// CHECK: attributes #0 = {{{.*}}optsize

test/IRGen/same_type_constraints.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
2+
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s --check-prefix=OSIZE
23

34
// <rdar://problem/21665983> IRGen crash with protocol extension involving same-type constraint to X<T>
45
public struct DefaultFoo<T> {
@@ -58,3 +59,6 @@ where Self : CodingType,
5859
Self.ValueType.Coder == Self {
5960
print(Self.ValueType.self)
6061
}
62+
63+
// OSIZE: define internal i8** @_T021same_type_constraints12GenericKlazzCyxq_GAA1EAA4DataQy_RszAaER_r0_lAfA0F4TypePWT(%swift.type* %"GenericKlazz<T, R>.Data", %swift.type* nocapture readonly %"GenericKlazz<T, R>", i8** nocapture readnone %"GenericKlazz<T, R>.E") [[ATTRS:#[0-9]+]] {
64+
// OSIZE: [[ATTRS]] = {{{.*}}noinline

test/IRGen/sanitize_coverage.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99

1010
import Darwin
1111

12+
class Foo {
13+
func bar() {
14+
print("foobar")
15+
}
16+
}
1217
// FIXME: We should have a reliable way of triggering an indirect call in the
1318
// LLVM IR generated from this code.
1419
func test() {
@@ -18,6 +23,9 @@ func test() {
1823
// Comparison is to trigger insertion of __sanitizer_cov_trace_cmp
1924
let z = x == y
2025
print("\(z)")
26+
// Trigger an indirect call.
27+
let foo = Foo()
28+
foo.bar()
2129
}
2230

2331
test()

test/IRGen/typemetadata.sil

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s --check-prefix=OSIZE
23

34
// REQUIRES: CPU=x86_64
45
// XFAIL: linux
@@ -47,3 +48,7 @@ bb0:
4748
// CHECK: [[RES:%.*]] = phi
4849
// CHECK-NEXT: ret %swift.type* [[RES]]
4950

51+
52+
// OSIZE: define hidden %swift.type* @_T012typemetadata1CCMa() [[ATTR:#[0-9]+]] {
53+
// OSIZE: [[ATTR]] = {{{.*}}noinline
54+

test/Interpreter/SDK/protocol_lookup_foreign.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
// rdar://20990451 is tracking the fix for compiling this test optimized.
88
// XFAIL: swift_test_mode_optimize
9+
// XFAIL: swift_test_mode_optimize_size
910
// XFAIL: swift_test_mode_optimize_unchecked
1011

1112
import Foundation

0 commit comments

Comments
 (0)