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-value-name ::= '%' sil-identifier
|
||||
sil-value ::= sil-value-name ('#' [0-9]+)?
|
||||
sil-value ::= sil-value-name
|
||||
sil-value ::= 'undef'
|
||||
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
|
||||
argument that produces the value. SIL values may also refer to the keyword
|
||||
'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
|
||||
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
|
||||
// storing to its value buffer:
|
||||
%error1 = alloc_existential_box $ErrorType, $NSError
|
||||
%addr = project_existential_box $NSError in %error1 : $ErrorType
|
||||
strong_retain %nserror: $NSError
|
||||
store %nserror to %error1#1 : $NSError
|
||||
store %nserror to %addr : $NSError
|
||||
|
||||
// The fast path supported for NSError:
|
||||
strong_retain %nserror: $NSError
|
||||
@@ -3432,7 +3422,7 @@ alloc_existential_box
|
||||
// $P must be a protocol or protocol composition type with boxed
|
||||
// representation
|
||||
// $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
|
||||
|
||||
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
|
||||
fully initialized, ``dealloc_existential_box`` must be used. A fully
|
||||
initialized box can be ``retain``-ed and ``release``-d like any
|
||||
reference-counted type. The address ``%0#1`` is dependent on the lifetime of
|
||||
the owner reference ``%0#0``.
|
||||
reference-counted type. The ``project_existential_box`` instruction is used
|
||||
to retrieve the address of the value inside the container.
|
||||
|
||||
project_existential_box
|
||||
```````````````````````
|
||||
@@ -3456,6 +3446,7 @@ project_existential_box
|
||||
// %1 will be of type $*T
|
||||
|
||||
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
|
||||
which the box was allocated with ``alloc_existential_box``.
|
||||
|
||||
|
||||
@@ -260,11 +260,11 @@ public:
|
||||
|
||||
AllocExistentialBoxInst *
|
||||
createAllocExistentialBox(SILLocation Loc, SILType ExistentialType,
|
||||
CanType ConcreteType, SILType ConcreteLoweredType,
|
||||
CanType ConcreteType,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances) {
|
||||
return insert(AllocExistentialBoxInst::create(
|
||||
createSILDebugLocation(Loc), ExistentialType, ConcreteType,
|
||||
ConcreteLoweredType, Conformances, &F));
|
||||
Conformances, &F));
|
||||
}
|
||||
|
||||
ApplyInst *createApply(SILLocation Loc, SILValue Fn, SILType SubstFnTy,
|
||||
|
||||
@@ -457,7 +457,6 @@ SILCloner<ImplClass>::visitAllocExistentialBoxInst(
|
||||
getBuilder().createAllocExistentialBox(getOpLocation(Inst->getLoc()),
|
||||
getOpType(origExistentialType),
|
||||
getOpASTType(origFormalType),
|
||||
getOpType(Inst->getLoweredConcreteType()),
|
||||
conformances));
|
||||
}
|
||||
|
||||
|
||||
@@ -588,18 +588,17 @@ public:
|
||||
/// value is uninitialized.
|
||||
class AllocExistentialBoxInst : public AllocationInst {
|
||||
friend class SILBuilder;
|
||||
|
||||
CanType ConcreteType;
|
||||
ArrayRef<ProtocolConformanceRef> Conformances;
|
||||
|
||||
AllocExistentialBoxInst(SILDebugLocation *DebugLoc, SILType ExistentialType,
|
||||
CanType ConcreteType, SILType ConcreteLoweredType,
|
||||
CanType ConcreteType,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances,
|
||||
SILFunction *Parent);
|
||||
|
||||
static AllocExistentialBoxInst *
|
||||
create(SILDebugLocation *DebugLoc, SILType ExistentialType,
|
||||
CanType ConcreteType, SILType ConcreteLoweredType,
|
||||
CanType ConcreteType,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances, SILFunction *Parent);
|
||||
|
||||
public:
|
||||
@@ -611,17 +610,10 @@ public:
|
||||
return getType(0);
|
||||
}
|
||||
|
||||
SILType getLoweredConcreteType() const {
|
||||
return getType(1);
|
||||
}
|
||||
|
||||
ArrayRef<ProtocolConformanceRef> getConformances() const {
|
||||
return Conformances;
|
||||
}
|
||||
|
||||
SILValue getExistentialResult() const { return SILValue(this, 0); }
|
||||
SILValue getValueAddressResult() const { return SILValue(this, 1); }
|
||||
|
||||
ArrayRef<Operand> getAllOperands() const { 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
|
||||
/// value of a given type.
|
||||
Address irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
|
||||
Explosion &dest,
|
||||
OwnedAddress irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
|
||||
SILType destType,
|
||||
CanType formalSrcType,
|
||||
SILType loweredSrcType,
|
||||
ArrayRef<ProtocolConformanceRef> conformances) {
|
||||
// TODO: Non-ErrorType boxed existentials.
|
||||
assert(_isErrorType(destType));
|
||||
|
||||
auto &destTI = IGF.getTypeInfo(destType).as<ErrorExistentialTypeInfo>();
|
||||
auto &srcTI = IGF.getTypeInfo(loweredSrcType);
|
||||
|
||||
auto srcMetadata = IGF.emitTypeMetadataRef(formalSrcType);
|
||||
// Should only be one conformance, for the ErrorType protocol.
|
||||
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.
|
||||
auto box = IGF.Builder.CreateExtractValue(result, 0);
|
||||
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,
|
||||
srcTI.getStorageType()->getPointerTo());
|
||||
return srcTI.getAddressForPointer(addr);
|
||||
return OwnedAddress(srcTI.getAddressForPointer(addr), box);
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// value of a given type.
|
||||
Address emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
|
||||
Explosion &dest,
|
||||
OwnedAddress emitBoxedExistentialContainerAllocation(IRGenFunction &IGF,
|
||||
SILType destType,
|
||||
CanType formalSrcType,
|
||||
SILType loweredSrcType,
|
||||
ArrayRef<ProtocolConformanceRef> conformances);
|
||||
|
||||
/// "Deinitialize" an existential container whose contained value is allocated
|
||||
|
||||
@@ -4456,14 +4456,11 @@ void IRGenSILFunction::visitInitBlockStorageHeaderInst(
|
||||
}
|
||||
|
||||
void IRGenSILFunction::visitAllocExistentialBoxInst(AllocExistentialBoxInst *i){
|
||||
Explosion box;
|
||||
auto projectionAddr =
|
||||
emitBoxedExistentialContainerAllocation(*this, box, i->getExistentialType(),
|
||||
OwnedAddress boxWithAddr =
|
||||
emitBoxedExistentialContainerAllocation(*this, i->getExistentialType(),
|
||||
i->getFormalConcreteType(),
|
||||
i->getLoweredConcreteType(),
|
||||
i->getConformances());
|
||||
setLoweredExplosion(i->getExistentialResult(), box);
|
||||
setLoweredAddress(i->getValueAddressResult(), projectionAddr);
|
||||
setLoweredBox(i, boxWithAddr);
|
||||
}
|
||||
|
||||
void IRGenSILFunction::visitDeallocExistentialBoxInst(
|
||||
@@ -4485,11 +4482,18 @@ void IRGenSILFunction::visitOpenExistentialBoxInst(OpenExistentialBoxInst *i) {
|
||||
|
||||
void
|
||||
IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) {
|
||||
Explosion box = getLoweredExplosion(i->getOperand());
|
||||
auto caddr = emitBoxedExistentialProjection(*this, box,
|
||||
i->getOperand().getType(),
|
||||
i->getType().getSwiftRValueType());
|
||||
setLoweredAddress(i, caddr.getAddress());
|
||||
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());
|
||||
auto caddr = emitBoxedExistentialProjection(*this, box,
|
||||
i->getOperand().getType(),
|
||||
i->getType().getSwiftRValueType());
|
||||
setLoweredAddress(i, caddr.getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
void IRGenSILFunction::visitDynamicMethodInst(DynamicMethodInst *i) {
|
||||
|
||||
@@ -3301,22 +3301,13 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
|
||||
parseASTType(ConcreteFormalTy))
|
||||
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.
|
||||
ArrayRef<ProtocolConformanceRef> conformances
|
||||
= collectExistentialConformances(P, ConcreteFormalTy,
|
||||
ExistentialTy.getSwiftRValueType());
|
||||
|
||||
ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy,
|
||||
ConcreteFormalTy, LoweredTy, conformances);
|
||||
ConcreteFormalTy, conformances);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -127,23 +127,11 @@ VarDecl *DebugValueAddrInst::getDecl() const {
|
||||
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(
|
||||
SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType,
|
||||
SILType ConcreteLoweredType, ArrayRef<ProtocolConformanceRef> Conformances,
|
||||
SILFunction *Parent)
|
||||
ArrayRef<ProtocolConformanceRef> Conformances, SILFunction *Parent)
|
||||
: AllocationInst(ValueKind::AllocExistentialBoxInst, Loc,
|
||||
getAllocExistentialBoxType(ExistentialType,
|
||||
ConcreteLoweredType, *Parent)),
|
||||
ExistentialType.getObjectType()),
|
||||
ConcreteType(ConcreteType), Conformances(Conformances) {}
|
||||
|
||||
static void declareWitnessTable(SILModule &Mod,
|
||||
@@ -159,7 +147,7 @@ static void declareWitnessTable(SILModule &Mod,
|
||||
|
||||
AllocExistentialBoxInst *AllocExistentialBoxInst::create(
|
||||
SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType,
|
||||
SILType ConcreteLoweredType, ArrayRef<ProtocolConformanceRef> Conformances,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances,
|
||||
SILFunction *F) {
|
||||
SILModule &Mod = F->getModule();
|
||||
void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst),
|
||||
@@ -169,7 +157,6 @@ AllocExistentialBoxInst *AllocExistentialBoxInst::create(
|
||||
return ::new (Buffer) AllocExistentialBoxInst(Loc,
|
||||
ExistentialType,
|
||||
ConcreteType,
|
||||
ConcreteLoweredType,
|
||||
Conformances, F);
|
||||
}
|
||||
|
||||
|
||||
@@ -1126,9 +1126,18 @@ public:
|
||||
"project_existential_box result must be an address");
|
||||
|
||||
if (auto *AEBI = dyn_cast<AllocExistentialBoxInst>(PEBI->getOperand())) {
|
||||
require(AEBI->getLoweredConcreteType() == PEBI->getType(),
|
||||
"type of project_existential_box does not match with the formal "
|
||||
"type of alloc_existential_box");
|
||||
// The lowered type must be the properly-abstracted form of the AST type.
|
||||
SILType exType = AEBI->getExistentialType();
|
||||
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 "
|
||||
"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());
|
||||
}
|
||||
|
||||
|
||||
@@ -448,14 +448,13 @@ ManagedValue SILGenFunction::emitExistentialErasure(
|
||||
}
|
||||
case ExistentialRepresentation::Boxed: {
|
||||
// Allocate the existential.
|
||||
auto box = B.createAllocExistentialBox(loc,
|
||||
auto *existential = B.createAllocExistentialBox(loc,
|
||||
existentialTL.getLoweredType(),
|
||||
concreteFormalType,
|
||||
concreteTL.getLoweredType(),
|
||||
conformances);
|
||||
auto existential = box->getExistentialResult();
|
||||
auto valueAddr = box->getValueAddressResult();
|
||||
|
||||
auto *valueAddr = B.createProjectExistentialBox(loc,
|
||||
concreteTL.getLoweredType(),
|
||||
existential);
|
||||
// Initialize the concrete value in-place.
|
||||
InitializationPtr init(
|
||||
new ExistentialInitialization(existential, valueAddr, concreteFormalType,
|
||||
|
||||
@@ -887,13 +887,11 @@ AllocExistentialBoxInst *
|
||||
SILGenBuilder::createAllocExistentialBox(SILLocation Loc,
|
||||
SILType ExistentialType,
|
||||
CanType ConcreteType,
|
||||
SILType ConcreteLoweredType,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances) {
|
||||
for (auto conformance : Conformances)
|
||||
SGM.useConformance(conformance);
|
||||
|
||||
return SILBuilder::createAllocExistentialBox(Loc, ExistentialType,
|
||||
ConcreteType,
|
||||
ConcreteLoweredType,
|
||||
Conformances);
|
||||
}
|
||||
|
||||
@@ -254,7 +254,6 @@ public:
|
||||
AllocExistentialBoxInst *createAllocExistentialBox(SILLocation Loc,
|
||||
SILType ExistentialType,
|
||||
CanType ConcreteType,
|
||||
SILType ConcreteLoweredType,
|
||||
ArrayRef<ProtocolConformanceRef> Conformances);
|
||||
};
|
||||
|
||||
|
||||
@@ -45,14 +45,25 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
|
||||
|
||||
StoreInst *SingleStore = nullptr;
|
||||
StrongReleaseInst *SingleRelease = nullptr;
|
||||
ProjectExistentialBoxInst *SingleProjection = nullptr;
|
||||
|
||||
// For each user U of the alloc_existential_box...
|
||||
for (auto U : getNonDebugUses(*AEBI)) {
|
||||
// Record stores into the box.
|
||||
if (auto *SI = dyn_cast<StoreInst>(U->getUser())) {
|
||||
// If this is not the only store into the box then bail out.
|
||||
if (SingleStore) return nullptr;
|
||||
SingleStore = SI;
|
||||
|
||||
if (auto *PEBI = dyn_cast<ProjectExistentialBoxInst>(U->getUser())) {
|
||||
if (SingleProjection) return nullptr;
|
||||
SingleProjection = PEBI;
|
||||
for (auto AddrUse : getNonDebugUses(*PEBI)) {
|
||||
// Record stores into the box.
|
||||
if (auto *SI = dyn_cast<StoreInst>(AddrUse->getUser())) {
|
||||
// If this is not the only store into the box then bail out.
|
||||
if (SingleStore) return nullptr;
|
||||
SingleStore = SI;
|
||||
continue;
|
||||
}
|
||||
// If there are other users to the box value address then bail out.
|
||||
return nullptr;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -69,6 +80,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
|
||||
}
|
||||
|
||||
if (SingleStore && SingleRelease) {
|
||||
assert(SingleProjection && "store without an projection");
|
||||
// Release the value that was stored into the existential box. The box
|
||||
// is going away so we need to release the stored value now.
|
||||
Builder.setInsertionPoint(SingleStore);
|
||||
@@ -78,6 +90,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
|
||||
// releases the box, and finally, release the box.
|
||||
eraseInstFromFunction(*SingleRelease);
|
||||
eraseInstFromFunction(*SingleStore);
|
||||
eraseInstFromFunction(*SingleProjection);
|
||||
return eraseInstFromFunction(*AEBI);
|
||||
}
|
||||
|
||||
|
||||
@@ -870,7 +870,6 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
|
||||
break;
|
||||
case ValueKind::AllocExistentialBoxInst:
|
||||
ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy,
|
||||
SILType::getPrimitiveAddressType(ConcreteTy),
|
||||
ctxConformances);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@ entry(%x : $*T):
|
||||
// CHECK: [[BOX:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 0
|
||||
// CHECK: [[ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1
|
||||
%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)
|
||||
copy_addr [take] %x to [initialization] %b#1 : $*T
|
||||
copy_addr [take] %x to [initialization] %p : $*T
|
||||
// CHECK: ret %swift.error* [[BOX]]
|
||||
return %b#0 : $ErrorType
|
||||
return %b : $ErrorType
|
||||
}
|
||||
|
||||
struct SomeError: ErrorType {
|
||||
@@ -40,9 +41,10 @@ entry(%x : $SomeError):
|
||||
// CHECK: [[OPAQUE_ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1
|
||||
// CHECK: [[ADDR:%.*]] = bitcast %swift.opaque* [[OPAQUE_ADDR]] to %V17boxed_existential9SomeError*
|
||||
%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]]
|
||||
return %b#0 : $ErrorType
|
||||
return %b : $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):
|
||||
// CHECK: %1 = alloc_existential_box $ErrorType, $SomeError
|
||||
%1 = alloc_existential_box $ErrorType, $SomeError
|
||||
// CHECK: store %0 to %1#1 : $*SomeError
|
||||
store %0 to %1#1 : $*SomeError
|
||||
// CHECK: %3 = project_existential_box $SomeError in %1#0 : $ErrorType
|
||||
%3 = project_existential_box $SomeError in %1#0 : $ErrorType
|
||||
// CHECK: store %0 to %3 : $*SomeError
|
||||
store %0 to %3 : $*SomeError
|
||||
// CHECK: %5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
%5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: dealloc_existential_box %1#0 : $ErrorType, $SomeError
|
||||
dealloc_existential_box %1#0 : $ErrorType, $SomeError
|
||||
// CHECK: %2 = project_existential_box $SomeError in %1 : $ErrorType
|
||||
%2 = project_existential_box $SomeError in %1 : $ErrorType
|
||||
// CHECK: store %0 to %2 : $*SomeError
|
||||
store %0 to %2 : $*SomeError
|
||||
// CHECK: %4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
%4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: dealloc_existential_box %1 : $ErrorType, $SomeError
|
||||
dealloc_existential_box %1 : $ErrorType, $SomeError
|
||||
return undef : $()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ func test_concrete_erasure(x: ClericalError) -> ErrorType {
|
||||
}
|
||||
// CHECK-LABEL: sil hidden @_TF18boxed_existentials21test_concrete_erasureFOS_13ClericalErrorPs9ErrorType_
|
||||
// CHECK: [[EXISTENTIAL:%.*]] = alloc_existential_box $ErrorType, $ClericalError
|
||||
// CHECK: store %0 to [[EXISTENTIAL]]#1 : $*ClericalError
|
||||
// CHECK: return [[EXISTENTIAL]]#0 : $ErrorType
|
||||
// CHECK: [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $ErrorType
|
||||
// CHECK: store %0 to [[ADDR]] : $*ClericalError
|
||||
// CHECK: return [[EXISTENTIAL]] : $ErrorType
|
||||
|
||||
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: [[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: 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: return [[NEW_EXISTENTIAL]]#0
|
||||
// CHECK: return [[NEW_EXISTENTIAL]]
|
||||
|
||||
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: [[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: store [[VALUE]] to [[NEW_EXISTENTIAL]]#1
|
||||
// CHECK: return [[NEW_EXISTENTIAL]]#0
|
||||
// CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $ErrorType
|
||||
// CHECK: store [[VALUE]] to [[ADDR]]
|
||||
// CHECK: return [[NEW_EXISTENTIAL]]
|
||||
|
||||
func test_property(x: ErrorType) -> String {
|
||||
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: [[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: [[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: throw [[BOX]]#0
|
||||
// CHECK-NEXT: throw [[BOX]]
|
||||
func dont_make_a_cat() throws -> Cat {
|
||||
throw HomeworkError.TooHard
|
||||
}
|
||||
|
||||
// CHECK: sil hidden @_TF6errors11dont_return{{.*}} : $@convention(thin) <T> (@out T, @in T) -> @error ErrorType {
|
||||
// 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: [[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: destroy_addr %1 : $*T
|
||||
// CHECK-NEXT: throw [[BOX]]#0
|
||||
// CHECK-NEXT: throw [[BOX]]
|
||||
func dont_return<T>(argument: T) throws -> T {
|
||||
throw HomeworkError.TooMuch
|
||||
}
|
||||
|
||||
@@ -100,15 +100,16 @@ func errorHandler(e: ErrorType) throws -> ErrorType {
|
||||
// CHECK: debug_value %0 : $ErrorType
|
||||
// CHECK: [[OPEN:%.*]] = open_existential_box %0 : $ErrorType to $*[[OPEN_TYPE:@opened\(.*\) ErrorType]]
|
||||
// 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: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[RESULT]]#1, [[OPEN]])
|
||||
// CHECK: try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
|
||||
//
|
||||
// CHECK: bb1
|
||||
// CHECK: strong_release %0 : $ErrorType
|
||||
// CHECK: return [[RESULT]]#0 : $ErrorType
|
||||
// CHECK: return [[RESULT]] : $ErrorType
|
||||
//
|
||||
// CHECK: bb2([[FAILURE:%.*]] : $ErrorType):
|
||||
// CHECK: dealloc_existential_box [[RESULT]]#0
|
||||
// CHECK: dealloc_existential_box [[RESULT]]
|
||||
// CHECK: strong_release %0 : $ErrorType
|
||||
// CHECK: throw [[FAILURE]] : $ErrorType
|
||||
//
|
||||
|
||||
@@ -8,10 +8,11 @@ throw MyError.A
|
||||
|
||||
// CHECK: sil @main
|
||||
// CHECK: [[ERR:%.*]] = alloc_existential_box $ErrorType, $MyError
|
||||
// CHECK: [[ADDR:%.*]] = project_existential_box $MyError in [[ERR]] : $ErrorType
|
||||
// CHECK: [[T0:%.*]] = enum $MyError, #MyError.A!enumelt
|
||||
// CHECK: store [[T0]] to [[ERR]]#1 : $*MyError
|
||||
// CHECK: builtin "willThrow"([[ERR]]#0 : $ErrorType)
|
||||
// CHECK: br bb2([[ERR]]#0 : $ErrorType)
|
||||
// CHECK: store [[T0]] to [[ADDR]] : $*MyError
|
||||
// CHECK: builtin "willThrow"([[ERR]] : $ErrorType)
|
||||
// CHECK: br bb2([[ERR]] : $ErrorType)
|
||||
|
||||
// CHECK: bb1([[T0:%.*]] : $Int32):
|
||||
// CHECK: return [[T0]] : $Int32
|
||||
|
||||
@@ -623,7 +623,9 @@ bb2(%5 : $ErrorType):
|
||||
|
||||
// CHECK-LABEL: CG of throwing_func
|
||||
// CHECK-NEXT: Arg %0 Esc: A, Succ:
|
||||
// CHECK-NEXT: Ret Esc: R, Succ: %0
|
||||
// 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: End
|
||||
sil @throwing_func : $@convention(thin) (@owned X) -> (@owned X, @error ErrorType) {
|
||||
bb0(%0 : $X):
|
||||
@@ -631,9 +633,10 @@ bb0(%0 : $X):
|
||||
|
||||
bb1:
|
||||
%2 = alloc_existential_box $ErrorType, $MyError
|
||||
%3 = struct $MyError ()
|
||||
store %3 to %2#1 : $*MyError
|
||||
throw %2#0 : $ErrorType
|
||||
%3 = project_existential_box $MyError in %2 : $ErrorType
|
||||
%4 = struct $MyError ()
|
||||
store %4 to %3 : $*MyError
|
||||
throw %2 : $ErrorType
|
||||
|
||||
bb2:
|
||||
return %0 : $X
|
||||
@@ -871,14 +874,16 @@ bb0(%0 : $X):
|
||||
|
||||
// CHECK-LABEL: CG of test_unknown_store
|
||||
// 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
|
||||
sil @test_unknown_store : $@convention(thin) (@owned ErrorClass) -> () {
|
||||
bb0(%0 : $ErrorClass):
|
||||
%2 = alloc_existential_box $ErrorType, $ErrorClass
|
||||
store %0 to %2#1 : $*ErrorClass
|
||||
%4 = tuple ()
|
||||
return %4 : $()
|
||||
%3 = project_existential_box $ErrorClass in %2 : $ErrorType
|
||||
store %0 to %3 : $*ErrorClass
|
||||
%5 = tuple ()
|
||||
return %5 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: CG of test_raw_pointer_to_ref
|
||||
|
||||
@@ -2595,13 +2595,14 @@ bb0(%0 : $Int32):
|
||||
|
||||
bb1: // Preds: bb0
|
||||
%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
|
||||
store %7 to %6#1 : $*VendingMachineError // id: %8
|
||||
debug_value %6#0 : $ErrorType, let, name "error" // id: %9
|
||||
store %7 to %6a : $*VendingMachineError // id: %8
|
||||
debug_value %6 : $ErrorType, let, name "error" // id: %9
|
||||
%10 = float_literal $Builtin.FPIEEE80, 0x3FFF8000000000000000 // 1 // user: %11
|
||||
%11 = builtin "fptrunc_FPIEEE80_FPIEEE64"(%10 : $Builtin.FPIEEE80) : $Builtin.FPIEEE64 // user: %12
|
||||
%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
|
||||
|
||||
bb2: // Preds: bb0
|
||||
|
||||
@@ -1111,18 +1111,16 @@ sil [fragile] @existential_box : $@convention(thin) (SomeError) -> () {
|
||||
bb0(%0 : $SomeError):
|
||||
// CHECK: %1 = alloc_existential_box $ErrorType, $SomeError
|
||||
%1 = alloc_existential_box $ErrorType, $SomeError
|
||||
// CHECK: store %0 to %1#1 : $*SomeError
|
||||
store %0 to %1#1 : $*SomeError
|
||||
// CHECK: %3 = project_existential_box $SomeError in %1#0 : $ErrorType
|
||||
%3 = project_existential_box $SomeError in %1#0 : $ErrorType
|
||||
// CHECK: store %0 to %3 : $*SomeError
|
||||
store %0 to %3 : $*SomeError
|
||||
// CHECK: %5 = open_existential_box %1#0 : $ErrorType to $*[[OPENED:@opened\(".*"\)]] ErrorType
|
||||
%5 = open_existential_box %1#0 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: destroy_addr %5 : $*[[OPENED]] ErrorType
|
||||
destroy_addr %5 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: dealloc_existential_box %1#0 : $ErrorType, $SomeError
|
||||
dealloc_existential_box %1#0 : $ErrorType, $SomeError
|
||||
// CHECK: %2 = project_existential_box $SomeError in %1 : $ErrorType
|
||||
%2 = project_existential_box $SomeError in %1 : $ErrorType
|
||||
// CHECK: store %0 to %2 : $*SomeError
|
||||
store %0 to %2 : $*SomeError
|
||||
// CHECK: %4 = open_existential_box %1 : $ErrorType to $*[[OPENED:@opened\(".*"\)]] ErrorType
|
||||
%4 = open_existential_box %1 : $ErrorType to $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: destroy_addr %4 : $*[[OPENED]] ErrorType
|
||||
destroy_addr %4 : $*@opened("01234567-89AB-CDEF-0123-333333333333") ErrorType
|
||||
// CHECK: dealloc_existential_box %1 : $ErrorType, $SomeError
|
||||
dealloc_existential_box %1 : $ErrorType, $SomeError
|
||||
return undef : $()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user