Skip to content

Commit d005743

Browse files
authored
Merge pull request #70242 from meg-gupta/unrevertarrayfix
Unrevert #69450 - Add a mark_dependence while emitting SIL for uninitialized array allocation
2 parents b60ed0b + e685b24 commit d005743

27 files changed

+362
-217
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import SIL
4141
///
4242
let objectOutliner = FunctionPass(name: "object-outliner") {
4343
(function: Function, context: FunctionPassContext) in
44-
4544
for inst in function.instructions {
4645
if let ari = inst as? AllocRefInstBase {
4746
if let globalValue = optimizeObjectAllocation(allocRef: ari, context) {
@@ -155,7 +154,7 @@ private func findInitStores(of object: Value,
155154
return false
156155
}
157156
default:
158-
if !isValidUseOfObject(use.instruction) {
157+
if !isValidUseOfObject(use) {
159158
return false
160159
}
161160
}
@@ -182,6 +181,18 @@ private func findStores(toTailAddress tailAddr: Value, tailElementIndex: Int, st
182181
if !findStores(inUsesOf: tea, index: tailElementIndex * numTupleElements + tupleIdx, stores: &stores) {
183182
return false
184183
}
184+
case let atp as AddressToPointerInst:
185+
if !findStores(toTailAddress: atp, tailElementIndex: tailElementIndex, stores: &stores) {
186+
return false
187+
}
188+
case let mdi as MarkDependenceInst:
189+
if !findStores(toTailAddress: mdi, tailElementIndex: tailElementIndex, stores: &stores) {
190+
return false
191+
}
192+
case let pta as PointerToAddressInst:
193+
if !findStores(toTailAddress: pta, tailElementIndex: tailElementIndex, stores: &stores) {
194+
return false
195+
}
185196
case let store as StoreInst:
186197
if store.source.type.isTuple {
187198
// This kind of SIL is never generated because tuples are stored with separated stores to tuple_element_addr.
@@ -192,7 +203,7 @@ private func findStores(toTailAddress tailAddr: Value, tailElementIndex: Int, st
192203
return false
193204
}
194205
default:
195-
if !isValidUseOfObject(use.instruction) {
206+
if !isValidUseOfObject(use) {
196207
return false
197208
}
198209
}
@@ -206,7 +217,7 @@ private func findStores(inUsesOf address: Value, index: Int, stores: inout [Stor
206217
if !handleStore(store, index: index, stores: &stores) {
207218
return false
208219
}
209-
} else if !isValidUseOfObject(use.instruction) {
220+
} else if !isValidUseOfObject(use) {
210221
return false
211222
}
212223
}
@@ -223,7 +234,8 @@ private func handleStore(_ store: StoreInst, index: Int, stores: inout [StoreIns
223234
return false
224235
}
225236

226-
private func isValidUseOfObject(_ inst: Instruction) -> Bool {
237+
private func isValidUseOfObject(_ use: Operand) -> Bool {
238+
let inst = use.instruction
227239
switch inst {
228240
case is DebugValueInst,
229241
is LoadInst,
@@ -235,6 +247,17 @@ private func isValidUseOfObject(_ inst: Instruction) -> Bool {
235247
is EndCOWMutationInst:
236248
return true
237249

250+
case let mdi as MarkDependenceInst:
251+
if (use == mdi.baseOperand) {
252+
return true;
253+
}
254+
for mdiUse in mdi.uses {
255+
if !isValidUseOfObject(mdiUse) {
256+
return false
257+
}
258+
}
259+
return true
260+
238261
case is StructElementAddrInst,
239262
is AddressToPointerInst,
240263
is StructInst,
@@ -246,9 +269,12 @@ private func isValidUseOfObject(_ inst: Instruction) -> Bool {
246269
is UpcastInst,
247270
is BeginDeallocRefInst,
248271
is RefTailAddrInst,
249-
is RefElementAddrInst:
250-
for use in (inst as! SingleValueInstruction).uses {
251-
if !isValidUseOfObject(use.instruction) {
272+
is RefElementAddrInst,
273+
is StructInst,
274+
is PointerToAddressInst,
275+
is IndexAddrInst:
276+
for instUse in (inst as! SingleValueInstruction).uses {
277+
if !isValidUseOfObject(instUse) {
252278
return false
253279
}
254280
}

lib/SILGen/SILGenApply.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6316,7 +6316,10 @@ SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy,
63166316
SmallVector<ManagedValue, 2> resultElts;
63176317
std::move(result).getAll(resultElts);
63186318

6319-
return {resultElts[0], resultElts[1].getUnmanagedValue()};
6319+
// Add a mark_dependence between the interior pointer and the array value
6320+
auto dependentValue = B.createMarkDependence(Loc, resultElts[1].getValue(),
6321+
resultElts[0].getValue());
6322+
return {resultElts[0], dependentValue};
63206323
}
63216324

63226325
/// Deallocate an uninitialized array.

lib/SILOptimizer/Analysis/ArraySemantic.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,8 @@ bool swift::ArraySemanticsCall::mapInitializationStores(
841841
return false;
842842

843843
// Match initialization stores into ElementBuffer. E.g.
844-
// %83 = struct_extract %element_buffer : $UnsafeMutablePointer<Int>
844+
// %82 = struct_extract %element_buffer : $UnsafeMutablePointer<Int>
845+
// %83 = mark_dependence %82 : $Builtin.RawPointer on ArrayVal
845846
// %84 = pointer_to_address %83 : $Builtin.RawPointer to strict $*Int
846847
// store %85 to %84 : $*Int
847848
// %87 = integer_literal $Builtin.Word, 1
@@ -850,12 +851,27 @@ bool swift::ArraySemanticsCall::mapInitializationStores(
850851

851852
// If this an ArrayUninitializedIntrinsic then the ElementBuffer is a
852853
// builtin.RawPointer. Otherwise, it is an UnsafeMutablePointer, which would
853-
// be struct-extracted to obtain a builtin.RawPointer.
854-
SILValue UnsafeMutablePointerExtract =
855-
(getKind() == ArrayCallKind::kArrayUninitialized)
856-
? dyn_cast_or_null<StructExtractInst>(
857-
getSingleNonDebugUser(ElementBuffer))
858-
: ElementBuffer;
854+
// be struct-extracted to obtain a builtin.RawPointer. In this case
855+
// mark_dependence can be an operand of the struct_extract or its user.
856+
857+
SILValue UnsafeMutablePointerExtract;
858+
if (getKind() == ArrayCallKind::kArrayUninitializedIntrinsic) {
859+
UnsafeMutablePointerExtract = dyn_cast_or_null<MarkDependenceInst>(
860+
getSingleNonDebugUser(ElementBuffer));
861+
} else {
862+
auto user = getSingleNonDebugUser(ElementBuffer);
863+
// Match mark_dependence (struct_extract or
864+
// struct_extract (mark_dependence
865+
if (auto *MDI = dyn_cast_or_null<MarkDependenceInst>(user)) {
866+
UnsafeMutablePointerExtract =
867+
dyn_cast_or_null<StructExtractInst>(getSingleNonDebugUser(MDI));
868+
} else {
869+
if (auto *SEI = dyn_cast_or_null<StructExtractInst>(user)) {
870+
UnsafeMutablePointerExtract =
871+
dyn_cast_or_null<MarkDependenceInst>(getSingleNonDebugUser(SEI));
872+
}
873+
}
874+
}
859875
if (!UnsafeMutablePointerExtract)
860876
return false;
861877

lib/SILOptimizer/Analysis/DifferentiableActivityAnalysis.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -429,12 +429,15 @@ void DifferentiableActivityInfo::setUsefulThroughArrayInitialization(
429429
continue;
430430
// The second tuple field of the return value is the `RawPointer`.
431431
for (auto use : dti->getResult(1)->getUses()) {
432-
// The `RawPointer` passes through a `pointer_to_address`. That
433-
// instruction's first use is a `store` whose source is useful; its
432+
// The `RawPointer` passes through a `mark_dependence(pointer_to_address`.
433+
// That instruction's first use is a `store` whose source is useful; its
434434
// subsequent uses are `index_addr`s whose only use is a useful `store`.
435-
auto *ptai = dyn_cast<PointerToAddressInst>(use->getUser());
436-
assert(ptai && "Expected `pointer_to_address` user for uninitialized "
437-
"array intrinsic");
435+
auto *mdi = dyn_cast<MarkDependenceInst>(use->getUser());
436+
assert(
437+
mdi &&
438+
"Expected a mark_dependence user for uninitialized array intrinsic.");
439+
auto *ptai = dyn_cast<PointerToAddressInst>(getSingleNonDebugUser(mdi));
440+
assert(ptai && "Expected a pointer_to_address.");
438441
setUseful(ptai, dependentVariableIndex);
439442
// Propagate usefulness through array element addresses:
440443
// `pointer_to_address` and `index_addr` instructions.

lib/SILOptimizer/Differentiation/Common.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,30 +37,18 @@ ApplyInst *getAllocateUninitializedArrayIntrinsicElementAddress(SILValue v) {
3737
ptai = dyn_cast<PointerToAddressInst>(iai->getOperand(0));
3838
if (!ptai)
3939
return nullptr;
40+
auto *mdi = dyn_cast<MarkDependenceInst>(
41+
ptai->getOperand()->getDefiningInstruction());
42+
if (!mdi)
43+
return nullptr;
4044
// Return the `array.uninitialized_intrinsic` application, if it exists.
4145
if (auto *dti = dyn_cast<DestructureTupleInst>(
42-
ptai->getOperand()->getDefiningInstruction()))
46+
mdi->getValue()->getDefiningInstruction()))
4347
return ArraySemanticsCall(dti->getOperand(),
4448
semantics::ARRAY_UNINITIALIZED_INTRINSIC);
4549
return nullptr;
4650
}
4751

48-
DestructureTupleInst *getSingleDestructureTupleUser(SILValue value) {
49-
bool foundDestructureTupleUser = false;
50-
if (!value->getType().is<TupleType>())
51-
return nullptr;
52-
DestructureTupleInst *result = nullptr;
53-
for (auto *use : value->getUses()) {
54-
if (auto *dti = dyn_cast<DestructureTupleInst>(use->getUser())) {
55-
assert(!foundDestructureTupleUser &&
56-
"There should only be one `destructure_tuple` user of a tuple");
57-
foundDestructureTupleUser = true;
58-
result = dti;
59-
}
60-
}
61-
return result;
62-
}
63-
6452
bool isSemanticMemberAccessor(SILFunction *original) {
6553
auto *dc = original->getDeclContext();
6654
if (!dc)
@@ -109,7 +97,7 @@ void forEachApplyDirectResult(
10997
resultCallback(ai);
11098
return;
11199
}
112-
if (auto *dti = getSingleDestructureTupleUser(ai))
100+
if (auto *dti = ai->getSingleUserOfType<DestructureTupleInst>())
113101
for (auto directResult : dti->getResults())
114102
resultCallback(directResult);
115103
break;

lib/SILOptimizer/Differentiation/JVPCloner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,8 @@ class JVPCloner::Implementation final
13121312
if (!origResult->getType().is<TupleType>()) {
13131313
setTangentValue(bb, origResult,
13141314
makeConcreteTangentValue(differentialResult));
1315-
} else if (auto *dti = getSingleDestructureTupleUser(ai)) {
1315+
} else if (auto *dti =
1316+
ai->getSingleUserOfType<DestructureTupleInst>()) {
13161317
bool notSetValue = true;
13171318
for (auto result : dti->getResults()) {
13181319
if (activityInfo.isActive(result, getConfig())) {

lib/SILOptimizer/Differentiation/PullbackCloner.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3331,7 +3331,11 @@ void PullbackCloner::Implementation::
33313331
builder.setCurrentDebugScope(remapScope(dti->getDebugScope()));
33323332
builder.setInsertionPoint(arrayAdjoint->getParentBlock());
33333333
for (auto use : dti->getResult(1)->getUses()) {
3334-
auto *ptai = dyn_cast<PointerToAddressInst>(use->getUser());
3334+
auto *mdi = dyn_cast<MarkDependenceInst>(use->getUser());
3335+
assert(mdi && "Expected mark_dependence user");
3336+
auto *ptai =
3337+
dyn_cast_or_null<PointerToAddressInst>(getSingleNonDebugUser(mdi));
3338+
assert(ptai && "Expected pointer_to_address user");
33353339
auto adjBuf = getAdjointBuffer(origBB, ptai);
33363340
auto *eltAdjBuf = getArrayAdjointElementBuffer(arrayAdjoint, 0, loc);
33373341
builder.emitInPlaceAdd(loc, adjBuf, eltAdjBuf);

lib/SILOptimizer/LoopTransforms/ForEachLoopUnroll.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,11 @@ void ArrayInfo::classifyUsesOfArray(SILValue arrayValue) {
302302
// above as the array would be passed indirectly.
303303
if (isFixLifetimeUseOfArray(user, arrayValue))
304304
continue;
305+
if (auto *MDI = dyn_cast<MarkDependenceInst>(user)) {
306+
if (MDI->getBase() == arrayValue) {
307+
continue;
308+
}
309+
}
305310
// Check if this is a forEach call on the array.
306311
if (TryApplyInst *forEachCall = isForEachUseOfArray(user, arrayValue)) {
307312
forEachCalls.insert(forEachCall);

lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ bool ArrayAllocation::recursivelyCollectUses(ValueBase *Def) {
127127
isa<DebugValueInst>(User))
128128
continue;
129129

130+
if (auto *MDI = dyn_cast<MarkDependenceInst>(User)) {
131+
if (Def == MDI->getBase()) {
132+
continue;
133+
}
134+
}
135+
130136
// Array value projection.
131137
if (auto *SEI = dyn_cast<StructExtractInst>(User)) {
132138
if (!recursivelyCollectUses(SEI))

lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ bool ArrayAllocation::replacementsAreValid() {
122122
/// Recursively look at all uses of this definition. Abort if the array value
123123
/// could escape or be changed. Collect all uses that are calls to array.count.
124124
bool ArrayAllocation::recursivelyCollectUses(ValueBase *Def) {
125+
LLVM_DEBUG(llvm::dbgs() << "Collecting uses of:");
126+
LLVM_DEBUG(Def->dump());
127+
125128
for (auto *Opd : Def->getUses()) {
126129
auto *User = Opd->getUser();
127130
// Ignore reference counting and debug instructions.
@@ -148,6 +151,12 @@ bool ArrayAllocation::recursivelyCollectUses(ValueBase *Def) {
148151
continue;
149152
}
150153

154+
if (auto *MDI = dyn_cast<MarkDependenceInst>(User)) {
155+
if (Def != MDI->getBase())
156+
return false;
157+
continue;
158+
}
159+
151160
// Check array semantic calls.
152161
ArraySemanticsCall ArrayOp(User);
153162
switch (ArrayOp.getKind()) {
@@ -181,17 +190,28 @@ bool ArrayAllocation::analyze(ApplyInst *Alloc) {
181190
if (!Uninitialized)
182191
return false;
183192

193+
LLVM_DEBUG(llvm::dbgs() << "Found array allocation: ");
194+
LLVM_DEBUG(Alloc->dump());
195+
184196
ArrayValue = Uninitialized.getArrayValue();
185-
if (!ArrayValue)
197+
if (!ArrayValue) {
198+
LLVM_DEBUG(llvm::dbgs() << "Did not find array value\n");
186199
return false;
200+
}
187201

202+
LLVM_DEBUG(llvm::dbgs() << "ArrayValue: ");
203+
LLVM_DEBUG(ArrayValue->dump());
188204
// Figure out all stores to the array.
189-
if (!mapInitializationStores(Uninitialized))
205+
if (!mapInitializationStores(Uninitialized)) {
206+
LLVM_DEBUG(llvm::dbgs() << "Could not map initializing stores\n");
190207
return false;
208+
}
191209

192210
// Check if the array value was stored or has escaped.
193-
if (!recursivelyCollectUses(ArrayValue))
211+
if (!recursivelyCollectUses(ArrayValue)) {
212+
LLVM_DEBUG(llvm::dbgs() << "Array value stored or escaped\n");
194213
return false;
214+
}
195215

196216
return true;
197217
}
@@ -328,7 +348,9 @@ class ArrayElementPropagation : public SILFunctionTransform {
328348
auto &Fn = *getFunction();
329349
bool Changed = false;
330350

331-
for (auto &BB :Fn) {
351+
LLVM_DEBUG(llvm::dbgs() << "ArrayElementPropagation looking at function: "
352+
<< Fn.getName() << "\n");
353+
for (auto &BB : Fn) {
332354
for (auto &Inst : BB) {
333355
if (auto *Apply = dyn_cast<ApplyInst>(&Inst)) {
334356
ArrayAllocation ALit;

lib/SILOptimizer/Transforms/DeadObjectElimination.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,13 @@ recursivelyCollectInteriorUses(ValueBase *DefInst,
616616
AllUsers.insert(User);
617617
continue;
618618
}
619+
if (auto *MDI = dyn_cast<MarkDependenceInst>(User)) {
620+
if (!recursivelyCollectInteriorUses(MDI, AddressNode,
621+
IsInteriorAddress)) {
622+
return false;
623+
}
624+
continue;
625+
}
619626
if (auto PTAI = dyn_cast<PointerToAddressInst>(User)) {
620627
// Only one pointer-to-address is allowed for safety.
621628
if (SeenPtrToAddr)
@@ -1163,11 +1170,17 @@ bool DeadObjectElimination::processAllocApply(ApplyInst *AI,
11631170

11641171
LLVM_DEBUG(llvm::dbgs() << " Success! Eliminating apply allocate(...).\n");
11651172

1173+
auto *ARI = dyn_cast<AllocRefInst>(AI->getArgument(0));
1174+
11661175
deleter.forceDeleteWithUsers(AI);
11671176
for (auto *toDelete : instsDeadAfterInitializerRemoved) {
11681177
deleter.trackIfDead(toDelete);
11691178
}
11701179

1180+
if (ARI) {
1181+
deleter.forceDeleteWithUsers(ARI);
1182+
}
1183+
11711184
++DeadAllocApplyEliminated;
11721185
return true;
11731186
}

lib/SILOptimizer/Utils/ConstExpr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
528528
if (auto *convertEscapeInst = dyn_cast<ConvertEscapeToNoEscapeInst>(value))
529529
return getConstantValue(convertEscapeInst->getOperand());
530530

531+
if (auto *mdi = dyn_cast<MarkDependenceInst>(value))
532+
return getConstantValue(mdi->getValue());
533+
531534
LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown simple: " << *value << "\n");
532535

533536
// Otherwise, we don't know how to handle this.

0 commit comments

Comments
 (0)