Skip to content

Split FSO FileWise #16981

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
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
2 changes: 2 additions & 0 deletions lib/SILOptimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_subdirectory(ARC)
add_subdirectory(Analysis)
add_subdirectory(FunctionSignatureTransforms)
add_subdirectory(IPO)
add_subdirectory(LoopTransforms)
add_subdirectory(Mandatory)
Expand All @@ -19,4 +20,5 @@ add_swift_library(swiftSILOptimizer STATIC
${MANDATORY_SOURCES}
${TRANSFORMS_SOURCES}
${IPO_SOURCES}
${FUNCTIONSIGNATURETRANSFORMS_SOURCES}
LINK_LIBRARIES swiftSIL)
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//===--- ArgumentExplosionTransform.cpp -----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "fso-argument-explosion-transform"
#include "FunctionSignatureOpts.h"
#include "llvm/Support/CommandLine.h"

using namespace swift;

static llvm::cl::opt<bool> FSODisableArgExplosion(
"sil-fso-disable-arg-explosion",
llvm::cl::desc("Do not perform argument explosion during FSO. Intended "
"only for testing purposes"));

bool FunctionSignatureTransform::ArgumentExplosionAnalyzeParameters() {
// If we are not supposed to perform argument explosion, bail.
if (FSODisableArgExplosion)
return false;

SILFunction *F = TransformDescriptor.OriginalFunction;
// Did we decide we should optimize any parameter?
bool SignatureOptimize = false;
auto Args = F->begin()->getFunctionArguments();
ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(
RCIA->get(F), F, {SILArgumentConvention::Direct_Owned});

// Analyze the argument information.
for (unsigned i : indices(Args)) {
ArgumentDescriptor &A = TransformDescriptor.ArgumentDescList[i];
// If the argument is dead, there is no point in trying to explode it. The
// dead argument pass will get it.
if (A.IsEntirelyDead) {
continue;
}

// Do not optimize argument.
if (!A.canOptimizeLiveArg()) {
continue;
}

// Explosion of generic parameters is not supported yet.
if (A.Arg->getType().hasArchetype())
continue;

A.ProjTree.computeUsesAndLiveness(A.Arg);
A.Explode = A.shouldExplode(ArgToReturnReleaseMap);

// Modified self argument.
if (A.Explode && Args[i]->isSelf()) {
TransformDescriptor.shouldModifySelfArgument = true;
}

SignatureOptimize |= A.Explode;
}
return SignatureOptimize;
}

void FunctionSignatureTransform::ArgumentExplosionFinalizeOptimizedFunction() {
SILFunction *NewF = TransformDescriptor.OptimizedFunction.get();
SILBasicBlock *BB = &*NewF->begin();
SILBuilder Builder(BB->begin());
Builder.setCurrentDebugScope(BB->getParent()->getDebugScope());
unsigned TotalArgIndex = 0;
for (ArgumentDescriptor &AD : TransformDescriptor.ArgumentDescList) {
// If this argument descriptor was dead and we removed it, just skip it. Do
// not increment the argument index.
if (AD.WasErased) {
continue;
}

// Simply continue if do not explode.
if (!AD.Explode) {
TransformDescriptor.AIM[TotalArgIndex] = AD.Index;
++TotalArgIndex;
continue;
}

assert(!AD.IsEntirelyDead &&
"Should never see completely dead values here");

// OK, we need to explode this argument.
unsigned ArgOffset = ++TotalArgIndex;
unsigned OldArgIndex = ArgOffset - 1;
llvm::SmallVector<SILValue, 8> LeafValues;

// We do this in the same order as leaf types since ProjTree expects that
// the order of leaf values matches the order of leaf types.
llvm::SmallVector<const ProjectionTreeNode *, 8> LeafNodes;
AD.ProjTree.getLiveLeafNodes(LeafNodes);

for (auto *Node : LeafNodes) {
auto OwnershipKind = *AD.getTransformedOwnershipKind(Node->getType());
LeafValues.push_back(
BB->insertFunctionArgument(ArgOffset, Node->getType(), OwnershipKind,
BB->getArgument(OldArgIndex)->getDecl()));
TransformDescriptor.AIM[TotalArgIndex - 1] = AD.Index;
++ArgOffset;
++TotalArgIndex;
}

// Then go through the projection tree constructing aggregates and replacing
// uses.
AD.ProjTree.replaceValueUsesWithLeafUses(
Builder, BB->getParent()->getLocation(), LeafValues);

// We ignored debugvalue uses when we constructed the new arguments, in
// order to preserve as much information as possible, we construct a new
// value for OrigArg from the leaf values and use that in place of the
// OrigArg.
SILValue NewOrigArgValue = AD.ProjTree.computeExplodedArgumentValue(
Builder, BB->getParent()->getLocation(), LeafValues);

// Replace all uses of the original arg with the new value.
SILArgument *OrigArg = BB->getArgument(OldArgIndex);
OrigArg->replaceAllUsesWith(NewOrigArgValue);

// Now erase the old argument since it does not have any uses. We also
// decrement ArgOffset since we have one less argument now.
BB->eraseArgument(OldArgIndex);
--TotalArgIndex;
}
}
6 changes: 6 additions & 0 deletions lib/SILOptimizer/FunctionSignatureTransforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
set(FUNCTIONSIGNATURETRANSFORMS_SOURCES
FunctionSignatureTransforms/FunctionSignatureOpts.cpp
FunctionSignatureTransforms/DeadArgumentTransform.cpp
FunctionSignatureTransforms/ArgumentExplosionTransform.cpp
FunctionSignatureTransforms/OwnedToGuaranteedTransform.cpp
PARENT_SCOPE)
104 changes: 104 additions & 0 deletions lib/SILOptimizer/FunctionSignatureTransforms/DeadArgumentTransform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//===--- DeadArgumentTransform.cpp ----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "fso-dead-argument-transform"
#include "FunctionSignatureOpts.h"
#include "swift/SIL/DebugUtils.h"
#include "llvm/Support/CommandLine.h"

using namespace swift;

static llvm::cl::opt<bool> FSODisableDeadArgument(
"sil-fso-disable-dead-argument",
llvm::cl::desc("Do not perform dead argument elimination during FSO. "
"Intended only for testing purposes"));

bool FunctionSignatureTransform::DeadArgumentAnalyzeParameters() {
if (FSODisableDeadArgument)
return false;

// Did we decide we should optimize any parameter?
SILFunction *F = TransformDescriptor.OriginalFunction;
bool SignatureOptimize = false;
auto Args = F->begin()->getFunctionArguments();
auto OrigShouldModifySelfArgument =
TransformDescriptor.shouldModifySelfArgument;
// Analyze the argument information.
for (unsigned i : indices(Args)) {
ArgumentDescriptor &A = TransformDescriptor.ArgumentDescList[i];
if (!A.PInfo.hasValue()) {
// It is not an argument. It could be an indirect result.
continue;
}

if (!A.canOptimizeLiveArg()) {
continue;
}

// Check whether argument is dead.
if (!hasNonTrivialNonDebugTransitiveUsers(Args[i])) {
A.IsEntirelyDead = true;
SignatureOptimize = true;
if (Args[i]->isSelf())
TransformDescriptor.shouldModifySelfArgument = true;
}
}

if (F->getLoweredFunctionType()->isPolymorphic()) {
// If the set of dead arguments contains only type arguments,
// don't remove them, because it would produce a slower code
// for generic functions.
bool HasNonTypeDeadArguments = false;
for (auto &AD : TransformDescriptor.ArgumentDescList) {
if (AD.IsEntirelyDead &&
!isa<AnyMetatypeType>(AD.Arg->getType().getASTType())) {
HasNonTypeDeadArguments = true;
break;
}
}

if (!HasNonTypeDeadArguments) {
for (auto &AD : TransformDescriptor.ArgumentDescList) {
if (AD.IsEntirelyDead) {
AD.IsEntirelyDead = false;
break;
}
}
TransformDescriptor.shouldModifySelfArgument =
OrigShouldModifySelfArgument;
SignatureOptimize = false;
}
}

return SignatureOptimize;
}

void FunctionSignatureTransform::DeadArgumentTransformFunction() {
SILFunction *F = TransformDescriptor.OriginalFunction;
SILBasicBlock *BB = &*F->begin();
for (const ArgumentDescriptor &AD : TransformDescriptor.ArgumentDescList) {
if (!AD.IsEntirelyDead)
continue;
eraseUsesOfValue(BB->getArgument(AD.Index));
}
}

void FunctionSignatureTransform::DeadArgumentFinalizeOptimizedFunction() {
auto *BB = &*TransformDescriptor.OptimizedFunction.get()->begin();
// Remove any dead argument starting from the last argument to the first.
for (ArgumentDescriptor &AD : reverse(TransformDescriptor.ArgumentDescList)) {
if (!AD.IsEntirelyDead)
continue;
AD.WasErased = true;
BB->eraseArgument(AD.Arg->getIndex());
}
}
Loading