[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-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``.

View File

@@ -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,

View File

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

View File

@@ -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 {}; }

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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());
}

View File

@@ -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,

View File

@@ -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);
}

View File

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

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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 : $()
}

View File

@@ -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

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: [[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
}

View File

@@ -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
//

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 : $()
}