Skip to content

Commit 0c35b2e

Browse files
committed
refactor a bunch of stuff around Initialization to simplify the code and
make it easier to extend, NFC. 3 files changed, 196 insertions(+), 238 deletions(-) Swift SVN r27029
1 parent bea04a3 commit 0c35b2e

File tree

3 files changed

+196
-238
lines changed

3 files changed

+196
-238
lines changed

lib/SILGen/Initialization.h

+26-19
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,6 @@ class Initialization {
8181
/// SILValue of that buffer's address. If not, returns an invalid SILValue.
8282
virtual SILValue getAddressOrNull() const = 0;
8383

84-
/// Provide a value to this initialization. Called only on
85-
/// initializations with Kind::Translating.
86-
virtual void translateValue(SILGenFunction &gen, SILLocation loc,
87-
ManagedValue value) {
88-
llvm_unreachable("unexpected translated value in initialization!");
89-
}
90-
91-
virtual void bindValue(SILValue value, SILGenFunction &gen) {
92-
llvm_unreachable("can only bind letvalue!");
93-
}
94-
9584
/// Returns true if this initialization represents a single contiguous buffer.
9685
bool hasAddress() const { return getAddressOrNull().isValid(); }
9786

@@ -104,12 +93,6 @@ class Initialization {
10493
return address;
10594
}
10695

107-
/// If this initialization represents an aggregation of sub-initializations,
108-
/// return the sub-initializations. Once all the sub-initializations have been
109-
/// initialized and finalized with finishInitialization, finishInitialization
110-
/// must then be called on this aggregate initialization.
111-
virtual ArrayRef<InitializationPtr> getSubInitializations() const = 0;
112-
11396
/// If this initialization represents an aggregation of sub-initializations,
11497
/// return the sub-initializations. If it represents a single
11598
/// initialization of tuple type, explode it into initializations for each
@@ -129,21 +112,45 @@ class Initialization {
129112
/// Perform post-initialization bookkeeping for this initialization.
130113
virtual void finishInitialization(SILGenFunction &gen) {}
131114

115+
116+
/// When emitting an exploded RValue into an initialization, this method is
117+
/// called once per scalar value in the explosion.
118+
///
119+
/// If this is an *copy* of the rvalue into this initialization then isInit is
120+
/// false. If it is an *initialization* of the memory in the initialization,
121+
/// then isInit is true.
122+
virtual void copyOrInitValueInto(ManagedValue explodedElement, bool isInit,
123+
SILLocation loc, SILGenFunction &gen) = 0;
124+
132125
private:
133126
Initialization(const Initialization &) = delete;
134127
Initialization(Initialization &&) = delete;
135128

136129
virtual void _anchor();
137130
};
138131

139-
/// Abstract base class for single-buffer initializations.
132+
/// Abstract base class for single-buffer initializations. These are
133+
/// initializations that have an addressable memory object to be stored into.
140134
class SingleBufferInitialization : public Initialization {
141135
public:
142136
SingleBufferInitialization()
143137
: Initialization(Initialization::Kind::SingleBuffer)
144138
{}
145139

146-
ArrayRef<InitializationPtr> getSubInitializations() const override;
140+
virtual ~SingleBufferInitialization();
141+
142+
void copyOrInitValueInto(ManagedValue explodedElement, bool isInit,
143+
SILLocation loc, SILGenFunction &gen) override {
144+
copyOrInitValueIntoSingleBuffer(explodedElement, isInit, getAddress(),
145+
loc, gen);
146+
}
147+
148+
/// Emit the exploded element into a buffer at the specified address.
149+
static void copyOrInitValueIntoSingleBuffer(ManagedValue explodedElement,
150+
bool isInit,
151+
SILValue BufferAddress,
152+
SILLocation loc,
153+
SILGenFunction &gen);
147154
};
148155

149156
/// Abstract base class for single-buffer initializations.

lib/SILGen/RValue.cpp

+72-176
Original file line numberDiff line numberDiff line change
@@ -229,179 +229,6 @@ static SILValue implodeTupleValues(ArrayRef<ManagedValue> values,
229229
return ImplodeLoadableTupleValue<KIND>(values, gen).visit(tupleType, l);
230230
}
231231

232-
class CopyIntoTupleValues
233-
: public CanTypeVisitor<CopyIntoTupleValues,
234-
/*RetTy=*/ void,
235-
/*Args...=*/ Initialization*>
236-
{
237-
public:
238-
ArrayRef<ManagedValue> values;
239-
SILGenFunction &gen;
240-
SILLocation loc;
241-
242-
CopyIntoTupleValues(ArrayRef<ManagedValue> values, SILGenFunction &gen,
243-
SILLocation l)
244-
: values(values), gen(gen), loc(l)
245-
{}
246-
247-
void visitType(CanType t, Initialization *I) {
248-
// Pop a value off.
249-
ManagedValue orig = values[0];
250-
values = values.slice(1);
251-
252-
switch (I->kind) {
253-
case Initialization::Kind::Tuple:
254-
llvm_unreachable("tuple initialization not destructured?!");
255-
256-
case Initialization::Kind::Ignored:
257-
// Throw out the value without copying it.
258-
return;
259-
260-
case Initialization::Kind::Translating: {
261-
auto copy = orig.copyUnmanaged(gen, loc);
262-
I->translateValue(gen, loc, copy);
263-
I->finishInitialization(gen);
264-
return;
265-
}
266-
267-
case Initialization::Kind::LetValue:
268-
// If this is a non-address-only let, just bind the value.
269-
if (!I->hasAddress()) {
270-
// Disable the expression cleanup of the copy, since the let value
271-
// initialization has a cleanup that lives for the entire scope of the
272-
// let declaration.
273-
I->bindValue(orig.copyUnmanaged(gen, loc).forward(gen), gen);
274-
I->finishInitialization(gen);
275-
return;
276-
}
277-
// Otherwise, handle it the same as the singlebuffer case.
278-
SWIFT_FALLTHROUGH;
279-
280-
case Initialization::Kind::SingleBuffer:
281-
assert(orig.getValue() != I->getAddress() && "copying in place?!");
282-
orig.copyInto(gen, I->getAddress(), loc);
283-
I->finishInitialization(gen);
284-
return;
285-
}
286-
}
287-
288-
void visitTupleType(CanTupleType t, Initialization *I) {
289-
// Break up the aggregate initialization if we can.
290-
if (I->canSplitIntoSubelementAddresses()) {
291-
SmallVector<InitializationPtr, 4> subInitBuf;
292-
auto subInits = I->getSubInitializationsForTuple(gen, t, subInitBuf, loc);
293-
294-
assert(subInits.size() == t->getNumElements() &&
295-
"initialization does not match tuple?!");
296-
297-
for (unsigned i = 0, e = subInits.size(); i < e; ++i)
298-
visit(t.getElementType(i), subInits[i].get());
299-
return;
300-
}
301-
302-
// Otherwise, process this by turning the values corresponding to the tuple
303-
// into a single value (through an implosion) and then binding that value to
304-
// our initialization.
305-
assert(I->kind == Initialization::Kind::LetValue);
306-
SILValue V = implodeTupleValues<ImplodeKind::Copy>(values, gen, t, loc);
307-
308-
// This will have just used up the first values in the list, pop them off.
309-
values = values.slice(getRValueSize(t));
310-
311-
I->bindValue(V, gen);
312-
I->finishInitialization(gen);
313-
}
314-
};
315-
316-
class InitializeTupleValues
317-
: public CanTypeVisitor<InitializeTupleValues,
318-
/*RetTy=*/ void,
319-
/*Args...=*/ Initialization*>
320-
{
321-
public:
322-
ArrayRef<ManagedValue> values;
323-
SILGenFunction &gen;
324-
SILLocation loc;
325-
326-
InitializeTupleValues(ArrayRef<ManagedValue> values, SILGenFunction &gen,
327-
SILLocation l)
328-
: values(values), gen(gen), loc(l)
329-
{}
330-
331-
void visitType(CanType t, Initialization *I) {
332-
// Pop a result off.
333-
ManagedValue result = values[0];
334-
values = values.slice(1);
335-
336-
switch (I->kind) {
337-
case Initialization::Kind::Tuple:
338-
llvm_unreachable("tuple initialization not destructured?!");
339-
340-
case Initialization::Kind::Ignored:
341-
// Throw out the value without storing it.
342-
return;
343-
344-
case Initialization::Kind::Translating:
345-
I->translateValue(gen, loc, result);
346-
I->finishInitialization(gen);
347-
return;
348-
349-
case Initialization::Kind::LetValue:
350-
// If this is a non-address-only let, just bind the value.
351-
if (!I->hasAddress()) {
352-
// Disable the rvalue expression cleanup, since the let value
353-
// initialization has a cleanup that lives for the entire scope of the
354-
// let declaration.
355-
I->bindValue(result.forward(gen), gen);
356-
I->finishInitialization(gen);
357-
return;
358-
}
359-
// Otherwise, handle it the same as the singlebuffer case.
360-
SWIFT_FALLTHROUGH;
361-
362-
case Initialization::Kind::SingleBuffer:
363-
// If we didn't evaluate into the initialization buffer, do so now.
364-
if (result.getValue() != I->getAddress()) {
365-
result.forwardInto(gen, loc, I->getAddress());
366-
} else {
367-
// If we did evaluate into the initialization buffer, disable the
368-
// cleanup.
369-
result.forwardCleanup(gen);
370-
}
371-
372-
I->finishInitialization(gen);
373-
return;
374-
}
375-
}
376-
377-
void visitTupleType(CanTupleType t, Initialization *I) {
378-
// Break up the aggregate initialization if we can.
379-
if (I->canSplitIntoSubelementAddresses()) {
380-
SmallVector<InitializationPtr, 4> subInitBuf;
381-
auto subInits = I->getSubInitializationsForTuple(gen, t, subInitBuf, loc);
382-
383-
assert(subInits.size() == t->getNumElements() &&
384-
"initialization does not match tuple?!");
385-
386-
for (unsigned i = 0, e = subInits.size(); i < e; ++i)
387-
visit(t.getElementType(i), subInits[i].get());
388-
return;
389-
}
390-
391-
// Otherwise, process this by turning the values corresponding to the tuple
392-
// into a single value (through an implosion) and then binding that value to
393-
// our initialization.
394-
assert(I->kind == Initialization::Kind::LetValue);
395-
SILValue V = implodeTupleValues<ImplodeKind::Forward>(values, gen, t, loc);
396-
397-
// This will have just used up the first values in the list, pop them off.
398-
values = values.slice(getRValueSize(t));
399-
400-
I->bindValue(V, gen);
401-
I->finishInitialization(gen);
402-
}
403-
};
404-
405232
class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
406233
/*RetTy*/ RValue>
407234
{
@@ -451,6 +278,73 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
451278

452279
} // end anonymous namespace
453280

281+
282+
/// Perform a copy or init operation from an array of ManagedValue (from an
283+
/// RValue) into an initialization. The RValue will have one scalar ManagedValue
284+
/// for each exploded tuple element in the RValue, so this needs to make the
285+
/// shape of the initialization match the available elements. This can be done
286+
/// one one of two ways:
287+
///
288+
/// 1) recursively scalarize down the initialization on demand if the type of
289+
/// the RValue is tuple type and the initialization supports it.
290+
/// 2) implode the corresponding values in the RValue to a scalar value of
291+
/// tuple type and process them as a unit.
292+
///
293+
/// We prefer to use approach #1 since it generates better code.
294+
///
295+
template <ImplodeKind KIND>
296+
static void copyOrInitValuesInto(Initialization *init,
297+
ArrayRef<ManagedValue> &values, CanType type,
298+
SILLocation loc, SILGenFunction &gen) {
299+
bool isInit;
300+
switch (KIND) {
301+
case ImplodeKind::Unmanaged: assert(0 && "Not handled by init");
302+
case ImplodeKind::Forward: isInit = true; break;
303+
case ImplodeKind::Copy: isInit = false; break;
304+
}
305+
306+
// If the element has non-tuple type, just serve it up to the initialization.
307+
auto tupleType = dyn_cast<TupleType>(type);
308+
if (!tupleType) {
309+
// We take the first value.
310+
ManagedValue result = values[0];
311+
values = values.slice(1);
312+
init->copyOrInitValueInto(result, isInit, loc, gen);
313+
init->finishInitialization(gen);
314+
return;
315+
}
316+
317+
318+
// If we can satisfy the tuple type by breaking up the aggregate
319+
// initialization, do so.
320+
if (init->canSplitIntoSubelementAddresses()) {
321+
SmallVector<InitializationPtr, 4> subInitBuf;
322+
auto subInits = init->getSubInitializationsForTuple(gen, type,
323+
subInitBuf, loc);
324+
325+
assert(subInits.size() == tupleType->getNumElements() &&
326+
"initialization does not match tuple?!");
327+
328+
for (unsigned i = 0, e = subInits.size(); i < e; ++i)
329+
copyOrInitValuesInto<KIND>(subInits[i].get(), values,
330+
tupleType.getElementType(i), loc, gen);
331+
return;
332+
}
333+
334+
// Otherwise, process this by turning the values corresponding to the tuple
335+
// into a single value (through an implosion) and then binding that value to
336+
// our initialization.
337+
SILValue scalar = implodeTupleValues<KIND>(values, gen, type, loc);
338+
339+
// This will have just used up the first values in the list, pop them off.
340+
values = values.slice(getRValueSize(type));
341+
342+
init->copyOrInitValueInto(ManagedValue::forUnmanaged(scalar), isInit, loc,
343+
gen);
344+
init->finishInitialization(gen);
345+
}
346+
347+
454348
RValue::RValue(ArrayRef<ManagedValue> values, CanType type)
455349
: values(values.begin(), values.end()), type(type), elementsToBeAdded(0) {
456350
if (values.size() == 1 && values[0].isInContext()) {
@@ -540,14 +434,16 @@ SILValue RValue::forwardAsSingleStorageValue(SILGenFunction &gen,
540434
void RValue::forwardInto(SILGenFunction &gen, Initialization *I,
541435
SILLocation loc) && {
542436
assert(isComplete() && "rvalue is not complete");
543-
InitializeTupleValues(values, gen, loc).visit(type, I);
437+
438+
ArrayRef<ManagedValue> elts = values;
439+
copyOrInitValuesInto<ImplodeKind::Forward>(I, elts, type, loc, gen);
544440
}
545441

546442
void RValue::copyInto(SILGenFunction &gen, Initialization *I,
547443
SILLocation loc) const & {
548444
assert(isComplete() && "rvalue is not complete");
549-
550-
CopyIntoTupleValues(values, gen, loc).visit(type, I);
445+
ArrayRef<ManagedValue> elts = values;
446+
copyOrInitValuesInto<ImplodeKind::Copy>(I, elts, type, loc, gen);
551447
}
552448

553449
ManagedValue RValue::getAsSingleValue(SILGenFunction &gen, SILLocation l) && {

0 commit comments

Comments
 (0)