[SIL] Let alloc_existential_box return a single value.

And use the new project_existential_box to get to the address value.
SILGen now generates a project_existential_box for each alloc_existential_box.
And IRGen re-uses the address value from the alloc_existential_box if the operand of project_existential_box is an alloc_existential_box.
This lets the generated code be the same as before.
This commit is contained in:
Erik Eckstein
2016-01-20 10:14:44 -08:00
parent 4dab67c582
commit b7ea3b9bb2
24 changed files with 137 additions and 165 deletions

View File

@@ -703,7 +703,7 @@ Values and Operands
sil-identifier ::= [A-Za-z_0-9]+ sil-identifier ::= [A-Za-z_0-9]+
sil-value-name ::= '%' sil-identifier sil-value-name ::= '%' sil-identifier
sil-value ::= sil-value-name ('#' [0-9]+)? sil-value ::= sil-value-name
sil-value ::= 'undef' sil-value ::= 'undef'
sil-operand ::= sil-value ':' sil-type sil-operand ::= sil-value ':' sil-type
@@ -711,17 +711,6 @@ SIL values are introduced with the ``%`` sigil and named by an
alphanumeric identifier, which references the instruction or basic block alphanumeric identifier, which references the instruction or basic block
argument that produces the value. SIL values may also refer to the keyword argument that produces the value. SIL values may also refer to the keyword
'undef', which is a value of undefined contents. 'undef', which is a value of undefined contents.
In SIL, a single instruction may produce multiple values. Operands that refer
to multiple-value instructions choose the value by following the ``%name`` with
``#`` and the index of the value. For example::
// alloc_existential_box produces two values--the refcounted pointer %box#0,
// and the value address %box#1
%box = alloc_existential_box $ErrorType, $MyError
// Refer to the address
store %value to %box#1 : $*MyError
// Refer to the refcounted pointer
throw %box#0 : $ErrorType
Unlike LLVM IR, SIL instructions that take value operands *only* accept Unlike LLVM IR, SIL instructions that take value operands *only* accept
value operands. References to literal constants, functions, global variables, or value operands. References to literal constants, functions, global variables, or
@@ -3289,8 +3278,9 @@ more expensive ``alloc_existential_box``::
// The slow general way to form an ErrorType, allocating a box and // The slow general way to form an ErrorType, allocating a box and
// storing to its value buffer: // storing to its value buffer:
%error1 = alloc_existential_box $ErrorType, $NSError %error1 = alloc_existential_box $ErrorType, $NSError
%addr = project_existential_box $NSError in %error1 : $ErrorType
strong_retain %nserror: $NSError strong_retain %nserror: $NSError
store %nserror to %error1#1 : $NSError store %nserror to %addr : $NSError
// The fast path supported for NSError: // The fast path supported for NSError:
strong_retain %nserror: $NSError strong_retain %nserror: $NSError
@@ -3432,7 +3422,7 @@ alloc_existential_box
// $P must be a protocol or protocol composition type with boxed // $P must be a protocol or protocol composition type with boxed
// representation // representation
// $T must be an AST type that conforms to P // $T must be an AST type that conforms to P
// %1#0 will be of type $P // %1 will be of type $P
// %1#1 will be of type $*T', where T' is the most abstracted lowering of T // %1#1 will be of type $*T', where T' is the most abstracted lowering of T
Allocates a boxed existential container of type ``$P`` with space to hold a Allocates a boxed existential container of type ``$P`` with space to hold a
@@ -3440,8 +3430,8 @@ value of type ``$T'``. The box is not fully initialized until a valid value
has been stored into the box. If the box must be deallocated before it is has been stored into the box. If the box must be deallocated before it is
fully initialized, ``dealloc_existential_box`` must be used. A fully fully initialized, ``dealloc_existential_box`` must be used. A fully
initialized box can be ``retain``-ed and ``release``-d like any initialized box can be ``retain``-ed and ``release``-d like any
reference-counted type. The address ``%0#1`` is dependent on the lifetime of reference-counted type. The ``project_existential_box`` instruction is used
the owner reference ``%0#0``. to retrieve the address of the value inside the container.
project_existential_box project_existential_box
``````````````````````` ```````````````````````
@@ -3456,6 +3446,7 @@ project_existential_box
// %1 will be of type $*T // %1 will be of type $*T
Projects the address of the value inside a boxed existential container. Projects the address of the value inside a boxed existential container.
The address is dependent on the lifetime of the owner reference ``%0``.
It is undefined behavior if the concrete type ``$T`` is not the same type for It is undefined behavior if the concrete type ``$T`` is not the same type for
which the box was allocated with ``alloc_existential_box``. which the box was allocated with ``alloc_existential_box``.

View File

@@ -260,11 +260,11 @@ public:
AllocExistentialBoxInst * AllocExistentialBoxInst *
createAllocExistentialBox(SILLocation Loc, SILType ExistentialType, createAllocExistentialBox(SILLocation Loc, SILType ExistentialType,
CanType ConcreteType, SILType ConcreteLoweredType, CanType ConcreteType,
ArrayRef<ProtocolConformanceRef> Conformances) { ArrayRef<ProtocolConformanceRef> Conformances) {
return insert(AllocExistentialBoxInst::create( return insert(AllocExistentialBoxInst::create(
createSILDebugLocation(Loc), ExistentialType, ConcreteType, createSILDebugLocation(Loc), ExistentialType, ConcreteType,
ConcreteLoweredType, Conformances, &F)); Conformances, &F));
} }
ApplyInst *createApply(SILLocation Loc, SILValue Fn, SILType SubstFnTy, ApplyInst *createApply(SILLocation Loc, SILValue Fn, SILType SubstFnTy,

View File

@@ -457,7 +457,6 @@ SILCloner<ImplClass>::visitAllocExistentialBoxInst(
getBuilder().createAllocExistentialBox(getOpLocation(Inst->getLoc()), getBuilder().createAllocExistentialBox(getOpLocation(Inst->getLoc()),
getOpType(origExistentialType), getOpType(origExistentialType),
getOpASTType(origFormalType), getOpASTType(origFormalType),
getOpType(Inst->getLoweredConcreteType()),
conformances)); conformances));
} }

View File

@@ -588,18 +588,17 @@ public:
/// value is uninitialized. /// value is uninitialized.
class AllocExistentialBoxInst : public AllocationInst { class AllocExistentialBoxInst : public AllocationInst {
friend class SILBuilder; friend class SILBuilder;
CanType ConcreteType; CanType ConcreteType;
ArrayRef<ProtocolConformanceRef> Conformances; ArrayRef<ProtocolConformanceRef> Conformances;
AllocExistentialBoxInst(SILDebugLocation *DebugLoc, SILType ExistentialType, AllocExistentialBoxInst(SILDebugLocation *DebugLoc, SILType ExistentialType,
CanType ConcreteType, SILType ConcreteLoweredType, CanType ConcreteType,
ArrayRef<ProtocolConformanceRef> Conformances, ArrayRef<ProtocolConformanceRef> Conformances,
SILFunction *Parent); SILFunction *Parent);
static AllocExistentialBoxInst * static AllocExistentialBoxInst *
create(SILDebugLocation *DebugLoc, SILType ExistentialType, create(SILDebugLocation *DebugLoc, SILType ExistentialType,
CanType ConcreteType, SILType ConcreteLoweredType, CanType ConcreteType,
ArrayRef<ProtocolConformanceRef> Conformances, SILFunction *Parent); ArrayRef<ProtocolConformanceRef> Conformances, SILFunction *Parent);
public: public:
@@ -611,17 +610,10 @@ public:
return getType(0); return getType(0);
} }
SILType getLoweredConcreteType() const {
return getType(1);
}
ArrayRef<ProtocolConformanceRef> getConformances() const { ArrayRef<ProtocolConformanceRef> getConformances() const {
return Conformances; return Conformances;
} }
SILValue getExistentialResult() const { return SILValue(this, 0); }
SILValue getValueAddressResult() const { return SILValue(this, 1); }
ArrayRef<Operand> getAllOperands() const { return {}; } ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; } MutableArrayRef<Operand> getAllOperands() { return {}; }

View File

@@ -1668,18 +1668,14 @@ Address irgen::emitOpenExistentialBox(IRGenFunction &IGF,
/// Allocate a boxed existential container with uninitialized space to hold a /// Allocate a boxed existential container with uninitialized space to hold a
/// value of a given type. /// value of a given type.
Address irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, OwnedAddress irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
Explosion &dest,
SILType destType, SILType destType,
CanType formalSrcType, CanType formalSrcType,
SILType loweredSrcType,
ArrayRef<ProtocolConformanceRef> conformances) { ArrayRef<ProtocolConformanceRef> conformances) {
// TODO: Non-ErrorType boxed existentials. // TODO: Non-ErrorType boxed existentials.
assert(_isErrorType(destType)); assert(_isErrorType(destType));
auto &destTI = IGF.getTypeInfo(destType).as<ErrorExistentialTypeInfo>(); auto &destTI = IGF.getTypeInfo(destType).as<ErrorExistentialTypeInfo>();
auto &srcTI = IGF.getTypeInfo(loweredSrcType);
auto srcMetadata = IGF.emitTypeMetadataRef(formalSrcType); auto srcMetadata = IGF.emitTypeMetadataRef(formalSrcType);
// Should only be one conformance, for the ErrorType protocol. // Should only be one conformance, for the ErrorType protocol.
assert(conformances.size() == 1 && destTI.getStoredProtocols().size() == 1); assert(conformances.size() == 1 && destTI.getStoredProtocols().size() == 1);
@@ -1699,11 +1695,13 @@ Address irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
// Extract the box and value address from the result. // Extract the box and value address from the result.
auto box = IGF.Builder.CreateExtractValue(result, 0); auto box = IGF.Builder.CreateExtractValue(result, 0);
auto addr = IGF.Builder.CreateExtractValue(result, 1); auto addr = IGF.Builder.CreateExtractValue(result, 1);
dest.add(box);
auto archetype = ArchetypeType::getOpened(destType.getSwiftRValueType());
auto &srcTI = IGF.getTypeInfoForUnlowered(AbstractionPattern(archetype),
formalSrcType);
addr = IGF.Builder.CreateBitCast(addr, addr = IGF.Builder.CreateBitCast(addr,
srcTI.getStorageType()->getPointerTo()); srcTI.getStorageType()->getPointerTo());
return srcTI.getAddressForPointer(addr); return OwnedAddress(srcTI.getAddressForPointer(addr), box);
} }
/// Deallocate a boxed existential container with uninitialized space to hold a /// Deallocate a boxed existential container with uninitialized space to hold a

View File

@@ -65,11 +65,9 @@ namespace irgen {
/// Allocate a boxed existential container with uninitialized space to hold a /// Allocate a boxed existential container with uninitialized space to hold a
/// value of a given type. /// value of a given type.
Address emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, OwnedAddress emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
Explosion &dest,
SILType destType, SILType destType,
CanType formalSrcType, CanType formalSrcType,
SILType loweredSrcType,
ArrayRef<ProtocolConformanceRef> conformances); ArrayRef<ProtocolConformanceRef> conformances);
/// "Deinitialize" an existential container whose contained value is allocated /// "Deinitialize" an existential container whose contained value is allocated

View File

@@ -4456,14 +4456,11 @@ void IRGenSILFunction::visitInitBlockStorageHeaderInst(
} }
void IRGenSILFunction::visitAllocExistentialBoxInst(AllocExistentialBoxInst *i){ void IRGenSILFunction::visitAllocExistentialBoxInst(AllocExistentialBoxInst *i){
Explosion box; OwnedAddress boxWithAddr =
auto projectionAddr = emitBoxedExistentialContainerAllocation(*this, i->getExistentialType(),
emitBoxedExistentialContainerAllocation(*this, box, i->getExistentialType(),
i->getFormalConcreteType(), i->getFormalConcreteType(),
i->getLoweredConcreteType(),
i->getConformances()); i->getConformances());
setLoweredExplosion(i->getExistentialResult(), box); setLoweredBox(i, boxWithAddr);
setLoweredAddress(i->getValueAddressResult(), projectionAddr);
} }
void IRGenSILFunction::visitDeallocExistentialBoxInst( void IRGenSILFunction::visitDeallocExistentialBoxInst(
@@ -4485,11 +4482,18 @@ void IRGenSILFunction::visitOpenExistentialBoxInst(OpenExistentialBoxInst *i) {
void void
IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) { IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) {
const LoweredValue &val = getLoweredValue(i->getOperand());
if (val.isBoxWithAddress()) {
// The operand is an alloc_existential_box.
// We can directly reuse the address.
setLoweredAddress(i, val.getAddressOfBox());
} else {
Explosion box = getLoweredExplosion(i->getOperand()); Explosion box = getLoweredExplosion(i->getOperand());
auto caddr = emitBoxedExistentialProjection(*this, box, auto caddr = emitBoxedExistentialProjection(*this, box,
i->getOperand().getType(), i->getOperand().getType(),
i->getType().getSwiftRValueType()); i->getType().getSwiftRValueType());
setLoweredAddress(i, caddr.getAddress()); setLoweredAddress(i, caddr.getAddress());
}
} }
void IRGenSILFunction::visitDynamicMethodInst(DynamicMethodInst *i) { void IRGenSILFunction::visitDynamicMethodInst(DynamicMethodInst *i) {

View File

@@ -3301,22 +3301,13 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
parseASTType(ConcreteFormalTy)) parseASTType(ConcreteFormalTy))
return true; return true;
// Lower the type at the abstraction level of the existential.
auto archetype
= ArchetypeType::getOpened(ExistentialTy.getSwiftRValueType())
->getCanonicalType();
SILType LoweredTy = SILMod.Types.getLoweredType(
Lowering::AbstractionPattern(archetype), ConcreteFormalTy)
.getAddressType();
// Collect conformances for the type. // Collect conformances for the type.
ArrayRef<ProtocolConformanceRef> conformances ArrayRef<ProtocolConformanceRef> conformances
= collectExistentialConformances(P, ConcreteFormalTy, = collectExistentialConformances(P, ConcreteFormalTy,
ExistentialTy.getSwiftRValueType()); ExistentialTy.getSwiftRValueType());
ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy, ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy,
ConcreteFormalTy, LoweredTy, conformances); ConcreteFormalTy, conformances);
break; break;
} }

View File

@@ -127,23 +127,11 @@ VarDecl *DebugValueAddrInst::getDecl() const {
return getLoc().getAsASTNode<VarDecl>(); return getLoc().getAsASTNode<VarDecl>();
} }
static SILTypeList *getAllocExistentialBoxType(SILType ExistTy,
SILType ConcreteTy,
SILFunction &F) {
SILType Tys[] = {
ExistTy.getObjectType(),
ConcreteTy.getAddressType(),
};
return F.getModule().getSILTypeList(Tys);
}
AllocExistentialBoxInst::AllocExistentialBoxInst( AllocExistentialBoxInst::AllocExistentialBoxInst(
SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType, SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType,
SILType ConcreteLoweredType, ArrayRef<ProtocolConformanceRef> Conformances, ArrayRef<ProtocolConformanceRef> Conformances, SILFunction *Parent)
SILFunction *Parent)
: AllocationInst(ValueKind::AllocExistentialBoxInst, Loc, : AllocationInst(ValueKind::AllocExistentialBoxInst, Loc,
getAllocExistentialBoxType(ExistentialType, ExistentialType.getObjectType()),
ConcreteLoweredType, *Parent)),
ConcreteType(ConcreteType), Conformances(Conformances) {} ConcreteType(ConcreteType), Conformances(Conformances) {}
static void declareWitnessTable(SILModule &Mod, static void declareWitnessTable(SILModule &Mod,
@@ -159,7 +147,7 @@ static void declareWitnessTable(SILModule &Mod,
AllocExistentialBoxInst *AllocExistentialBoxInst::create( AllocExistentialBoxInst *AllocExistentialBoxInst::create(
SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType, SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType,
SILType ConcreteLoweredType, ArrayRef<ProtocolConformanceRef> Conformances, ArrayRef<ProtocolConformanceRef> Conformances,
SILFunction *F) { SILFunction *F) {
SILModule &Mod = F->getModule(); SILModule &Mod = F->getModule();
void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst), void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst),
@@ -169,7 +157,6 @@ AllocExistentialBoxInst *AllocExistentialBoxInst::create(
return ::new (Buffer) AllocExistentialBoxInst(Loc, return ::new (Buffer) AllocExistentialBoxInst(Loc,
ExistentialType, ExistentialType,
ConcreteType, ConcreteType,
ConcreteLoweredType,
Conformances, F); Conformances, F);
} }

View File

@@ -1126,9 +1126,18 @@ public:
"project_existential_box result must be an address"); "project_existential_box result must be an address");
if (auto *AEBI = dyn_cast<AllocExistentialBoxInst>(PEBI->getOperand())) { if (auto *AEBI = dyn_cast<AllocExistentialBoxInst>(PEBI->getOperand())) {
require(AEBI->getLoweredConcreteType() == PEBI->getType(), // The lowered type must be the properly-abstracted form of the AST type.
"type of project_existential_box does not match with the formal " SILType exType = AEBI->getExistentialType();
"type of alloc_existential_box"); auto archetype = ArchetypeType::getOpened(exType.getSwiftRValueType());
auto loweredTy = F.getModule().Types.getLoweredType(
Lowering::AbstractionPattern(archetype),
AEBI->getFormalConcreteType())
.getAddressType();
requireSameType(loweredTy, PEBI->getType(),
"project_existential_box result should be the lowered "
"concrete type of its alloc_existential_box");
} }
} }
@@ -1836,22 +1845,6 @@ public:
"alloc_existential_box must be used with a boxed existential " "alloc_existential_box must be used with a boxed existential "
"type"); "type");
// The lowered type must be the properly-abstracted form of the AST type.
auto archetype = ArchetypeType::getOpened(exType.getSwiftRValueType());
auto loweredTy = F.getModule().Types.getLoweredType(
Lowering::AbstractionPattern(archetype),
AEBI->getFormalConcreteType())
.getAddressType();
requireSameType(loweredTy, AEBI->getLoweredConcreteType(),
"alloc_existential_box #1 result should be the lowered "
"concrete type at the right abstraction level");
require(isLoweringOf(AEBI->getLoweredConcreteType(),
AEBI->getFormalConcreteType()),
"alloc_existential_box payload must be a lowering of the formal "
"concrete type");
checkExistentialProtocolConformances(exType, AEBI->getConformances()); checkExistentialProtocolConformances(exType, AEBI->getConformances());
} }

View File

@@ -448,14 +448,13 @@ ManagedValue SILGenFunction::emitExistentialErasure(
} }
case ExistentialRepresentation::Boxed: { case ExistentialRepresentation::Boxed: {
// Allocate the existential. // Allocate the existential.
auto box = B.createAllocExistentialBox(loc, auto *existential = B.createAllocExistentialBox(loc,
existentialTL.getLoweredType(), existentialTL.getLoweredType(),
concreteFormalType, concreteFormalType,
concreteTL.getLoweredType(),
conformances); conformances);
auto existential = box->getExistentialResult(); auto *valueAddr = B.createProjectExistentialBox(loc,
auto valueAddr = box->getValueAddressResult(); concreteTL.getLoweredType(),
existential);
// Initialize the concrete value in-place. // Initialize the concrete value in-place.
InitializationPtr init( InitializationPtr init(
new ExistentialInitialization(existential, valueAddr, concreteFormalType, new ExistentialInitialization(existential, valueAddr, concreteFormalType,

View File

@@ -887,13 +887,11 @@ AllocExistentialBoxInst *
SILGenBuilder::createAllocExistentialBox(SILLocation Loc, SILGenBuilder::createAllocExistentialBox(SILLocation Loc,
SILType ExistentialType, SILType ExistentialType,
CanType ConcreteType, CanType ConcreteType,
SILType ConcreteLoweredType,
ArrayRef<ProtocolConformanceRef> Conformances) { ArrayRef<ProtocolConformanceRef> Conformances) {
for (auto conformance : Conformances) for (auto conformance : Conformances)
SGM.useConformance(conformance); SGM.useConformance(conformance);
return SILBuilder::createAllocExistentialBox(Loc, ExistentialType, return SILBuilder::createAllocExistentialBox(Loc, ExistentialType,
ConcreteType, ConcreteType,
ConcreteLoweredType,
Conformances); Conformances);
} }

View File

@@ -254,7 +254,6 @@ public:
AllocExistentialBoxInst *createAllocExistentialBox(SILLocation Loc, AllocExistentialBoxInst *createAllocExistentialBox(SILLocation Loc,
SILType ExistentialType, SILType ExistentialType,
CanType ConcreteType, CanType ConcreteType,
SILType ConcreteLoweredType,
ArrayRef<ProtocolConformanceRef> Conformances); ArrayRef<ProtocolConformanceRef> Conformances);
}; };

View File

@@ -45,16 +45,27 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
StoreInst *SingleStore = nullptr; StoreInst *SingleStore = nullptr;
StrongReleaseInst *SingleRelease = nullptr; StrongReleaseInst *SingleRelease = nullptr;
ProjectExistentialBoxInst *SingleProjection = nullptr;
// For each user U of the alloc_existential_box... // For each user U of the alloc_existential_box...
for (auto U : getNonDebugUses(*AEBI)) { for (auto U : getNonDebugUses(*AEBI)) {
if (auto *PEBI = dyn_cast<ProjectExistentialBoxInst>(U->getUser())) {
if (SingleProjection) return nullptr;
SingleProjection = PEBI;
for (auto AddrUse : getNonDebugUses(*PEBI)) {
// Record stores into the box. // Record stores into the box.
if (auto *SI = dyn_cast<StoreInst>(U->getUser())) { if (auto *SI = dyn_cast<StoreInst>(AddrUse->getUser())) {
// If this is not the only store into the box then bail out. // If this is not the only store into the box then bail out.
if (SingleStore) return nullptr; if (SingleStore) return nullptr;
SingleStore = SI; SingleStore = SI;
continue; continue;
} }
// If there are other users to the box value address then bail out.
return nullptr;
}
continue;
}
// Record releases of the box. // Record releases of the box.
if (auto *RI = dyn_cast<StrongReleaseInst>(U->getUser())) { if (auto *RI = dyn_cast<StrongReleaseInst>(U->getUser())) {
@@ -69,6 +80,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
} }
if (SingleStore && SingleRelease) { if (SingleStore && SingleRelease) {
assert(SingleProjection && "store without an projection");
// Release the value that was stored into the existential box. The box // Release the value that was stored into the existential box. The box
// is going away so we need to release the stored value now. // is going away so we need to release the stored value now.
Builder.setInsertionPoint(SingleStore); Builder.setInsertionPoint(SingleStore);
@@ -78,6 +90,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
// releases the box, and finally, release the box. // releases the box, and finally, release the box.
eraseInstFromFunction(*SingleRelease); eraseInstFromFunction(*SingleRelease);
eraseInstFromFunction(*SingleStore); eraseInstFromFunction(*SingleStore);
eraseInstFromFunction(*SingleProjection);
return eraseInstFromFunction(*AEBI); return eraseInstFromFunction(*AEBI);
} }

View File

@@ -870,7 +870,6 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
break; break;
case ValueKind::AllocExistentialBoxInst: case ValueKind::AllocExistentialBoxInst:
ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy,
SILType::getPrimitiveAddressType(ConcreteTy),
ctxConformances); ctxConformances);
break; break;
} }

View File

@@ -21,10 +21,11 @@ entry(%x : $*T):
// CHECK: [[BOX:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 0 // CHECK: [[BOX:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 0
// CHECK: [[ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1 // CHECK: [[ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1
%b = alloc_existential_box $ErrorType, $T %b = alloc_existential_box $ErrorType, $T
%p = project_existential_box $T in %b : $ErrorType
// CHECK: call %swift.opaque* %initializeWithTake(%swift.opaque* [[ADDR]], %swift.opaque* %0, %swift.type* %T) // CHECK: call %swift.opaque* %initializeWithTake(%swift.opaque* [[ADDR]], %swift.opaque* %0, %swift.type* %T)
copy_addr [take] %x to [initialization] %b#1 : $*T copy_addr [take] %x to [initialization] %p : $*T
// CHECK: ret %swift.error* [[BOX]] // CHECK: ret %swift.error* [[BOX]]
return %b#0 : $ErrorType return %b : $ErrorType
} }
struct SomeError: ErrorType { struct SomeError: ErrorType {
@@ -40,9 +41,10 @@ entry(%x : $SomeError):
// CHECK: [[OPAQUE_ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1 // CHECK: [[OPAQUE_ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1
// CHECK: [[ADDR:%.*]] = bitcast %swift.opaque* [[OPAQUE_ADDR]] to %V17boxed_existential9SomeError* // CHECK: [[ADDR:%.*]] = bitcast %swift.opaque* [[OPAQUE_ADDR]] to %V17boxed_existential9SomeError*
%b = alloc_existential_box $ErrorType, $SomeError %b = alloc_existential_box $ErrorType, $SomeError
store %x to %b#1 : $*SomeError %p = project_existential_box $SomeError in %b : $ErrorType
store %x to %p : $*SomeError
// CHECK: ret %swift.error* [[BOX]] // CHECK: ret %swift.error* [[BOX]]
return %b#0 : $ErrorType return %b : $ErrorType
} }
// CHECK-LABEL: define void @dealloc_boxed_existential(%swift.error*, %swift.type* %T, i8** %T.ErrorType) // CHECK-LABEL: define void @dealloc_boxed_existential(%swift.error*, %swift.type* %T, i8** %T.ErrorType)

View File

@@ -1267,18 +1267,16 @@ sil @existential_box : $@convention(thin) (SomeError) -> () {
bb0(%0 : $SomeError): bb0(%0 : $SomeError):
// CHECK: %1 = alloc_existential_box $ErrorType, $SomeError // CHECK: %1 = alloc_existential_box $ErrorType, $SomeError
%1 = alloc_existential_box $ErrorType, $SomeError %1 = alloc_existential_box $ErrorType, $SomeError
// CHECK: store %0 to %1#1 : $*SomeError // CHECK: %2 = project_existential_box $SomeError in %1 : $ErrorType
store %0 to %1#1 : $*SomeError %2 = project_existential_box $SomeError in %1 : $ErrorType
// CHECK: %3 = project_existential_box $SomeError in %1#0 : $ErrorType // CHECK: store %0 to %2 : $*SomeError
%3 = project_existential_box $SomeError in %1#0 : $ErrorType store %0 to %2 : $*SomeError
// CHECK: store %0 to %3 : $*SomeError // CHECK: %4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
store %0 to %3 : $*SomeError %4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
// CHECK: %5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType // CHECK: destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
%5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
// CHECK: destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType // CHECK: dealloc_existential_box %1 : $ErrorType, $SomeError
destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType dealloc_existential_box %1 : $ErrorType, $SomeError
// CHECK: dealloc_existential_box %1#0 : $ErrorType, $SomeError
dealloc_existential_box %1#0 : $ErrorType, $SomeError
return undef : $() return undef : $()
} }

View File

@@ -19,8 +19,9 @@ func test_concrete_erasure(x: ClericalError) -> ErrorType {
} }
// CHECK-LABEL: sil hidden @_TF18boxed_existentials21test_concrete_erasureFOS_13ClericalErrorPs9ErrorType_ // CHECK-LABEL: sil hidden @_TF18boxed_existentials21test_concrete_erasureFOS_13ClericalErrorPs9ErrorType_
// CHECK: [[EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $ClericalError // CHECK: [[EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $ClericalError
// CHECK: store %0 to [[EXISTENTIAL]]#1 : $*ClericalError // CHECK: [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $ErrorType
// CHECK: return [[EXISTENTIAL]]#0 : $ErrorType // CHECK: store %0 to [[ADDR]] : $*ClericalError
// CHECK: return [[EXISTENTIAL]] : $ErrorType
protocol HairType {} protocol HairType {}
@@ -30,9 +31,10 @@ func test_composition_erasure(x: protocol<HairType, ErrorType>) -> ErrorType {
// CHECK-LABEL: sil hidden @_TF18boxed_existentials24test_composition_erasureFPs9ErrorTypeS_8HairType_PS0__ // CHECK-LABEL: sil hidden @_TF18boxed_existentials24test_composition_erasureFPs9ErrorTypeS_8HairType_PS0__
// CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr [[OLD_EXISTENTIAL:%.*]] : $*protocol<ErrorType, HairType> to $*[[VALUE_TYPE:@opened\(.*\) protocol<ErrorType, HairType>]] // CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr [[OLD_EXISTENTIAL:%.*]] : $*protocol<ErrorType, HairType> to $*[[VALUE_TYPE:@opened\(.*\) protocol<ErrorType, HairType>]]
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $[[VALUE_TYPE]] // CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $[[VALUE_TYPE]]
// CHECK: copy_addr [[VALUE_ADDR]] to [initialization] [[NEW_EXISTENTIAL]]#1 // CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $ErrorType
// CHECK: copy_addr [[VALUE_ADDR]] to [initialization] [[ADDR]]
// CHECK: destroy_addr [[OLD_EXISTENTIAL]] // CHECK: destroy_addr [[OLD_EXISTENTIAL]]
// CHECK: return [[NEW_EXISTENTIAL]]#0 // CHECK: return [[NEW_EXISTENTIAL]]
protocol HairClassType: class {} protocol HairClassType: class {}
@@ -42,8 +44,9 @@ func test_class_composition_erasure(x: protocol<HairClassType, ErrorType>) -> Er
// CHECK-LABEL: sil hidden @_TF18boxed_existentials30test_class_composition_erasureFPs9ErrorTypeS_13HairClassType_PS0__ // CHECK-LABEL: sil hidden @_TF18boxed_existentials30test_class_composition_erasureFPs9ErrorTypeS_13HairClassType_PS0__
// CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $protocol<ErrorType, HairClassType> to $[[VALUE_TYPE:@opened\(.*\) protocol<ErrorType, HairClassType>]] // CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $protocol<ErrorType, HairClassType> to $[[VALUE_TYPE:@opened\(.*\) protocol<ErrorType, HairClassType>]]
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $[[VALUE_TYPE]] // CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $[[VALUE_TYPE]]
// CHECK: store [[VALUE]] to [[NEW_EXISTENTIAL]]#1 // CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $ErrorType
// CHECK: return [[NEW_EXISTENTIAL]]#0 // CHECK: store [[VALUE]] to [[ADDR]]
// CHECK: return [[NEW_EXISTENTIAL]]
func test_property(x: ErrorType) -> String { func test_property(x: ErrorType) -> String {
return x._domain return x._domain

View File

@@ -21,23 +21,25 @@ func make_a_cat() throws -> Cat {
// CHECK: sil hidden @_TF6errors15dont_make_a_cat{{.*}} : $@convention(thin) () -> (@owned Cat, @error ErrorType) { // CHECK: sil hidden @_TF6errors15dont_make_a_cat{{.*}} : $@convention(thin) () -> (@owned Cat, @error ErrorType) {
// CHECK: [[BOX:%.*]] = alloc_existential_box $ErrorType, $HomeworkError // CHECK: [[BOX:%.*]] = alloc_existential_box $ErrorType, $HomeworkError
// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $ErrorType
// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type // CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
// CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooHard!enumelt // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooHard!enumelt
// CHECK-NEXT: store [[T1]] to [[BOX]]#1 // CHECK-NEXT: store [[T1]] to [[ADDR]]
// CHECK-NEXT: builtin "willThrow" // CHECK-NEXT: builtin "willThrow"
// CHECK-NEXT: throw [[BOX]]#0 // CHECK-NEXT: throw [[BOX]]
func dont_make_a_cat() throws -> Cat { func dont_make_a_cat() throws -> Cat {
throw HomeworkError.TooHard throw HomeworkError.TooHard
} }
// CHECK: sil hidden @_TF6errors11dont_return{{.*}} : $@convention(thin) <T> (@out T, @in T) -> @error ErrorType { // CHECK: sil hidden @_TF6errors11dont_return{{.*}} : $@convention(thin) <T> (@out T, @in T) -> @error ErrorType {
// CHECK: [[BOX:%.*]] = alloc_existential_box $ErrorType, $HomeworkError // CHECK: [[BOX:%.*]] = alloc_existential_box $ErrorType, $HomeworkError
// CHECK-NEXT: [[ADDR:%.*]] = project_existential_box $HomeworkError in [[BOX]] : $ErrorType
// CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type // CHECK-NEXT: [[T0:%.*]] = metatype $@thin HomeworkError.Type
// CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooMuch!enumelt // CHECK-NEXT: [[T1:%.*]] = enum $HomeworkError, #HomeworkError.TooMuch!enumelt
// CHECK-NEXT: store [[T1]] to [[BOX]]#1 // CHECK-NEXT: store [[T1]] to [[ADDR]]
// CHECK-NEXT: builtin "willThrow" // CHECK-NEXT: builtin "willThrow"
// CHECK-NEXT: destroy_addr %1 : $*T // CHECK-NEXT: destroy_addr %1 : $*T
// CHECK-NEXT: throw [[BOX]]#0 // CHECK-NEXT: throw [[BOX]]
func dont_return<T>(argument: T) throws -> T { func dont_return<T>(argument: T) throws -> T {
throw HomeworkError.TooMuch throw HomeworkError.TooMuch
} }

View File

@@ -100,15 +100,16 @@ func errorHandler(e: ErrorType) throws -> ErrorType {
// CHECK: debug_value %0 : $ErrorType // CHECK: debug_value %0 : $ErrorType
// CHECK: [[OPEN:%.*]] = open_existential_box %0 : $ErrorType to $*[[OPEN_TYPE:@opened\(.*\) ErrorType]] // CHECK: [[OPEN:%.*]] = open_existential_box %0 : $ErrorType to $*[[OPEN_TYPE:@opened\(.*\) ErrorType]]
// CHECK: [[RESULT:%.*]] = alloc_existential_box $ErrorType, $[[OPEN_TYPE]] // CHECK: [[RESULT:%.*]] = alloc_existential_box $ErrorType, $[[OPEN_TYPE]]
// CHECK: [[ADDR:%.*]] = project_existential_box $[[OPEN_TYPE]] in [[RESULT]] : $ErrorType
// CHECK: [[FUNC:%.*]] = function_ref @_TFE19existential_erasurePs9ErrorType17returnOrThrowSelf // CHECK: [[FUNC:%.*]] = function_ref @_TFE19existential_erasurePs9ErrorType17returnOrThrowSelf
// CHECK: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[RESULT]]#1, [[OPEN]]) // CHECK: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
// //
// CHECK: bb1 // CHECK: bb1
// CHECK: strong_release %0 : $ErrorType // CHECK: strong_release %0 : $ErrorType
// CHECK: return [[RESULT]]#0 : $ErrorType // CHECK: return [[RESULT]] : $ErrorType
// //
// CHECK: bb2([[FAILURE:%.*]] : $ErrorType): // CHECK: bb2([[FAILURE:%.*]] : $ErrorType):
// CHECK: dealloc_existential_box [[RESULT]]#0 // CHECK: dealloc_existential_box [[RESULT]]
// CHECK: strong_release %0 : $ErrorType // CHECK: strong_release %0 : $ErrorType
// CHECK: throw [[FAILURE]] : $ErrorType // CHECK: throw [[FAILURE]] : $ErrorType
// //

View File

@@ -8,10 +8,11 @@ throw MyError.A
// CHECK: sil @main // CHECK: sil @main
// CHECK: [[ERR:%.*]] = alloc_existential_box $ErrorType, $MyError // CHECK: [[ERR:%.*]] = alloc_existential_box $ErrorType, $MyError
// CHECK: [[ADDR:%.*]] = project_existential_box $MyError in [[ERR]] : $ErrorType
// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt // CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
// CHECK: store [[T0]] to [[ERR]]#1 : $*MyError // CHECK: store [[T0]] to [[ADDR]] : $*MyError
// CHECK: builtin "willThrow"([[ERR]]#0 : $ErrorType) // CHECK: builtin "willThrow"([[ERR]] : $ErrorType)
// CHECK: br bb2([[ERR]]#0 : $ErrorType) // CHECK: br bb2([[ERR]] : $ErrorType)
// CHECK: bb1([[T0:%.*]] : $Int32): // CHECK: bb1([[T0:%.*]] : $Int32):
// CHECK: return [[T0]] : $Int32 // CHECK: return [[T0]] : $Int32

View File

@@ -623,6 +623,8 @@ bb2(%5 : $ErrorType):
// CHECK-LABEL: CG of throwing_func // CHECK-LABEL: CG of throwing_func
// CHECK-NEXT: Arg %0 Esc: A, Succ: // CHECK-NEXT: Arg %0 Esc: A, Succ:
// CHECK-NEXT: Val %3 Esc: G, Succ: (%3.1)
// CHECK-NEXT: Con %3.1 Esc: G, Succ:
// CHECK-NEXT: Ret Esc: R, Succ: %0 // CHECK-NEXT: Ret Esc: R, Succ: %0
// CHECK-NEXT: End // CHECK-NEXT: End
sil @throwing_func : $@convention(thin) (@owned X) -> (@owned X, @error ErrorType) { sil @throwing_func : $@convention(thin) (@owned X) -> (@owned X, @error ErrorType) {
@@ -631,9 +633,10 @@ bb0(%0 : $X):
bb1: bb1:
%2 = alloc_existential_box $ErrorType, $MyError %2 = alloc_existential_box $ErrorType, $MyError
%3 = struct $MyError () %3 = project_existential_box $MyError in %2 : $ErrorType
store %3 to %2#1 : $*MyError %4 = struct $MyError ()
throw %2#0 : $ErrorType store %4 to %3 : $*MyError
throw %2 : $ErrorType
bb2: bb2:
return %0 : $X return %0 : $X
@@ -871,14 +874,16 @@ bb0(%0 : $X):
// CHECK-LABEL: CG of test_unknown_store // CHECK-LABEL: CG of test_unknown_store
// CHECK-NEXT: Arg %0 Esc: G, Succ: // CHECK-NEXT: Arg %0 Esc: G, Succ:
// CHECK-NEXT: Con %0.1 Esc: G, Succ: // CHECK-NEXT: Val %2 Esc: G, Succ: (%2.1)
// CHECK-NEXT: Con %2.1 Esc: G, Succ: %0
// CHECK-NEXT: End // CHECK-NEXT: End
sil @test_unknown_store : $@convention(thin) (@owned ErrorClass) -> () { sil @test_unknown_store : $@convention(thin) (@owned ErrorClass) -> () {
bb0(%0 : $ErrorClass): bb0(%0 : $ErrorClass):
%2 = alloc_existential_box $ErrorType, $ErrorClass %2 = alloc_existential_box $ErrorType, $ErrorClass
store %0 to %2#1 : $*ErrorClass %3 = project_existential_box $ErrorClass in %2 : $ErrorType
%4 = tuple () store %0 to %3 : $*ErrorClass
return %4 : $() %5 = tuple ()
return %5 : $()
} }
// CHECK-LABEL: CG of test_raw_pointer_to_ref // CHECK-LABEL: CG of test_raw_pointer_to_ref

View File

@@ -2595,13 +2595,14 @@ bb0(%0 : $Int32):
bb1: // Preds: bb0 bb1: // Preds: bb0
%6 = alloc_existential_box $ErrorType, $VendingMachineError // users: %8, %9, %13 %6 = alloc_existential_box $ErrorType, $VendingMachineError // users: %8, %9, %13
%6a = project_existential_box $VendingMachineError in %6 : $ErrorType
%7 = enum $VendingMachineError, #VendingMachineError.OutOfStock!enumelt // user: %8 %7 = enum $VendingMachineError, #VendingMachineError.OutOfStock!enumelt // user: %8
store %7 to %6#1 : $*VendingMachineError // id: %8 store %7 to %6a : $*VendingMachineError // id: %8
debug_value %6#0 : $ErrorType, let, name "error" // id: %9 debug_value %6 : $ErrorType, let, name "error" // id: %9
%10 = float_literal $Builtin.FPIEEE80, 0x3FFF8000000000000000 // 1 // user: %11 %10 = float_literal $Builtin.FPIEEE80, 0x3FFF8000000000000000 // 1 // user: %11
%11 = builtin "fptrunc_FPIEEE80_FPIEEE64"(%10 : $Builtin.FPIEEE80) : $Builtin.FPIEEE64 // user: %12 %11 = builtin "fptrunc_FPIEEE80_FPIEEE64"(%10 : $Builtin.FPIEEE80) : $Builtin.FPIEEE64 // user: %12
%12 = struct $Double (%11 : $Builtin.FPIEEE64) // user: %14 %12 = struct $Double (%11 : $Builtin.FPIEEE64) // user: %14
strong_release %6#0 : $ErrorType // id: %13 strong_release %6 : $ErrorType // id: %13
br bb3(%12 : $Double) // id: %14 br bb3(%12 : $Double) // id: %14
bb2: // Preds: bb0 bb2: // Preds: bb0

View File

@@ -1111,18 +1111,16 @@ sil [fragile] @existential_box : $@convention(thin) (SomeError) -> () {
bb0(%0 : $SomeError): bb0(%0 : $SomeError):
// CHECK: %1 = alloc_existential_box $ErrorType, $SomeError // CHECK: %1 = alloc_existential_box $ErrorType, $SomeError
%1 = alloc_existential_box $ErrorType, $SomeError %1 = alloc_existential_box $ErrorType, $SomeError
// CHECK: store %0 to %1#1 : $*SomeError // CHECK: %2 = project_existential_box $SomeError in %1 : $ErrorType
store %0 to %1#1 : $*SomeError %2 = project_existential_box $SomeError in %1 : $ErrorType
// CHECK: %3 = project_existential_box $SomeError in %1#0 : $ErrorType // CHECK: store %0 to %2 : $*SomeError
%3 = project_existential_box $SomeError in %1#0 : $ErrorType store %0 to %2 : $*SomeError
// CHECK: store %0 to %3 : $*SomeError // CHECK: %4 = open_existential_box %1 : $ErrorType to $*[[OPENED:@opened\(".*"\)]] ErrorType
store %0 to %3 : $*SomeError %4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
// CHECK: %5 = open_existential_box %1#0 : $ErrorType to $*[[OPENED:@opened\(".*"\)]] ErrorType // CHECK: destroy_addr %4 : $*[[OPENED]] ErrorType
%5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
// CHECK: destroy_addr %5 : $*[[OPENED]] ErrorType // CHECK: dealloc_existential_box %1 : $ErrorType, $SomeError
destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType dealloc_existential_box %1 : $ErrorType, $SomeError
// CHECK: dealloc_existential_box %1#0 : $ErrorType, $SomeError
dealloc_existential_box %1#0 : $ErrorType, $SomeError
return undef : $() return undef : $()
} }