Skip to content

Commit

Permalink
[SIL] Let alloc_stack return a single value.
Browse files Browse the repository at this point in the history
Having a separate address and container value returned from alloc_stack is not really needed in SIL.
Even if they differ we have both addresses available during IRGen, because a dealloc_stack is always dominated by the corresponding alloc_stack in the same function.

Although this commit quite large, most changes are trivial. The largest non-trivial change is in IRGenSIL.

This commit is a NFC regarding the generated code. Even the generated SIL is the same (except removed #0, #1 and @local_storage).
  • Loading branch information
eeckstein committed Jan 7, 2016
1 parent 5f80471 commit 6ff2f09
Show file tree
Hide file tree
Showing 188 changed files with 2,851 additions and 2,889 deletions.
38 changes: 12 additions & 26 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -386,22 +386,6 @@ type. Values of address type thus cannot be allocated, loaded, or stored
Addresses can be passed as arguments to functions if the corresponding
parameter is indirect. They cannot be returned.

Local Storage Types
```````````````````

The *address of local storage for T* ``$*@local_storage T`` is a
handle to a stack allocation of a variable of type ``$T``.

For many types, the handle for a stack allocation is simply the
allocated address itself. However, if a type is runtime-sized, the
compiler must emit code to potentially dynamically allocate memory.
SIL abstracts over such differences by using values of local-storage
type as the first result of ``alloc_stack`` and the operand of
``dealloc_stack``.

Local-storage address types are not *first-class* in the same sense
that address types are not first-class.

Box Types
`````````

Expand Down Expand Up @@ -1634,13 +1618,15 @@ alloc_stack
sil-instruction ::= 'alloc_stack' sil-type (',' debug-var-attr)*

%1 = alloc_stack $T
// %1#0 has type $*@local_storage T
// %1#1 has type $*T
// %1 has type $*T

Allocates uninitialized memory that is sufficiently aligned on the stack
to contain a value of type ``T``. The first result of the instruction
is a local-storage handle suitable for passing to ``dealloc_stack``.
The second result of the instruction is the address of the allocated memory.
to contain a value of type ``T``. The result of the instruction is the address
of the allocated memory.

If a type is runtime-sized, the compiler must emit code to potentially
dynamically allocate memory. So there is no guarantee that the allocated
memory is really located on the stack.

``alloc_stack`` marks the start of the lifetime of the value; the
allocation must be balanced with a ``dealloc_stack`` instruction to
Expand Down Expand Up @@ -1741,16 +1727,16 @@ dealloc_stack

sil-instruction ::= 'dealloc_stack' sil-operand

dealloc_stack %0 : $*@local_storage T
// %0 must be of a local-storage $*@local_storage T type
dealloc_stack %0 : $*T
// %0 must be of $*T type

Deallocates memory previously allocated by ``alloc_stack``. The
allocated value in memory must be uninitialized or destroyed prior to
being deallocated. This instruction marks the end of the lifetime for
the value created by the corresponding ``alloc_stack`` instruction. The operand
must be the ``@local_storage`` of the shallowest live ``alloc_stack``
allocation preceding the deallocation. In other words, deallocations must be
in last-in, first-out stack order.
must be the shallowest live ``alloc_stack`` allocation preceding the
deallocation. In other words, deallocations must be in last-in, first-out
stack order.

dealloc_box
```````````
Expand Down
10 changes: 5 additions & 5 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,15 +460,15 @@ class AllocStackInst : public AllocationInst {
};
void setArgNo(unsigned N) { VarInfo.setArgNo(N); }

/// getType() is ok since this is known to only have one type.
SILType getType(unsigned i = 0) const { return ValueBase::getType(i); }

/// getElementType - Get the type of the allocated memory (as opposed to the
/// (second) type of the instruction itself, which will be an address type).
/// type of the instruction itself, which will be an address type).
SILType getElementType() const {
return getType(1).getObjectType();
return getType().getObjectType();
}

SILValue getContainerResult() const { return SILValue(this, 0); }
SILValue getAddressResult() const { return SILValue(this, 1); }

ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }

Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 228; // no substitutions for value witnesses
const uint16_t VERSION_MINOR = 229; // alloc_stack returns a single value

using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;
Expand Down
105 changes: 59 additions & 46 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,15 @@ class LoweredValue {
public:
enum class Kind {
/// This LoweredValue corresponds to a SIL address value.
/// The LoweredValue of an alloc_stack keeps an owning container in
/// addition to the address of the allocated buffer.
/// Depending on the allocated type, the container may be equal to the
/// buffer itself (for types with known sizes) or it may be the address
/// of a fixed-size container which points to the heap-allocated buffer.
/// In this case the address-part may be null, which means that the buffer
/// is not allocated yet.
Address,

/// This LoweredValue corresponds to a SIL address value owned by an
/// uninitialized fixed-size buffer.
UnallocatedAddressInBuffer,

/// The following kinds correspond to SIL non-address values.
Value_First,
/// A normal value, represented as an exploded array of llvm Values.
Expand All @@ -151,7 +154,7 @@ class LoweredValue {
using ExplosionVector = SmallVector<llvm::Value *, 4>;

union {
Address address;
ContainedAddress address;
struct {
ExplosionVector values;
} explosion;
Expand All @@ -160,14 +163,24 @@ class LoweredValue {
};

public:

/// Create an address value without a container (the usual case).
LoweredValue(const Address &address)
: kind(Kind::Address), address(address)
: kind(Kind::Address), address(Address(), address)
{}

enum UnallocatedAddressInBuffer_t { UnallocatedAddressInBuffer };
enum ContainerForUnallocatedAddress_t { ContainerForUnallocatedAddress };

/// Create an address value for an alloc_stack, consisting of a container and
/// a not yet allocated buffer.
LoweredValue(const Address &container, ContainerForUnallocatedAddress_t)
: kind(Kind::Address), address(container, Address())
{}

LoweredValue(const Address &address, UnallocatedAddressInBuffer_t)
: kind(Kind::UnallocatedAddressInBuffer), address(address)
/// Create an address value for an alloc_stack, consisting of a container and
/// the address of the allocated buffer.
LoweredValue(const ContainedAddress &address)
: kind(Kind::Address), address(address)
{}

LoweredValue(StaticFunction &&staticFunction)
Expand All @@ -189,8 +202,7 @@ class LoweredValue {
{
switch (kind) {
case Kind::Address:
case Kind::UnallocatedAddressInBuffer:
::new (&address) Address(std::move(lv.address));
::new (&address) ContainedAddress(std::move(lv.address));
break;
case Kind::Explosion:
::new (&explosion.values) ExplosionVector(std::move(lv.explosion.values));
Expand All @@ -212,23 +224,24 @@ class LoweredValue {
}

bool isAddress() const {
return kind == Kind::Address;
return kind == Kind::Address && address.getAddress().isValid();
}
bool isUnallocatedAddressInBuffer() const {
return kind == Kind::UnallocatedAddressInBuffer;
return kind == Kind::Address && !address.getAddress().isValid();
}
bool isValue() const {
return kind >= Kind::Value_First && kind <= Kind::Value_Last;
}

Address getAddress() const {
assert(kind == Kind::Address && "not an allocated address");
return address;
assert(isAddress() && "not an allocated address");
return address.getAddress();
}

Address getAddressOfUnallocatedBuffer() const {
assert(kind == Kind::UnallocatedAddressInBuffer);
return address;
Address getContainerOfAddress() const {
assert(kind == Kind::Address);
assert(address.getContainer().isValid() && "address has no container");
return address.getContainer();
}

void getExplosion(IRGenFunction &IGF, Explosion &ex) const;
Expand All @@ -254,8 +267,7 @@ class LoweredValue {
~LoweredValue() {
switch (kind) {
case Kind::Address:
case Kind::UnallocatedAddressInBuffer:
address.~Address();
address.~ContainedAddress();
break;
case Kind::Explosion:
explosion.values.~ExplosionVector();
Expand Down Expand Up @@ -345,18 +357,28 @@ class IRGenSILFunction :
setLoweredValue(v, address);
}

void setLoweredUnallocatedAddressInBuffer(SILValue v,
const Address &buffer) {
void setLoweredContainedAddress(SILValue v, const ContainedAddress &address) {
assert((v.getType().isAddress() || v.getType().isLocalStorage()) &&
"address for non-address value?!");
setLoweredValue(v, address);
}

void setContainerOfUnallocatedAddress(SILValue v,
const Address &buffer) {
assert((v.getType().isAddress() || v.getType().isLocalStorage()) &&
"address for non-address value?!");
setLoweredValue(v,
LoweredValue(buffer, LoweredValue::UnallocatedAddressInBuffer));
LoweredValue(buffer, LoweredValue::ContainerForUnallocatedAddress));
}

void overwriteLoweredAddress(SILValue v, const Address &address) {
void overwriteAllocatedAddress(SILValue v, const Address &address) {
assert((v.getType().isAddress() || v.getType().isLocalStorage()) &&
"address for non-address value?!");
overwriteLoweredValue(v, address);
auto it = LoweredValues.find(v);
assert(it != LoweredValues.end() && "no existing entry for overwrite?");
assert(it->second.isUnallocatedAddressInBuffer() &&
"not an unallocated address");
it->second = ContainedAddress(it->second.getContainerOfAddress(), address);
}

void setAllocatedAddressForBuffer(SILValue v, const Address &allocedAddress);
Expand Down Expand Up @@ -466,6 +488,9 @@ class IRGenSILFunction :
Address getLoweredAddress(SILValue v) {
return getLoweredValue(v).getAddress();
}
Address getLoweredContainerOfAddress(SILValue v) {
return getLoweredValue(v).getContainerOfAddress();
}
/// Add the unmanaged LLVM values lowered from a SIL value to an explosion.
void getLoweredExplosion(SILValue v, Explosion &e) {
getLoweredValue(v).getExplosion(*this, e);
Expand Down Expand Up @@ -781,7 +806,6 @@ llvm::Value *StaticFunction::getExplosionValue(IRGenFunction &IGF) const {
void LoweredValue::getExplosion(IRGenFunction &IGF, Explosion &ex) const {
switch (kind) {
case Kind::Address:
case Kind::UnallocatedAddressInBuffer:
llvm_unreachable("not a value");

case Kind::Explosion:
Expand All @@ -802,7 +826,6 @@ void LoweredValue::getExplosion(IRGenFunction &IGF, Explosion &ex) const {
llvm::Value *LoweredValue::getSingletonExplosion(IRGenFunction &IGF) const {
switch (kind) {
case Kind::Address:
case Kind::UnallocatedAddressInBuffer:
llvm_unreachable("not a value");

case Kind::Explosion:
Expand Down Expand Up @@ -1849,7 +1872,6 @@ static CallEmission getCallEmissionForLoweredValue(IRGenSILFunction &IGF,
}

case LoweredValue::Kind::Address:
case LoweredValue::Kind::UnallocatedAddressInBuffer:
llvm_unreachable("sil address isn't a valid callee");
}

Expand Down Expand Up @@ -2015,7 +2037,6 @@ getPartialApplicationFunction(IRGenSILFunction &IGF,

switch (lv.kind) {
case LoweredValue::Kind::Address:
case LoweredValue::Kind::UnallocatedAddressInBuffer:
llvm_unreachable("can't partially apply an address");
case LoweredValue::Kind::ObjCMethod:
llvm_unreachable("objc method partial application shouldn't get here");
Expand Down Expand Up @@ -3255,7 +3276,6 @@ visitIsUniqueOrPinnedInst(swift::IsUniqueOrPinnedInst *i) {
static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF,
const SILInstruction *allocInst,
const TypeInfo &ti,
SILValue containerValue,
SILValue addressValue,
Address fixedSizeBuffer,
const llvm::Twine &name) {
Expand Down Expand Up @@ -3298,9 +3318,7 @@ static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF,
IGF.Builder.CreateLifetimeStart(fixedSizeBuffer,
getFixedBufferSize(IGF.IGM));
}
if (containerValue)
IGF.setLoweredAddress(containerValue, fixedSizeBuffer);
IGF.setLoweredUnallocatedAddressInBuffer(addressValue, fixedSizeBuffer);
IGF.setContainerOfUnallocatedAddress(addressValue, fixedSizeBuffer);
return true;
}

Expand Down Expand Up @@ -3345,8 +3363,7 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
// operation, we can combine the allocation and initialization using an
// optimized value witness.
if (tryDeferFixedSizeBufferInitialization(*this, i, type,
i->getContainerResult(),
i->getAddressResult(),
SILValue(i, 0),
Address(),
dbgname))
return;
Expand All @@ -3356,8 +3373,8 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
dbgname);

emitDebugInfoForAllocStack(i, type, addr.getAddress().getAddress());
setLoweredAddress(i->getContainerResult(), addr.getContainer());
setLoweredAddress(i->getAddressResult(), addr.getAddress());

setLoweredContainedAddress(i, addr);
}

void IRGenSILFunction::visitAllocRefInst(swift::AllocRefInst *i) {
Expand Down Expand Up @@ -3392,8 +3409,8 @@ void IRGenSILFunction::visitAllocRefDynamicInst(swift::AllocRefDynamicInst *i) {

void IRGenSILFunction::visitDeallocStackInst(swift::DeallocStackInst *i) {
const TypeInfo &type = getTypeInfo(i->getOperand().getType());
Address addr = getLoweredAddress(i->getOperand());
type.deallocateStack(*this, addr,
Address container = getLoweredContainerOfAddress(i->getOperand());
type.deallocateStack(*this, container,
i->getOperand().getType());
}

Expand Down Expand Up @@ -4204,8 +4221,7 @@ void IRGenSILFunction::visitInitExistentialAddrInst(swift::InitExistentialAddrIn
auto &srcTI = getTypeInfo(i->getLoweredConcreteType());

// See if we can defer initialization of the buffer to a copy_addr into it.
if (tryDeferFixedSizeBufferInitialization(*this, i, srcTI, SILValue(), i,
buffer, ""))
if (tryDeferFixedSizeBufferInitialization(*this, i, srcTI, i, buffer, ""))
return;

// Compute basic layout information about the type. If we have a
Expand Down Expand Up @@ -4414,11 +4430,8 @@ void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) {

void IRGenSILFunction::setAllocatedAddressForBuffer(SILValue v,
const Address &allocedAddress) {
assert(getLoweredValue(v).kind ==
LoweredValue::Kind::UnallocatedAddressInBuffer &&
"not an unallocated address");
overwriteAllocatedAddress(v, allocedAddress);

overwriteLoweredAddress(v, allocedAddress);
// Emit the debug info for the variable if any.
if (auto allocStack = dyn_cast<AllocStackInst>(v)) {
emitDebugInfoForAllocStack(allocStack, getTypeInfo(v.getType()),
Expand All @@ -4435,7 +4448,7 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
auto &loweredDest = getLoweredValue(i->getDest());
if (loweredDest.isUnallocatedAddressInBuffer()) {
isFixedBufferInitialization = true;
dest = loweredDest.getAddressOfUnallocatedBuffer();
dest = loweredDest.getContainerOfAddress();
} else {
isFixedBufferInitialization = false;
dest = loweredDest.getAddress();
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/DynamicCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ namespace {
if (!source.shouldTake()) {
sourceTemp = B.createAllocStack(Loc,
sourceAddr.getType().getObjectType());
sourceAddr = sourceTemp->getAddressResult();
sourceAddr = sourceTemp;
B.createCopyAddr(Loc, source.Value, sourceAddr, IsNotTake,
IsInitialization);
}
Expand All @@ -677,7 +677,7 @@ namespace {

// Deallocate the source temporary if we needed one.
if (sourceTemp) {
B.createDeallocStack(Loc, sourceTemp->getContainerResult());
B.createDeallocStack(Loc, sourceTemp);
}

Source result = emitSome(resultObject, target, state);
Expand Down
Loading

1 comment on commit 6ff2f09

@eeckstein
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjmccall can you please review my changes in IRGenSIL.cpp (and the whole commit if you like)?

Please sign in to comment.