Skip to content

Add an Osize option #11720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class IRGenOptions {
/// Whether or not to run optimization passes.
unsigned Optimize : 1;

/// Whether or not to optimize for code size.
unsigned OptimizeForSize : 1;

/// Which sanitizer is turned on.
SanitizerKind Sanitize : 2;

Expand Down Expand Up @@ -172,7 +175,8 @@ class IRGenOptions {

IRGenOptions()
: DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly),
Verify(true), Optimize(false), Sanitize(SanitizerKind::None),
Verify(true), Optimize(false), OptimizeForSize(false),
Sanitize(SanitizerKind::None),
DebugInfoKind(IRGenDebugInfoKind::None), UseJIT(false),
DisableLLVMOptzns(false), DisableLLVMARCOpts(false),
DisableLLVMSLPVectorizer(false), DisableFPElim(true), Playground(false),
Expand All @@ -196,6 +200,7 @@ class IRGenOptions {
unsigned getLLVMCodeGenOptionsHash() {
unsigned Hash = 0;
Hash = (Hash << 1) | Optimize;
Hash = (Hash << 1) | OptimizeForSize;
Hash = (Hash << 1) | DisableLLVMOptzns;
Hash = (Hash << 1) | DisableLLVMARCOpts;
return Hash;
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class SILOptions {
None,
Debug,
Optimize,
OptimizeForSize,
OptimizeUnchecked
};

Expand Down
2 changes: 2 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ def Onone : Flag<["-"], "Onone">, Group<O_Group>, Flags<[FrontendOption]>,
HelpText<"Compile without any optimization">;
def O : Flag<["-"], "O">, Group<O_Group>, Flags<[FrontendOption]>,
HelpText<"Compile with optimizations">;
def Osize : Flag<["-"], "Osize">, Group<O_Group>, Flags<[FrontendOption]>,
HelpText<"Compile with optimizations and target small code size">;
def Ounchecked : Flag<["-"], "Ounchecked">, Group<O_Group>,
Flags<[FrontendOption]>,
HelpText<"Compile with optimizations and remove runtime safety checks">;
Expand Down
11 changes: 11 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1373,23 +1373,34 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
Args.hasArg(OPT_sil_serialize_witness_tables);

// Parse the optimization level.
// Default to Onone settings if no option is passed.
IRGenOpts.Optimize = false;
IRGenOpts.OptimizeForSize = false;
Opts.Optimization = SILOptions::SILOptMode::None;
if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
if (A->getOption().matches(OPT_Onone)) {
IRGenOpts.Optimize = false;
Opts.Optimization = SILOptions::SILOptMode::None;
} else if (A->getOption().matches(OPT_Ounchecked)) {
// Turn on optimizations and remove all runtime checks.
IRGenOpts.Optimize = true;
IRGenOpts.OptimizeForSize = false;
Opts.Optimization = SILOptions::SILOptMode::OptimizeUnchecked;
// Removal of cond_fail (overflow on binary operations).
Opts.RemoveRuntimeAsserts = true;
Opts.AssertConfig = SILOptions::Unchecked;
} else if (A->getOption().matches(OPT_Oplayground)) {
// For now -Oplayground is equivalent to -Onone.
IRGenOpts.Optimize = false;
IRGenOpts.OptimizeForSize = false;
Opts.Optimization = SILOptions::SILOptMode::None;
} else if (A->getOption().matches(OPT_Osize)) {
IRGenOpts.Optimize = true;
IRGenOpts.OptimizeForSize = true;
Opts.Optimization = SILOptions::SILOptMode::OptimizeForSize;
} else {
assert(A->getOption().matches(OPT_O));
IRGenOpts.OptimizeForSize = false;
IRGenOpts.Optimize = true;
Opts.Optimization = SILOptions::SILOptMode::Optimize;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,7 @@ static bool emitIndexData(SourceFile *PrimarySourceFile,
isDebugCompilation = true;
break;
case SILOptions::SILOptMode::Optimize:
case SILOptions::SILOptMode::OptimizeForSize:
case SILOptions::SILOptMode::OptimizeUnchecked:
isDebugCompilation = false;
break;
Expand Down Expand Up @@ -1123,6 +1124,8 @@ silOptModeArgStr(SILOptions::SILOptMode mode) {
return "O";
case SILOptions::SILOptMode::OptimizeUnchecked:
return "Ounchecked";
case SILOptions::SILOptMode::OptimizeForSize:
return "Osize";
default:
return "Onone";
}
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,9 @@ static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM,
if (!isTypeMetadataAccessTrivial(IGM, type)) {
cacheVariable = cast<llvm::GlobalVariable>(
IGM.getAddrOfTypeMetadataLazyCacheVariable(type, ForDefinition));

if (IGM.IRGen.Opts.OptimizeForSize)
accessor->addFnAttr(llvm::Attribute::NoInline);
}

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

if (IGM.IRGen.Opts.OptimizeForSize)
accessor->addFnAttr(llvm::Attribute::NoInline);

emitLazyCacheAccessFunction(IGM, accessor, /*cacheVariable=*/nullptr,
[&](IRGenFunction &IGF) -> llvm::Value* {
return emitGenericMetadataAccessFunction(IGF, nominal, genericArgs);
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,9 @@ getWitnessTableLazyAccessFunction(IRGenModule &IGM,
if (!accessor->empty())
return accessor;

if (IGM.IRGen.Opts.OptimizeForSize)
accessor->addFnAttr(llvm::Attribute::NoInline);

// Okay, define the accessor.
auto cacheVariable = cast<llvm::GlobalVariable>(
IGM.getAddrOfWitnessTableLazyCacheVariable(conformance, conformingType,
Expand Down Expand Up @@ -1318,6 +1321,8 @@ getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement,
llvm::Function *accessor =
IGM.getAddrOfAssociatedTypeMetadataAccessFunction(&Conformance,
requirement);
if (IGM.IRGen.Opts.OptimizeForSize)
accessor->addFnAttr(llvm::Attribute::NoInline);

IRGenFunction IGF(IGM, accessor);
if (IGM.DebugInfo)
Expand Down Expand Up @@ -1428,6 +1433,9 @@ getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType,
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);

if (IGM.IRGen.Opts.OptimizeForSize)
accessor->addFnAttr(llvm::Attribute::NoInline);

Explosion parameters = IGF.collectParameters();

llvm::Value *associatedTypeMetadata = parameters.claimNext();
Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,11 @@ llvm::AttributeSet IRGenModule::constructInitialAttributes() {
llvm::AttributeSet::FunctionIndex, "target-features",
allFeatures);
}

if (IRGen.Opts.OptimizeForSize)
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex,
llvm::Attribute::OptimizeForSize);
return attrsUpdated;
}

Expand Down
9 changes: 8 additions & 1 deletion lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2292,9 +2292,16 @@ class SwiftArrayOptPass : public SILFunctionTransform {
if (!ShouldSpecializeArrayProps)
return;

auto *Fn = getFunction();

// Don't hoist array property calls at Osize.
auto OptMode = Fn->getModule().getOptions().Optimization;
if (OptMode == SILOptions::SILOptMode::OptimizeForSize)
return;

DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
SILLoopAnalysis *LA = PM->getAnalysis<SILLoopAnalysis>();
SILLoopInfo *LI = LA->get(getFunction());
SILLoopInfo *LI = LA->get(Fn);

bool HasChanged = false;

Expand Down
5 changes: 5 additions & 0 deletions lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,11 @@ class FunctionSignatureOpts : public SILFunctionTransform {
void run() override {
auto *F = getFunction();

// Don't run function signature optimizations at -Os.
if (F->getModule().getOptions().Optimization ==
SILOptions::SILOptMode::OptimizeForSize)
return;

// Don't optimize callees that should not be optimized.
if (!F->shouldOptimize())
return;
Expand Down
39 changes: 30 additions & 9 deletions lib/SILOptimizer/Transforms/PerformanceInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class SILPerformanceInliner {
DefaultApplyLength = 10
};

SILOptions::SILOptMode OptMode;

#ifndef NDEBUG
SILFunction *LastPrintedCaller = nullptr;
void dumpCaller(SILFunction *Caller) {
Expand Down Expand Up @@ -146,8 +148,10 @@ class SILPerformanceInliner {

public:
SILPerformanceInliner(InlineSelection WhatToInline, DominanceAnalysis *DA,
SILLoopAnalysis *LA, SideEffectAnalysis *SEA)
: WhatToInline(WhatToInline), DA(DA), LA(LA), SEA(SEA), CBI(DA) {}
SILLoopAnalysis *LA, SideEffectAnalysis *SEA,
SILOptions::SILOptMode OptMode)
: WhatToInline(WhatToInline), DA(DA), LA(LA), SEA(SEA), CBI(DA),
OptMode(OptMode) {}

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

assert(EnableSILInliningOfGenerics || !IsGeneric);

// Start with a base benefit.
int BaseBenefit = RemovedCallBenefit;

// Osize heuristic.
if (OptMode == SILOptions::SILOptMode::OptimizeForSize) {
// Don't inline into thunks.
if (AI.getFunction()->isThunk())
return false;

// Don't inline class methods.
if (Callee->hasSelfParam()) {
auto SelfTy = Callee->getLoweredFunctionType()->getSelfInstanceType();
if (SelfTy->mayHaveSuperclass() &&
Callee->getRepresentation() == SILFunctionTypeRepresentation::Method)
return false;
}

BaseBenefit = BaseBenefit / 2;
}

// Bail out if this generic call can be optimized by means of
// the generic specialization, because we prefer generic specialization
// to inlining of generics.
Expand All @@ -190,21 +214,16 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
int CalleeCost = 0;
int Benefit = 0;

// Start with a base benefit.
int BaseBenefit = RemovedCallBenefit;

SubstitutionMap CalleeSubstMap;
if (IsGeneric) {
CalleeSubstMap = Callee->getLoweredFunctionType()
->getGenericSignature()
->getSubstitutionMap(AI.getSubstitutions());
}

const SILOptions &Opts = Callee->getModule().getOptions();

// For some reason -Ounchecked can accept a higher base benefit without
// increasing the code size too much.
if (Opts.Optimization == SILOptions::SILOptMode::OptimizeUnchecked)
if (OptMode == SILOptions::SILOptMode::OptimizeUnchecked)
BaseBenefit *= 2;

CallerWeight.updateBenefit(Benefit, BaseBenefit);
Expand Down Expand Up @@ -696,7 +715,9 @@ class SILPerformanceInlinerPass : public SILFunctionTransform {
return;
}

SILPerformanceInliner Inliner(WhatToInline, DA, LA, SEA);
auto OptMode = getFunction()->getModule().getOptions().Optimization;

SILPerformanceInliner Inliner(WhatToInline, DA, LA, SEA, OptMode);

assert(getFunction()->isDefinition() &&
"Expected only functions with bodies!");
Expand Down
7 changes: 7 additions & 0 deletions lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,13 @@ namespace {
~SpeculativeDevirtualization() override {}

void run() override {

auto &CurFn = *getFunction();
// Don't perform speculative devirtualization at -Os.
if (CurFn.getModule().getOptions().Optimization ==
SILOptions::SILOptMode::OptimizeForSize)
return;

ClassHierarchyAnalysis *CHA = PM->getAnalysis<ClassHierarchyAnalysis>();

bool Changed = false;
Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ set(profdata_merge_worker
"${CMAKE_CURRENT_SOURCE_DIR}/../utils/profdata_merge/main.py")

set(TEST_MODES
optimize_none optimize optimize_unchecked
optimize_none optimize optimize_unchecked optimize_size
only_executable only_non_executable
)
set(TEST_SUBSETS
Expand Down
1 change: 1 addition & 0 deletions test/DebugInfo/dbgvalue-insertpt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ for i in 0 ..< 3 {
// CHECK-NEXT: call void @llvm.dbg.declare(metadata i{{32|64}}* %i.addr,
// CHECK-SAME: metadata ![[I:[0-9]+]],
// CHECK: %[[CAST:[0-9]+]] = bitcast %TSiSg* %[[ALLOCA]] to i{{32|64}}*
// CHECK: %[[CAST:[0-9]+]] = bitcast %TSiSg* %[[ALLOCA]] to i{{32|64}}*
// CHECK: %[[LD:[0-9]+]] = load i{{32|64}}, i{{32|64}}* %[[CAST]]
// CHECK: br i1 {{%.*}}, label %[[FAIL:.*]], label %[[SUCCESS:.*]],
//
Expand Down
1 change: 1 addition & 0 deletions test/IDE/Inputs/foo_swift_module.printed.comments.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import SwiftOnoneSupport

precedencegroup High {
associativity: left
Expand Down
4 changes: 4 additions & 0 deletions test/IRGen/generic_classes.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s --check-prefix=OSIZE

// REQUIRES: CPU=x86_64

Expand Down Expand Up @@ -366,3 +367,6 @@ entry(%c : $RootGeneric<Int32>):
// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]])
// CHECK: ret %swift.type* [[METADATA]]
// CHECK: }

// OSIZE: define hidden %swift.type* @_T015generic_classes11RootGenericCMa(%swift.type*) [[ATTRS:#[0-9]+]] {
// OSIZE: [[ATTRS]] = {{{.*}}noinline
16 changes: 16 additions & 0 deletions test/IRGen/optimize_for_size.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
// RUN: %target-swift-frontend -O -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s --check-prefix=O
sil_stage canonical

import Builtin

// CHECK-LABEL: define{{.*}} swiftcc void @optimize_for_size_attribute({{.*}}) #0 {
// O-LABEL: define{{.*}} swiftcc void @optimize_for_size_attribute({{.*}}) #0 {
sil @optimize_for_size_attribute : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%1 = tuple ()
return %1 : $()
}

// O-NOT: attributes #0 = {{{.*}}optsize
// CHECK: attributes #0 = {{{.*}}optsize
4 changes: 4 additions & 0 deletions test/IRGen/same_type_constraints.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
// 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

// <rdar://problem/21665983> IRGen crash with protocol extension involving same-type constraint to X<T>
public struct DefaultFoo<T> {
Expand Down Expand Up @@ -58,3 +59,6 @@ where Self : CodingType,
Self.ValueType.Coder == Self {
print(Self.ValueType.self)
}

// 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]+]] {
// OSIZE: [[ATTRS]] = {{{.*}}noinline
8 changes: 8 additions & 0 deletions test/IRGen/sanitize_coverage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

import Darwin

class Foo {
func bar() {
print("foobar")
}
}
// FIXME: We should have a reliable way of triggering an indirect call in the
// LLVM IR generated from this code.
func test() {
Expand All @@ -18,6 +23,9 @@ func test() {
// Comparison is to trigger insertion of __sanitizer_cov_trace_cmp
let z = x == y
print("\(z)")
// Trigger an indirect call.
let foo = Foo()
foo.bar()
}

test()
Expand Down
5 changes: 5 additions & 0 deletions test/IRGen/typemetadata.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s
// RUN: %target-swift-frontend -Osize -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s --check-prefix=OSIZE

// REQUIRES: CPU=x86_64
// XFAIL: linux
Expand Down Expand Up @@ -47,3 +48,7 @@ bb0:
// CHECK: [[RES:%.*]] = phi
// CHECK-NEXT: ret %swift.type* [[RES]]


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

1 change: 1 addition & 0 deletions test/Interpreter/SDK/protocol_lookup_foreign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

// rdar://20990451 is tracking the fix for compiling this test optimized.
// XFAIL: swift_test_mode_optimize
// XFAIL: swift_test_mode_optimize_size
// XFAIL: swift_test_mode_optimize_unchecked

import Foundation
Expand Down
Loading