Skip to content

Commit e22908f

Browse files
committed
IRGen: Peephole (copy_addr to [initialization] (init_existential_addr)) as well.
We can simultaneously allocate and initialize an opaque existential container's fixed-size buffer the same way, which benefits conversions from generic types to protocol types. Swift SVN r29371
1 parent f003bc7 commit e22908f

File tree

3 files changed

+69
-37
lines changed

3 files changed

+69
-37
lines changed

lib/IRGen/GenProto.cpp

+3-34
Original file line numberDiff line numberDiff line change
@@ -4995,7 +4995,8 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF,
49954995
}
49964996

49974997
/// Emit an existential container initialization operation for a concrete type.
4998-
/// Returns the address of the uninitialized buffer for the concrete value.
4998+
/// Returns the address of the uninitialized fixed-size buffer for the concrete
4999+
/// value.
49995000
Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF,
50005001
Address dest,
50015002
SILType destType,
@@ -5005,26 +5006,13 @@ Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF,
50055006
assert(!destType.isClassExistentialType() &&
50065007
"initializing a class existential container as opaque");
50075008
auto &destTI = IGF.getTypeInfo(destType).as<OpaqueExistentialTypeInfo>();
5008-
auto &srcTI = IGF.getTypeInfo(loweredSrcType);
50095009
OpaqueExistentialLayout destLayout = destTI.getLayout();
50105010
assert(destTI.getStoredProtocols().size() == conformances.size());
50115011

50125012
// First, write out the metadata.
50135013
llvm::Value *metadata = IGF.emitTypeMetadataRef(formalSrcType);
50145014
IGF.Builder.CreateStore(metadata, destLayout.projectMetadataRef(IGF, dest));
50155015

5016-
// Compute basic layout information about the type. If we have a
5017-
// concrete type, we need to know how it packs into a fixed-size
5018-
// buffer. If we don't, we need a value witness table.
5019-
FixedPacking packing;
5020-
bool needValueWitnessToAllocate;
5021-
if (!isa<FixedTypeInfo>(srcTI)) {
5022-
packing = (FixedPacking) -1;
5023-
needValueWitnessToAllocate = true;
5024-
} else {
5025-
packing = srcTI.getFixedPacking(IGF.IGM);
5026-
needValueWitnessToAllocate = false;
5027-
}
50285016

50295017
// Next, write the protocol witness tables.
50305018
forEachProtocolWitnessTable(IGF, formalSrcType, destType.getSwiftRValueType(),
@@ -5037,26 +5025,7 @@ Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF,
50375025
// Finally, evaluate into the buffer.
50385026

50395027
// Project down to the destination fixed-size buffer.
5040-
Address buffer = destLayout.projectExistentialBuffer(IGF, dest);
5041-
5042-
// If the type is provably empty, we're done.
5043-
if (srcTI.isKnownEmpty()) {
5044-
assert(packing == FixedPacking::OffsetZero);
5045-
return buffer;
5046-
}
5047-
5048-
// Otherwise, allocate if necessary.
5049-
5050-
if (needValueWitnessToAllocate) {
5051-
// If we're using a witness-table to do this, we need to emit a
5052-
// value-witness call to allocate the fixed-size buffer.
5053-
return Address(emitAllocateBufferCall(IGF, loweredSrcType, buffer),
5054-
Alignment(1));
5055-
} else {
5056-
// Otherwise, allocate using what we know statically about the type.
5057-
return emitAllocateBuffer(IGF, loweredSrcType,
5058-
srcTI, packing, buffer);
5059-
}
5028+
return destLayout.projectExistentialBuffer(IGF, dest);
50605029
}
50615030

50625031
/// Emit an existential metatype container from a metatype value

lib/IRGen/IRGenSIL.cpp

+52-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "GenHeap.h"
5050
#include "GenMeta.h"
5151
#include "GenObjC.h"
52+
#include "GenOpaque.h"
5253
#include "GenPoly.h"
5354
#include "GenProto.h"
5455
#include "GenStruct.h"
@@ -3219,6 +3220,7 @@ static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF,
32193220
const TypeInfo &ti,
32203221
SILValue containerValue,
32213222
SILValue addressValue,
3223+
Address fixedSizeBuffer,
32223224
const llvm::Twine &name) {
32233225
// There's no point in doing this for fixed-sized types, since we'll allocate
32243226
// an appropriately-sized buffer for them statically.
@@ -3254,7 +3256,8 @@ static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF,
32543256

32553257
// We can defer to this initialization. Allocate the fixed-size buffer
32563258
// now, but don't allocate the value inside it.
3257-
auto fixedSizeBuffer = IGF.createFixedSizeBufferAlloca(name);
3259+
if (!fixedSizeBuffer.getAddress())
3260+
fixedSizeBuffer = IGF.createFixedSizeBufferAlloca(name);
32583261
if (containerValue)
32593262
IGF.setLoweredAddress(containerValue, fixedSizeBuffer);
32603263
IGF.setLoweredUnallocatedAddressInBuffer(addressValue, fixedSizeBuffer);
@@ -3307,6 +3310,7 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
33073310
if (tryDeferFixedSizeBufferInitialization(*this, i, type,
33083311
i->getContainerResult(),
33093312
i->getAddressResult(),
3313+
Address(),
33103314
dbgname))
33113315
return;
33123316

@@ -4076,7 +4080,52 @@ void IRGenSILFunction::visitInitExistentialAddrInst(swift::InitExistentialAddrIn
40764080
i->getFormalConcreteType(),
40774081
i->getLoweredConcreteType(),
40784082
i->getConformances());
4079-
setLoweredAddress(SILValue(i, 0), buffer);
4083+
4084+
auto &srcTI = getTypeInfo(i->getLoweredConcreteType());
4085+
4086+
// See if we can defer initialization of the buffer to a copy_addr into it.
4087+
if (tryDeferFixedSizeBufferInitialization(*this, i, srcTI, SILValue(), i,
4088+
buffer, ""))
4089+
return;
4090+
4091+
// Compute basic layout information about the type. If we have a
4092+
// concrete type, we need to know how it packs into a fixed-size
4093+
// buffer. If we don't, we need a value witness table.
4094+
4095+
4096+
FixedPacking packing;
4097+
bool needValueWitnessToAllocate;
4098+
if (!isa<FixedTypeInfo>(srcTI)) {
4099+
packing = (FixedPacking) -1;
4100+
needValueWitnessToAllocate = true;
4101+
} else {
4102+
packing = srcTI.getFixedPacking(IGM);
4103+
needValueWitnessToAllocate = false;
4104+
}
4105+
4106+
// Project down to the destination fixed-size buffer.
4107+
Address address = [&]{
4108+
// If the type is provably empty, we're done.
4109+
if (srcTI.isKnownEmpty()) {
4110+
assert(packing == FixedPacking::OffsetZero);
4111+
return buffer;
4112+
}
4113+
4114+
// Otherwise, allocate if necessary.
4115+
4116+
if (needValueWitnessToAllocate) {
4117+
// If we're using a witness-table to do this, we need to emit a
4118+
// value-witness call to allocate the fixed-size buffer.
4119+
return Address(emitAllocateBufferCall(*this, i->getLoweredConcreteType(),
4120+
buffer),
4121+
Alignment(1));
4122+
} else {
4123+
// Otherwise, allocate using what we know statically about the type.
4124+
return emitAllocateBuffer(*this, i->getLoweredConcreteType(), buffer);
4125+
}
4126+
}();
4127+
4128+
setLoweredAddress(SILValue(i, 0), address);
40804129
}
40814130

40824131
void IRGenSILFunction::visitInitExistentialMetatypeInst(
@@ -4297,7 +4346,7 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
42974346
Address addr = addrTI.initializeBufferWithTake(*this, dest, src, addrTy);
42984347
setAllocatedAddressForBuffer(i->getDest(), addr);
42994348
} else
4300-
addrTI.initializeWithTake(*this, dest, src, addrTy);
4349+
addrTI.initializeWithTake(*this, dest, src, addrTy);
43014350
break;
43024351
default:
43034352
llvm_unreachable("unexpected take/initialize attribute combination?!");

test/IRGen/fixed_size_buffer_peepholes.sil

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ entry(%x : $*T):
1919
return undef : $()
2020
}
2121

22+
protocol P {}
23+
24+
// CHECK-LABEL: define void @join_init_existential_copy_addr(%P27fixed_size_buffer_peepholes1P_* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T, i8** %T.P)
25+
// CHECK: [[BUFFER:%.*]] = getelementptr inbounds %P27fixed_size_buffer_peepholes1P_, %P27fixed_size_buffer_peepholes1P_* %0, i32 0, i32 0
26+
// CHECK: call %swift.opaque* %initializeBufferWithTake([[BUFFER_TYPE]]* [[BUFFER]], %swift.opaque* %1
27+
sil @join_init_existential_copy_addr : $@convention(thin) <T: P> (@out P, @in T) -> () {
28+
entry(%p : $*P, %x: $*T):
29+
%y = init_existential_addr %p : $*P, $T
30+
copy_addr [take] %x to [initialization] %y : $*T
31+
return undef : $()
32+
}
33+
2234
// CHECK-LABEL: define void @dont_join_alloc_stack_copy_addr_if_intervening_use
2335
sil @dont_join_alloc_stack_copy_addr_if_intervening_use : $@convention(thin) <T> (@in T) -> () {
2436
entry(%x : $*T):
@@ -67,3 +79,5 @@ next:
6779
dealloc_stack %a#0 : $*@local_storage T
6880
return undef : $()
6981
}
82+
83+

0 commit comments

Comments
 (0)