mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
23
docs/SIL.rst
23
docs/SIL.rst
@@ -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``.
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {}; }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 : $()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 : $()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user