Skip to content

Commit 632b72a

Browse files
committed
Refactor bottom-up function ordering code from the call graph.
This adds a new utility as well as a test pass for computing the bottom-up SCC ordering of the functions in the module. Currently all functions are included, but we could consider in the future including only those functions that are potentially reachable from outside the current scope of compilation (module or file depending on compile mode). This would allow us to skip optimizing functions that we'll eventually eliminate.
1 parent 1d8a4cd commit 632b72a

File tree

7 files changed

+753
-0
lines changed

7 files changed

+753
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===--- FunctionOrder.h - Utilities for function ordering ----*- C++ -*--===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SILANALYSIS_FUNCTIONORDER_H
14+
#define SWIFT_SILANALYSIS_FUNCTIONORDER_H
15+
16+
#include "swift/SILAnalysis/BasicCalleeAnalysis.h"
17+
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/SetVector.h"
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/TinyPtrVector.h"
22+
23+
namespace swift {
24+
25+
class BasicCalleeAnalysis;
26+
class SILFunction;
27+
class SILModule;
28+
29+
class BottomUpFunctionOrder {
30+
public:
31+
typedef TinyPtrVector<SILFunction *> SCC;
32+
33+
private:
34+
llvm::SmallVector<SCC, 32> TheSCCs;
35+
36+
// The callee analysis we use to determine the callees at each call site.
37+
BasicCalleeAnalysis *BCA;
38+
39+
unsigned NextDFSNum;
40+
llvm::DenseMap<SILFunction *, unsigned> DFSNum;
41+
llvm::DenseMap<SILFunction *, unsigned> MinDFSNum;
42+
llvm::SmallSetVector<SILFunction *, 4> DFSStack;
43+
44+
public:
45+
BottomUpFunctionOrder(SILModule &M, BasicCalleeAnalysis *BCA)
46+
: BCA(BCA), NextDFSNum(0) {
47+
FindSCCs(M);
48+
}
49+
50+
ArrayRef<SCC> getBottomUpSCCs() { return TheSCCs; }
51+
52+
private:
53+
void DFS(SILFunction *F);
54+
void FindSCCs(SILModule &M);
55+
};
56+
57+
} // end namespace swift
58+
59+
#endif

include/swift/SILPasses/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ PASS(ExternalDefsToDecls, "external-defs-to-decls",
8383
"Convert external definitions to decls")
8484
PASS(ExternalFunctionDefinitionsElimination, "external-func-definition-elim",
8585
"Eliminate external function definitions")
86+
PASS(FunctionOrderPrinter, "function-order-printer",
87+
"Print function orderings for test purposes")
8688
PASS(FunctionSignatureOpts, "function-signature-opts",
8789
"Optimize Function Signatures")
8890
PASS(ARCSequenceOpts, "arc-sequence-opts",

lib/SILAnalysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_swift_library(swiftSILAnalysis
1010
ColdBlockInfo.cpp
1111
DestructorAnalysis.cpp
1212
EscapeAnalysis.cpp
13+
FunctionOrder.cpp
1314
IVAnalysis.cpp
1415
LoopAnalysis.cpp
1516
LoopRegionAnalysis.cpp

lib/SILAnalysis/FunctionOrder.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----- FunctionOrder.cpp - Utility for function ordering --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/SILAnalysis/FunctionOrder.h"
14+
#include "swift/SIL/SILBasicBlock.h"
15+
#include "swift/SIL/SILFunction.h"
16+
#include "swift/SIL/SILInstruction.h"
17+
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/ADT/TinyPtrVector.h"
19+
#include <algorithm>
20+
21+
using namespace swift;
22+
23+
/// Use Tarjan's strongly connected components (SCC) algorithm to find
24+
/// the SCCs in the call graph.
25+
void BottomUpFunctionOrder::DFS(SILFunction *Start) {
26+
// Set the DFSNum for this node if we haven't already, and if we
27+
// have, which indicates it's already been visited, return.
28+
if (!DFSNum.insert(std::make_pair(Start, NextDFSNum)).second)
29+
return;
30+
31+
assert(MinDFSNum.find(Start) == MinDFSNum.end() &&
32+
"Function should not already have a minimum DFS number!");
33+
34+
MinDFSNum[Start] = NextDFSNum;
35+
++NextDFSNum;
36+
37+
DFSStack.insert(Start);
38+
39+
// Visit all the instructions, looking for apply sites.
40+
for (auto &B : *Start) {
41+
for (auto &I : B) {
42+
auto FAS = FullApplySite::isa(&I);
43+
if (!FAS)
44+
continue;
45+
46+
auto Callees = BCA->getCalleeList(FAS);
47+
for (auto *CalleeFn : Callees) {
48+
// If not yet visited, visit the callee.
49+
if (DFSNum.find(CalleeFn) == DFSNum.end()) {
50+
DFS(CalleeFn);
51+
MinDFSNum[Start] = std::min(MinDFSNum[Start], MinDFSNum[CalleeFn]);
52+
} else if (DFSStack.count(CalleeFn)) {
53+
// If the callee is on the stack, it update our minimum DFS
54+
// number based on it's DFS number.
55+
MinDFSNum[Start] = std::min(MinDFSNum[Start], DFSNum[CalleeFn]);
56+
}
57+
}
58+
}
59+
}
60+
61+
// If our DFS number is the minimum found, we've found a
62+
// (potentially singleton) SCC, so pop the nodes off the stack and
63+
// push the new SCC on our stack of SCCs.
64+
if (DFSNum[Start] == MinDFSNum[Start]) {
65+
SCC CurrentSCC;
66+
67+
SILFunction *Popped;
68+
do {
69+
Popped = DFSStack.pop_back_val();
70+
CurrentSCC.push_back(Popped);
71+
} while (Popped != Start);
72+
73+
TheSCCs.push_back(CurrentSCC);
74+
}
75+
}
76+
77+
void BottomUpFunctionOrder::FindSCCs(SILModule &M) {
78+
for (auto &F : M)
79+
DFS(&F);
80+
}

lib/SILPasses/UtilityPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(UTILITYPASSES_SOURCES
33
UtilityPasses/BasicCalleePrinter.cpp
44
UtilityPasses/CFGPrinter.cpp
55
UtilityPasses/CallGraphPrinter.cpp
6+
UtilityPasses/FunctionOrderPrinter.cpp
67
UtilityPasses/IVInfoPrinter.cpp
78
UtilityPasses/InstCount.cpp
89
UtilityPasses/Link.cpp
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===-- FunctionOrderPrinter.cpp - Function ordering test pass ------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This pass prints a bottom-up ordering of functions in the module (in the
14+
// sense that each function is printed before functions that call it).
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "swift/SILAnalysis/FunctionOrder.h"
19+
#include "swift/Basic/DemangleWrappers.h"
20+
#include "swift/SILAnalysis/BasicCalleeAnalysis.h"
21+
#include "swift/SIL/SILFunction.h"
22+
#include "swift/SIL/SILModule.h"
23+
#include "swift/SILPasses/Transforms.h"
24+
#include "llvm/Support/raw_ostream.h"
25+
26+
using namespace swift;
27+
28+
#define DEBUG_TYPE "function-order-printer"
29+
30+
namespace {
31+
32+
class FunctionOrderPrinterPass : public SILModuleTransform {
33+
BasicCalleeAnalysis *BCA;
34+
35+
/// The entry point to the transformation.
36+
void run() override {
37+
BCA = getAnalysis<BasicCalleeAnalysis>();
38+
auto &M = *getModule();
39+
BottomUpFunctionOrder Orderer(M, BCA);
40+
41+
llvm::outs() << "Bottom up function order:\n";
42+
auto SCCs = Orderer.getBottomUpSCCs();
43+
for (auto &SCC : SCCs) {
44+
std::string Indent;
45+
46+
if (SCC.size() != 1) {
47+
llvm::outs() << "Non-trivial SCC:\n";
48+
Indent = std::string(2, ' ');
49+
}
50+
51+
for (auto *F : SCC) {
52+
llvm::outs() << Indent
53+
<< demangle_wrappers::demangleSymbolAsString(F->getName())
54+
<< "\n";
55+
}
56+
}
57+
llvm::outs() << "\n";
58+
}
59+
60+
StringRef getName() override { return "Function Order Printer"; }
61+
};
62+
63+
} // end anonymous namespace
64+
65+
SILTransform *swift::createFunctionOrderPrinter() {
66+
return new FunctionOrderPrinterPass();
67+
}

0 commit comments

Comments
 (0)