Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ set(SWIFT_BENCH_MODULES
single-source/SortLargeExistentials
single-source/SortLettersInPlace
single-source/SortStrings
single-source/StackPromo
single-source/StaticArray
single-source/StrComplexWalk
single-source/StrToInt
Expand Down
65 changes: 0 additions & 65 deletions benchmark/single-source/StackPromo.swift

This file was deleted.

2 changes: 0 additions & 2 deletions benchmark/utils/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ import SortIntPyramids
import SortLargeExistentials
import SortLettersInPlace
import SortStrings
import StackPromo
import StaticArray
import StrComplexWalk
import StrToInt
Expand Down Expand Up @@ -388,7 +387,6 @@ register(SortIntPyramids.benchmarks)
register(SortLargeExistentials.benchmarks)
register(SortLettersInPlace.benchmarks)
register(SortStrings.benchmarks)
register(StackPromo.benchmarks)
register(StaticArray.benchmarks)
register(StrComplexWalk.benchmarks)
register(StrToInt.benchmarks)
Expand Down
14 changes: 8 additions & 6 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7058,7 +7058,7 @@ RValue SILGenFunction::emitLiteral(LiteralExpr *literal, SGFContext C) {
/// Allocate an uninitialized array of a given size, returning the array
/// and a pointer to its uninitialized contents, which must be initialized
/// before the array is valid.
std::pair<ManagedValue, SILValue>
ManagedValue
SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc) {
Expand All @@ -7075,11 +7075,13 @@ SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy,
SmallVector<ManagedValue, 2> resultElts;
std::move(result).getAll(resultElts);

// Add a mark_dependence between the interior pointer and the array value
auto dependentValue = B.createMarkDependence(Loc, resultElts[1].getValue(),
resultElts[0].getValue(),
MarkDependenceKind::Escaping);
return {resultElts[0], dependentValue};
// The second result, which is the base element address, is not used. We extract
// it from the array (= the first result) directly to create a correct borrow scope.
// TODO: Consider adding a new intrinsic which only returns the array.
// Although the current intrinsic is inlined and the code for returning the
// second result is optimized away. So it doesn't make a performance difference.

return resultElts[0];
}

/// Deallocate an uninitialized array.
Expand Down
46 changes: 34 additions & 12 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2664,6 +2664,29 @@ RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
}

static SILValue getArrayBuffer(SILValue array, SILGenFunction &SGF, SILLocation loc) {
SILValue v = array;
SILType storageType;
while (auto *sd = v->getType().getStructOrBoundGenericStruct()) {
ASSERT(sd->getStoredProperties().size() == 1 &&
"Array or its internal structs should have exactly one stored property");
auto *se = SGF.getBuilder().createStructExtract(loc, v, v->getType().getFieldDecl(0));
if (se->getType() == SILType::getBridgeObjectType(SGF.getASTContext())) {
auto bridgeObjTy = cast<BoundGenericStructType>(v->getType().getASTType());
CanType ct = CanType(bridgeObjTy->getGenericArgs()[0]);
storageType = SILType::getPrimitiveObjectType(ct);
}
v = se;
}

if (storageType) {
v = SGF.getBuilder().createUncheckedRefCast(loc, v, storageType);
}
ASSERT(v->getType().isReferenceCounted(&SGF.F) &&
"expected a reference-counted buffer in the Array data type");
return v;
}

VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
CanType baseTy, CanType arrayTy,
unsigned numElements) {
Expand All @@ -2675,12 +2698,7 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
SILValue numEltsVal = SGF.B.createIntegerLiteral(loc,
SILType::getBuiltinWordType(SGF.getASTContext()),
numElements);
// The first result is the array value.
ManagedValue array;
// The second result is a RawPointer to the base address of the array.
SILValue basePtr;
std::tie(array, basePtr)
= SGF.emitUninitializedArrayAllocation(arrayTy, numEltsVal, loc);
ManagedValue array = SGF.emitUninitializedArrayAllocation(arrayTy, numEltsVal, loc);

// Temporarily deactivate the main array cleanup.
if (array.hasCleanup())
Expand All @@ -2690,13 +2708,15 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
auto abortCleanup =
SGF.enterDeallocateUninitializedArrayCleanup(array.getValue());

// Turn the pointer into an address.
basePtr = SGF.B.createPointerToAddress(
loc, basePtr, baseTL.getLoweredType().getAddressType(),
/*isStrict*/ true,
/*isInvariant*/ false);
auto borrowedArray = array.borrow(SGF, loc);
auto borrowCleanup = SGF.Cleanups.getTopCleanup();

SILValue buffer = getArrayBuffer(borrowedArray.getValue(), SGF, loc);

return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction);
SILType elementAddrTy = baseTL.getLoweredType().getAddressType();
SILValue baseAddr = SGF.getBuilder().createRefTailAddr(loc, buffer, elementAddrTy);

return VarargsInfo(array, borrowCleanup, abortCleanup, baseAddr, baseTL, baseAbstraction);
}

ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc,
Expand All @@ -2710,6 +2730,8 @@ ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc,
if (array.hasCleanup())
SGF.Cleanups.setCleanupState(array.getCleanup(), CleanupState::Active);

SGF.Cleanups.popAndEmitCleanup(varargs.getBorrowCleanup(), CleanupLocation(loc), NotForUnwind);

// Array literals only need to be finalized, if the array is really allocated.
// In case of zero elements, no allocation is done, but the empty-array
// singleton is used. "Finalization" means to emit an end_cow_mutation
Expand Down
9 changes: 4 additions & 5 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1899,11 +1899,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
ManagedValue emitUndef(Type type);
ManagedValue emitUndef(SILType type);
RValue emitUndefRValue(SILLocation loc, Type type);

std::pair<ManagedValue, SILValue>
emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc);

ManagedValue emitUninitializedArrayAllocation(Type ArrayTy,
SILValue Length,
SILLocation Loc);

CleanupHandle enterDeallocateUninitializedArrayCleanup(SILValue array);
void emitUninitializedArrayDeallocation(SILLocation loc, SILValue array);
Expand Down
8 changes: 6 additions & 2 deletions lib/SILGen/Varargs.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,26 @@ class TypeLowering;
/// Information about a varargs emission.
class VarargsInfo {
ManagedValue Array;
CleanupHandle borrowCleanup;
CleanupHandle AbortCleanup;
SILValue BaseAddress;
AbstractionPattern BasePattern;
const TypeLowering &BaseTL;
public:
VarargsInfo(ManagedValue array, CleanupHandle abortCleanup,
VarargsInfo(ManagedValue array, CleanupHandle borrowCleanup, CleanupHandle abortCleanup,
SILValue baseAddress, const TypeLowering &baseTL,
AbstractionPattern basePattern)
: Array(array), AbortCleanup(abortCleanup),
: Array(array), borrowCleanup(borrowCleanup), AbortCleanup(abortCleanup),
BaseAddress(baseAddress), BasePattern(basePattern), BaseTL(baseTL) {}

/// Return the array value. emitEndVarargs() is really the only
/// function that should be accessing this directly.
ManagedValue getArray() const {
return Array;
}

CleanupHandle getBorrowCleanup() const { return borrowCleanup; }

CleanupHandle getAbortCleanup() const { return AbortCleanup; }

/// An address of the lowered type.
Expand Down
51 changes: 40 additions & 11 deletions lib/SILOptimizer/Analysis/ArraySemantic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "swift/Basic/Assertions.h"
#include "swift/SIL/DebugUtils.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/NodeDatastructures.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
Expand Down Expand Up @@ -732,14 +733,10 @@ SILValue swift::ArraySemanticsCall::getArrayElementStoragePointer() const {
return getArrayUninitializedInitResult(*this, 1);
}

bool swift::ArraySemanticsCall::mapInitializationStores(
llvm::DenseMap<uint64_t, StoreInst *> &ElementValueMap) {
if (getKind() != ArrayCallKind::kArrayUninitialized &&
getKind() != ArrayCallKind::kArrayUninitializedIntrinsic)
return false;
SILValue ElementBuffer = getArrayElementStoragePointer();
static SILValue getElementBaseAddress(ArraySemanticsCall initArray) {
SILValue ElementBuffer = initArray.getArrayElementStoragePointer();
if (!ElementBuffer)
return false;
return SILValue();

// Match initialization stores into ElementBuffer. E.g.
// %82 = struct_extract %element_buffer : $UnsafeMutablePointer<Int>
Expand All @@ -756,9 +753,29 @@ bool swift::ArraySemanticsCall::mapInitializationStores(
// mark_dependence can be an operand of the struct_extract or its user.

SILValue UnsafeMutablePointerExtract;
if (getKind() == ArrayCallKind::kArrayUninitializedIntrinsic) {
if (initArray.getKind() == ArrayCallKind::kArrayUninitializedIntrinsic) {
UnsafeMutablePointerExtract = dyn_cast_or_null<MarkDependenceInst>(
getSingleNonDebugUser(ElementBuffer));
if (!UnsafeMutablePointerExtract) {
SILValue array = initArray.getArrayValue();
ValueWorklist worklist(array);
while (SILValue v = worklist.pop()) {
for (auto use : v->getUses()) {
switch (use->getUser()->getKind()) {
case SILInstructionKind::UncheckedRefCastInst:
case SILInstructionKind::StructExtractInst:
case SILInstructionKind::BeginBorrowInst:
worklist.pushIfNotVisited(cast<SingleValueInstruction>(use->getUser()));
break;
case SILInstructionKind::RefTailAddrInst:
return cast<RefTailAddrInst>(use->getUser());
default:
break;
}
}
}
return SILValue();
}
} else {
auto user = getSingleNonDebugUser(ElementBuffer);
// Match mark_dependence (struct_extract or
Expand All @@ -774,21 +791,33 @@ bool swift::ArraySemanticsCall::mapInitializationStores(
}
}
if (!UnsafeMutablePointerExtract)
return false;
return SILValue();

auto *PointerToAddress = dyn_cast_or_null<PointerToAddressInst>(
getSingleNonDebugUser(UnsafeMutablePointerExtract));
if (!PointerToAddress)
return SILValue();
return PointerToAddress;
}

bool swift::ArraySemanticsCall::mapInitializationStores(
llvm::DenseMap<uint64_t, StoreInst *> &ElementValueMap) {
if (getKind() != ArrayCallKind::kArrayUninitialized &&
getKind() != ArrayCallKind::kArrayUninitializedIntrinsic)
return false;

SILValue elementAddr = getElementBaseAddress(*this);
if (!elementAddr)
return false;

// Match the stores. We can have either a store directly to the address or
// to an index_addr projection.
for (auto *Op : PointerToAddress->getUses()) {
for (auto *Op : elementAddr->getUses()) {
auto *Inst = Op->getUser();

// Store to the base.
auto *SI = dyn_cast<StoreInst>(Inst);
if (SI && SI->getDest() == PointerToAddress) {
if (SI && SI->getDest() == elementAddr) {
// We have already seen an entry for this index bail.
if (ElementValueMap.count(0))
return false;
Expand Down
Loading