Skip to content

Commit 5cffa73

Browse files
committed
Refactoring: extract some code of the inliner to the projection classes.
Michael, thanks for your comments! This also adds support for tuples and enums in Projection::getOperandForAggregate(). Swift SVN r24112
1 parent c1de65e commit 5cffa73

File tree

4 files changed

+130
-69
lines changed

4 files changed

+130
-69
lines changed

include/swift/SIL/Projection.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ class Projection {
223223
}
224224
}
225225

226+
/// Returns the operand of a struct, tuple or enum instruction which is
227+
/// associated with this projection. Returns an invalid SILValue if \p I is
228+
/// not a matching aggregate instruction.
229+
SILValue getOperandForAggregate(SILInstruction *I) const;
230+
226231
private:
227232
Projection(ProjectionKind Kind, SILType Type, ValueDecl *Decl,
228233
unsigned Index)
@@ -274,13 +279,11 @@ class ProjectionPath {
274279
private:
275280
PathTy Path;
276281

277-
/// This is private since in all cases where we construct a projection path we
278-
/// can fail. That implies that we only want to allow ProjectionPaths to be
279-
/// created from static factory methods that can return an rvalue of a
280-
/// projection path.
282+
public:
283+
/// Create an empty path which serves as a stack. Use push_back() to populate
284+
/// the stack with members.
281285
ProjectionPath() : Path() {}
282286

283-
public:
284287
~ProjectionPath() = default;
285288

286289
/// Do not allow copy construction. The only way to get one of these is from
@@ -317,6 +320,15 @@ class ProjectionPath {
317320
findMatchingValueProjectionPaths(SILInstruction *I,
318321
SmallVectorImpl<SILInstruction *> &T) const;
319322

323+
/// Pushes an element to the path.
324+
void push_back(const Projection &Proj) { Path.push_back(Proj); }
325+
326+
/// Removes the last element from the path.
327+
void pop_back() { Path.pop_back(); }
328+
329+
/// Returns the last element of the path.
330+
const Projection &back() const { return Path.back(); }
331+
320332
/// Returns true if LHS and RHS have all the same projections in the same
321333
/// order.
322334
bool operator==(const ProjectionPath &RHS) const {

lib/SIL/Projection.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,31 @@ createAddrProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const {
239239
}
240240
}
241241

242+
SILValue Projection::getOperandForAggregate(SILInstruction *I) const {
243+
switch (getKind()) {
244+
case ProjectionKind::Struct:
245+
if (isa<StructInst>(I))
246+
return I->getOperand(getDeclIndex());
247+
break;
248+
case ProjectionKind::Tuple:
249+
if (isa<TupleInst>(I))
250+
return I->getOperand(getIndex());
251+
break;
252+
case ProjectionKind::Enum:
253+
if (EnumInst *EI = dyn_cast<EnumInst>(I)) {
254+
if (EI->getElement() == Decl) {
255+
assert(EI->hasOperand() && "expected data operand");
256+
return EI->getOperand();
257+
}
258+
}
259+
break;
260+
case ProjectionKind::Class:
261+
// There is no SIL instruction to create a class by aggregating values.
262+
break;
263+
}
264+
return SILValue();
265+
}
266+
242267
//===----------------------------------------------------------------------===//
243268
// Projection Path
244269
//===----------------------------------------------------------------------===//

lib/SILPasses/PerformanceInliner.cpp

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ namespace {
4242
// Links between loaded and stored values.
4343
llvm::DenseMap<SILValue, SILValue> links;
4444

45-
typedef llvm::SmallVector<Projection, 8> ProjectionStack;
46-
4745
// The constant tracker of the caller function (null if this is the
4846
// tracker of the callee).
4947
ConstantTracker *callerTracker;
@@ -53,10 +51,7 @@ namespace {
5351
ApplyInst *AI;
5452

5553
// Gets the estimated constant of a value.
56-
SILInstruction *getConst(SILValue val, ProjectionStack &projStack);
57-
58-
// Get's the struct/tuple member based on the top of the projection stack.
59-
static SILValue getMember(SILInstruction *inst, ProjectionStack &projStack);
54+
SILInstruction *getConst(SILValue val, ProjectionPath &projStack);
6055

6156
public:
6257

@@ -73,7 +68,7 @@ namespace {
7368

7469
// Gets the estimated constant of a value.
7570
SILInstruction *getConst(SILValue val) {
76-
ProjectionStack projStack;
71+
ProjectionPath projStack;
7772
return getConst(val, projStack);
7873
}
7974
};
@@ -132,26 +127,17 @@ void ConstantTracker::trackInst(SILInstruction *inst) {
132127
}
133128
}
134129

135-
SILValue ConstantTracker::getMember(SILInstruction *inst,
136-
ProjectionStack &projStack) {
130+
// Get the aggregate member based on the top of the projection stack.
131+
static SILValue getMember(SILInstruction *inst, ProjectionPath &projStack) {
137132
if (!projStack.empty()) {
138133
const Projection &proj = projStack.back();
139-
switch (proj.getKind()) {
140-
case ProjectionKind::Struct:
141-
if (StructInst *SI = dyn_cast<StructInst>(inst)) {
142-
return SI->getOperand(proj.getDeclIndex());
143-
}
144-
break;
145-
default:
146-
// TODO: not yet supported
147-
break;
148-
}
134+
return proj.getOperandForAggregate(inst);
149135
}
150136
return SILValue();
151137
}
152138

153139
SILInstruction *ConstantTracker::getConst(SILValue val,
154-
ProjectionStack &projStack) {
140+
ProjectionPath &projStack) {
155141

156142
// Track the value up the dominator tree.
157143
// The val can also be an address value. In this case it refers to the
@@ -173,22 +159,11 @@ SILInstruction *ConstantTracker::getConst(SILValue val,
173159
default:
174160
break;
175161
}
176-
if (Projection::isValueProjection(inst)) {
177-
// Extract a member from a struct/tuple.
178-
auto proj = Projection::valueProjectionForInstruction(inst);
179-
if (proj) {
180-
projStack.push_back(proj.getValue());
181-
val = inst->getOperand(0);
182-
continue;
183-
}
184-
} else if (Projection::isAddrProjection(inst)) {
185-
// Extract a member address from a struct/tuple address.
186-
auto proj = Projection::addressProjectionForInstruction(inst);
187-
if (proj) {
188-
projStack.push_back(proj.getValue());
189-
val = inst->getOperand(0);
190-
continue;
191-
}
162+
if (auto proj = Projection::projectionForInstruction(inst)) {
163+
// Extract a member from a struct/tuple/enum.
164+
projStack.push_back(proj.getValue());
165+
val = inst->getOperand(0);
166+
continue;
192167
} else if (SILValue member = getMember(inst, projStack)) {
193168
// The opposite of a projection instruction: composing a struct/tuple.
194169
projStack.pop_back();

test/SILPasses/inline_heuristics.sil

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ struct Cont {
1818
var cl: (Int) -> Int
1919
}
2020

21+
struct Cont2 {
22+
var tp: (Int, (Int) -> Int)
23+
}
24+
25+
enum E {
26+
case A
27+
case B((Int) -> Int)
28+
}
29+
30+
2131
// CHECK-LABEL: sil @testDirectClosure
2232
// CHECK: [[C:%[0-9]+]] = thin_to_thick_function
2333
// CHECK: apply [[C]](
@@ -30,7 +40,7 @@ struct Cont {
3040
sil @testDirectClosure : $@thin () -> Int {
3141
bb0:
3242
%0 = function_ref @takeDirectClosure : $@thin (@owned @callee_owned (Int) -> Int) -> Int
33-
%1 = function_ref @directClosure : $@thin (Int) -> Int
43+
%1 = function_ref @closure : $@thin (Int) -> Int
3444
%2 = thin_to_thick_function %1 : $@thin (Int) -> Int to $@callee_owned (Int) -> Int
3545
%3 = apply %0(%2) : $@thin (@owned @callee_owned (Int) -> Int) -> Int
3646
return %3 : $Int
@@ -44,18 +54,6 @@ bb0(%0 : $@callee_owned (Int) -> Int):
4454
return %3 : $Int
4555
}
4656

47-
sil shared @directClosure : $@thin (Int) -> Int {
48-
bb0(%0 : $Int):
49-
%1 = integer_literal $Builtin.Word, 1
50-
%2 = struct_extract %0 : $Int, #Int.value
51-
%3 = integer_literal $Builtin.Int1, -1
52-
%4 = builtin "sadd_with_overflow_Word"(%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
53-
%5 = tuple_extract %4 : $(Builtin.Word, Builtin.Int1), 0
54-
%6 = tuple_extract %4 : $(Builtin.Word, Builtin.Int1), 1
55-
cond_fail %6 : $Builtin.Int1
56-
%8 = struct $Int (%5 : $Builtin.Word)
57-
return %8 : $Int
58-
}
5957

6058
// CHECK-LABEL: sil @testStructClosure
6159
// CHECK: [[C:%[0-9]+]] = struct_extract
@@ -69,7 +67,7 @@ bb0(%0 : $Int):
6967
sil @testStructClosure : $@thin () -> Int {
7068
bb0:
7169
%0 = function_ref @takeStructClosure : $@thin (@owned Cont) -> Int
72-
%1 = function_ref @structClosure : $@thin (Int) -> Int
70+
%1 = function_ref @closure : $@thin (Int) -> Int
7371
%2 = thin_to_thick_function %1 : $@thin (Int) -> Int to $@callee_owned (Int) -> Int
7472
%3 = struct $Cont (%2 : $@callee_owned (Int) -> Int)
7573
%4 = apply %0(%3) : $@thin (@owned Cont) -> Int
@@ -85,18 +83,6 @@ bb0(%0 : $Cont):
8583
return %4 : $Int
8684
}
8785

88-
sil shared @structClosure : $@thin (Int) -> Int {
89-
bb0(%0 : $Int):
90-
%1 = integer_literal $Builtin.Word, 1
91-
%2 = struct_extract %0 : $Int, #Int.value
92-
%3 = integer_literal $Builtin.Int1, -1
93-
%4 = builtin "sadd_with_overflow_Word"(%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
94-
%5 = tuple_extract %4 : $(Builtin.Word, Builtin.Int1), 0
95-
%6 = tuple_extract %4 : $(Builtin.Word, Builtin.Int1), 1
96-
cond_fail %6 : $Builtin.Int1
97-
%8 = struct $Int (%5 : $Builtin.Word)
98-
return %8 : $Int
99-
}
10086

10187
// CHECK-LABEL: sil @testStructAddrClosure
10288
// CHECK: [[C:%[0-9]+]] = load
@@ -110,7 +96,7 @@ bb0(%0 : $Int):
11096
sil @testStructAddrClosure : $@thin () -> Int {
11197
bb0:
11298
%0 = alloc_stack $Cont
113-
%1 = function_ref @structAddrClosure : $@thin (Int) -> Int
99+
%1 = function_ref @closure : $@thin (Int) -> Int
114100
%2 = thin_to_thick_function %1 : $@thin (Int) -> Int to $@callee_owned (Int) -> Int
115101
%3 = struct $Cont (%2 : $@callee_owned (Int) -> Int)
116102
store %3 to %0#1 : $*Cont
@@ -134,7 +120,70 @@ bb0(%0 : $*Cont):
134120
return %6 : $Int
135121
}
136122

137-
sil shared @structAddrClosure : $@thin (Int) -> Int {
123+
124+
// CHECK-LABEL: sil @testTupleClosure
125+
// CHECK: [[C:%[0-9]+]] = tuple_extract
126+
// CHECK: apply [[C]](
127+
// CHECK: return
128+
129+
// LOG-LABEL: Visiting Function: testTupleClosure
130+
// LOG: Eligible callee: takeTupleClosure
131+
// LOG: Boost: apply const function
132+
133+
sil @takeTupleClosure : $@thin (@owned Cont2) -> Int {
134+
bb0(%0 : $Cont2):
135+
%1 = struct_extract %0 : $Cont2, #Cont2.tp
136+
%2 = tuple_extract %1 : $(Int, @callee_owned (Int) -> Int), 1
137+
%3 = integer_literal $Builtin.Word, 27
138+
%4 = struct $Int (%3 : $Builtin.Word)
139+
%5 = apply %2(%4) : $@callee_owned (Int) -> Int
140+
return %5 : $Int
141+
}
142+
143+
sil @testTupleClosure : $@thin () -> Int {
144+
bb0:
145+
%0 = function_ref @takeTupleClosure : $@thin (@owned Cont2) -> Int
146+
%1 = integer_literal $Builtin.Word, 27
147+
%2 = struct $Int (%1 : $Builtin.Word)
148+
%3 = function_ref @closure : $@thin (Int) -> Int
149+
%4 = thin_to_thick_function %3 : $@thin (Int) -> Int to $@callee_owned (Int) -> Int
150+
%5 = tuple (%2 : $Int, %4 : $@callee_owned (Int) -> Int)
151+
%6 = struct $Cont2 (%5 : $(Int, @callee_owned (Int) -> Int))
152+
%7 = apply %0(%6) : $@thin (@owned Cont2) -> Int
153+
return %7 : $Int
154+
}
155+
156+
157+
// CHECK-LABEL: sil @testEnumClosure
158+
// CHECK: [[C:%[0-9]+]] = unchecked_enum_data
159+
// CHECK: apply [[C]](
160+
// CHECK: return
161+
162+
// LOG-LABEL: Visiting Function: testEnumClosure
163+
// LOG: Eligible callee: takeEnumClosure
164+
// LOG: Boost: apply const function
165+
166+
sil @takeEnumClosure : $@thin (@owned E) -> Int {
167+
bb0(%0 : $E):
168+
%1 = unchecked_enum_data %0 : $E, #E.B!enumelt.1
169+
%2 = integer_literal $Builtin.Word, 27
170+
%3 = struct $Int (%2 : $Builtin.Word)
171+
%4 = apply %1(%3) : $@callee_owned (Int) -> Int
172+
return %4 : $Int
173+
}
174+
175+
sil @testEnumClosure : $@thin () -> Int {
176+
bb0:
177+
%0 = function_ref @takeEnumClosure : $@thin (@owned E) -> Int
178+
%1 = function_ref @closure : $@thin (Int) -> Int
179+
%2 = thin_to_thick_function %1 : $@thin (Int) -> Int to $@callee_owned (Int) -> Int
180+
%3 = enum $E, #E.B!enumelt.1, %2 : $@callee_owned (Int) -> Int
181+
%4 = apply %0(%3) : $@thin (@owned E) -> Int
182+
return %4 : $Int
183+
}
184+
185+
186+
sil shared @closure : $@thin (Int) -> Int {
138187
bb0(%0 : $Int):
139188
%1 = integer_literal $Builtin.Word, 1
140189
%2 = struct_extract %0 : $Int, #Int.value

0 commit comments

Comments
 (0)