Skip to content

Commit 680c737

Browse files
Merge pull request #64789 from nate-chandler/more-move-values
[SILGen] Used move_value for more lexical values.
2 parents e8828f3 + 72ff0ae commit 680c737

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+430
-280
lines changed

include/swift/SIL/InstWrappers.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,12 @@ class ForwardingOperation {
257257
// ForwardingInstruction.swift mirrors this implementation.
258258
Operand *getSingleForwardingOperand() const {
259259
switch (forwardingInst->getKind()) {
260-
case SILInstructionKind::StructInst:
261260
case SILInstructionKind::TupleInst:
261+
case SILInstructionKind::StructInst: {
262+
if (forwardingInst->getNumRealOperands() != 1)
263+
return nullptr;
264+
return *forwardingInst->getRealOperands().begin();
265+
}
262266
case SILInstructionKind::LinearFunctionInst:
263267
case SILInstructionKind::DifferentiableFunctionInst:
264268
return nullptr;

include/swift/SIL/SILBuilder.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -841,11 +841,14 @@ class SILBuilder {
841841
return createLoadBorrow(loc, v);
842842
}
843843

844-
SILValue emitBeginBorrowOperation(SILLocation loc, SILValue v) {
844+
SILValue emitBeginBorrowOperation(SILLocation loc, SILValue v,
845+
bool isLexical = false,
846+
bool hasPointerEscape = false,
847+
bool fromVarDecl = false) {
845848
if (!hasOwnership() ||
846849
v->getOwnershipKind().isCompatibleWith(OwnershipKind::Guaranteed))
847850
return v;
848-
return createBeginBorrow(loc, v);
851+
return createBeginBorrow(loc, v, isLexical, hasPointerEscape, fromVarDecl);
849852
}
850853

851854
void emitEndBorrowOperation(SILLocation loc, SILValue v) {
@@ -2834,13 +2837,16 @@ class SILBuilder {
28342837

28352838
/// Convenience function that is a no-op for trivial values and inserts a
28362839
/// move_value on non-trivial instructions.
2837-
SILValue emitMoveValueOperation(SILLocation Loc, SILValue v) {
2840+
SILValue emitMoveValueOperation(SILLocation Loc, SILValue v,
2841+
bool isLexical = false,
2842+
bool hasPointerEscape = false,
2843+
bool fromVarDecl = false) {
28382844
assert(!v->getType().isAddress());
28392845
if (v->getType().isTrivial(*getInsertionBB()->getParent()))
28402846
return v;
28412847
assert(v->getOwnershipKind() == OwnershipKind::Owned &&
28422848
"move_value consumes its argument");
2843-
return createMoveValue(Loc, v);
2849+
return createMoveValue(Loc, v, isLexical, hasPointerEscape, fromVarDecl);
28442850
}
28452851

28462852
SILValue emitTupleExtract(SILLocation Loc, SILValue Operand, unsigned FieldNo,

include/swift/SIL/SILInstruction.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,16 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
613613
/// Return the array of mutable type dependent operands for this instruction.
614614
MutableArrayRef<Operand> getTypeDependentOperands();
615615

616+
private:
617+
struct FilterOperandToRealOperand;
618+
619+
public:
620+
using RealOperandRange =
621+
OptionalTransformRange<ArrayRef<Operand>, FilterOperandToRealOperand>;
622+
623+
/// The array of real (i.e. not type-dependent) operands.
624+
RealOperandRange getRealOperands() const;
625+
616626
unsigned getNumOperands() const { return getAllOperands().size(); }
617627

618628
unsigned getNumTypeDependentOperands() const {
@@ -1006,6 +1016,18 @@ struct SILInstruction::OperandRefToValue {
10061016
}
10071017
};
10081018

1019+
struct SILInstruction::FilterOperandToRealOperand {
1020+
const SILInstruction &i;
1021+
1022+
FilterOperandToRealOperand(const SILInstruction &i) : i(i) {}
1023+
1024+
llvm::Optional<Operand *> operator()(const Operand &use) const {
1025+
if (i.isTypeDependentOperand(use))
1026+
return llvm::None;
1027+
return {const_cast<Operand *>(&use)};
1028+
}
1029+
};
1030+
10091031
struct SILInstruction::NonTypeDependentOperandToValue {
10101032
const SILInstruction &i;
10111033

@@ -1037,6 +1059,11 @@ struct SILInstruction::OperandToTransformedValue {
10371059
}
10381060
};
10391061

1062+
inline SILInstruction::RealOperandRange
1063+
SILInstruction::getRealOperands() const {
1064+
return RealOperandRange(getAllOperands(), FilterOperandToRealOperand(*this));
1065+
}
1066+
10401067
inline SILInstruction::OperandValueRange
10411068
SILInstruction::getOperandValues(ArrayRef<Operand*> operands) {
10421069
return OperandValueRange(operands, OperandToValue());

include/swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ class CanonicalizeOSSALifetime final {
414414
bool respectsDeinitBarriers() const {
415415
if (!currentDef->isLexical())
416416
return false;
417+
if (currentDef->getFunction()->forceEnableLexicalLifetimes())
418+
return true;
417419
auto &module = currentDef->getFunction()->getModule();
418420
return module.getASTContext().SILOpts.supportsLexicalLifetimes(module);
419421
}

lib/SILGen/SILGenDecl.cpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -832,25 +832,33 @@ class LetValueInitialization : public Initialization {
832832
ConsumableAndAssignable);
833833
}
834834

835-
// Otherwise, if we do not have a no implicit copy variable, just follow
836-
// the "normal path": perform a lexical borrow if the lifetime is lexical.
837-
if (!vd->isNoImplicitCopy()) {
838-
return SGF.B.createBeginBorrow(
835+
// If we have a no implicit copy lexical, emit the instruction stream so
836+
// that the move checker knows to check this variable.
837+
if (vd->isNoImplicitCopy()) {
838+
value = SGF.B.createMoveValue(PrologueLoc, value, /*isLexical*/ true,
839+
/*hasPointerEscape=*/false,
840+
/*fromVarDecl=*/true);
841+
value =
842+
SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(PrologueLoc, value);
843+
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
839844
PrologueLoc, value,
840-
/*isLexical=*/SGF.F.getLifetime(vd, value->getType()).isLexical(),
841-
/*hasPointerEscape=*/false, /*fromVarDecl=*/true);
845+
MarkUnresolvedNonCopyableValueInst::CheckKind::
846+
ConsumableAndAssignable);
842847
}
843848

844-
// If we have a no implicit copy lexical, emit the instruction stream so
845-
// that the move checker knows to check this variable.
846-
value = SGF.B.createBeginBorrow(
847-
PrologueLoc, value,
848-
/*isLexical*/ true, /*hasPointerEscape=*/false, /*fromVarDecl=*/true);
849-
value = SGF.B.createCopyValue(PrologueLoc, value);
850-
value = SGF.B.createOwnedCopyableToMoveOnlyWrapperValue(PrologueLoc, value);
851-
return SGF.B.createMarkUnresolvedNonCopyableValueInst(
852-
PrologueLoc, value,
853-
MarkUnresolvedNonCopyableValueInst::CheckKind::ConsumableAndAssignable);
849+
// Otherwise, if we do not have a no implicit copy variable, just follow
850+
// the "normal path".
851+
852+
auto isLexical = SGF.F.getLifetime(vd, value->getType()).isLexical();
853+
854+
if (value->getOwnershipKind() == OwnershipKind::Owned)
855+
return SGF.B.createMoveValue(PrologueLoc, value, /*isLexical*/ isLexical,
856+
/*hasPointerEscape=*/false,
857+
/*fromVarDecl=*/true);
858+
859+
return SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ isLexical,
860+
/*hasPointerEscape=*/false,
861+
/*fromVarDecl=*/true);
854862
}
855863

856864
void bindValue(SILValue value, SILGenFunction &SGF, bool wasPlusOne,
@@ -2176,6 +2184,11 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
21762184
return;
21772185
}
21782186

2187+
if (auto *mvi = dyn_cast<MoveValueInst>(Val.getDefiningInstruction())) {
2188+
B.emitDestroyValueOperation(silLoc, mvi);
2189+
return;
2190+
}
2191+
21792192
if (auto *mvi = dyn_cast<MarkUnresolvedNonCopyableValueInst>(
21802193
Val.getDefiningInstruction())) {
21812194
if (mvi->hasMoveCheckerKind()) {
@@ -2192,14 +2205,10 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
21922205

21932206
if (auto *copyToMove = dyn_cast<CopyableToMoveOnlyWrapperValueInst>(
21942207
mvi->getOperand())) {
2195-
if (auto *cvi = dyn_cast<CopyValueInst>(copyToMove->getOperand())) {
2196-
if (auto *bbi = dyn_cast<BeginBorrowInst>(cvi->getOperand())) {
2197-
if (bbi->isLexical()) {
2198-
B.emitDestroyValueOperation(silLoc, mvi);
2199-
B.createEndBorrow(silLoc, bbi);
2200-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
2201-
return;
2202-
}
2208+
if (auto *move = dyn_cast<MoveValueInst>(copyToMove->getOperand())) {
2209+
if (move->isLexical()) {
2210+
B.emitDestroyValueOperation(silLoc, mvi);
2211+
return;
22032212
}
22042213
}
22052214
}

lib/SILOptimizer/Differentiation/JVPCloner.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,9 @@ class JVPCloner::Implementation final
777777
auto &diffBuilder = getDifferentialBuilder();
778778
auto loc = bbi->getLoc();
779779
auto tanVal = materializeTangent(getTangentValue(bbi->getOperand()), loc);
780-
auto tanValBorrow = diffBuilder.emitBeginBorrowOperation(loc, tanVal);
780+
auto tanValBorrow = diffBuilder.emitBeginBorrowOperation(
781+
loc, tanVal, bbi->isLexical(), bbi->hasPointerEscape(),
782+
bbi->isFromVarDecl());
781783
setTangentValue(bbi->getParent(), bbi,
782784
makeConcreteTangentValue(tanValBorrow));
783785
}
@@ -805,6 +807,17 @@ class JVPCloner::Implementation final
805807
makeConcreteTangentValue(tanValCopy));
806808
}
807809

810+
CLONE_AND_EMIT_TANGENT(MoveValue, mvi) {
811+
auto &diffBuilder = getDifferentialBuilder();
812+
auto tan = getTangentValue(mvi->getOperand());
813+
auto tanVal = materializeTangent(tan, mvi->getLoc());
814+
auto tanValMove = diffBuilder.emitMoveValueOperation(
815+
mvi->getLoc(), tanVal, mvi->isLexical(), mvi->hasPointerEscape(),
816+
mvi->isFromVarDecl());
817+
setTangentValue(mvi->getParent(), mvi,
818+
makeConcreteTangentValue(tanValMove));
819+
}
820+
808821
/// Handle `load` instruction.
809822
/// Original: y = load x
810823
/// Tangent: tan[y] = load tan[x]

lib/SILOptimizer/LoopTransforms/ForEachLoopUnroll.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ void ArrayInfo::classifyUsesOfArray(SILValue arrayValue) {
312312
forEachCalls.insert(forEachCall);
313313
continue;
314314
}
315-
// Recursively classify begin_borrow and copy_value uses.
315+
// Recursively classify begin_borrow, copy_value, and move_value uses.
316316
if (BeginBorrowInst *beginBorrow = dyn_cast<BeginBorrowInst>(user)) {
317317
classifyUsesOfArray(beginBorrow);
318318
continue;
@@ -321,6 +321,10 @@ void ArrayInfo::classifyUsesOfArray(SILValue arrayValue) {
321321
classifyUsesOfArray(copyValue);
322322
continue;
323323
}
324+
if (MoveValueInst *moveValue = dyn_cast<MoveValueInst>(user)) {
325+
classifyUsesOfArray(moveValue);
326+
continue;
327+
}
324328
if (DestroyValueInst *destroyValue = dyn_cast<DestroyValueInst>(user)) {
325329
destroys.push_back(destroyValue);
326330
continue;

lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableValuesChecker.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,13 @@ bool ConsumeOperatorCopyableValuesChecker::check() {
409409

410410
for (auto &block : *fn) {
411411
for (auto &ii : block) {
412+
if (auto *mvi = dyn_cast<MoveValueInst>(&ii)) {
413+
if (mvi->isFromVarDecl() && !mvi->getType().isMoveOnly()) {
414+
LLVM_DEBUG(llvm::dbgs()
415+
<< "Found lexical lifetime to check: " << *mvi);
416+
valuesToCheck.insert(mvi);
417+
}
418+
}
412419
if (auto *bbi = dyn_cast<BeginBorrowInst>(&ii)) {
413420
if (bbi->isFromVarDecl() && !bbi->getType().isMoveOnly()) {
414421
LLVM_DEBUG(llvm::dbgs()

lib/SILOptimizer/Mandatory/OSLogOptimization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ static bool isSILValueFoldable(SILValue value) {
313313
return (!silType.isAddress() && !isa<LiteralInst>(definingInst) &&
314314
!isa<LoadBorrowInst>(definingInst) &&
315315
!isa<BeginBorrowInst>(definingInst) &&
316+
!isa<MoveValueInst>(definingInst) &&
316317
!isa<CopyValueInst>(definingInst) &&
317318
(isFoldableIntOrBool(value, astContext) ||
318319
isFoldableString(value, astContext) ||

lib/SILOptimizer/SemanticARC/RedundantMoveValueElimination.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ using namespace semanticarc;
3333
//===----------------------------------------------------------------------===//
3434

3535
bool SemanticARCOptVisitor::visitMoveValueInst(MoveValueInst *mvi) {
36-
if (ctx.onlyMandatoryOpts)
37-
return false;
38-
3936
if (!ctx.shouldPerform(ARCTransformKind::RedundantMoveValueElim))
4037
return false;
4138

lib/SILOptimizer/Transforms/CopyPropagation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ void CopyPropagation::run() {
503503
// Run the sequence of utilities:
504504
// - ShrinkBorrowScope
505505
// - CanonicalizeOSSALifetime
506-
// - LexicalDestroyFolder
506+
// - LexicalDestroyFolding
507507
// at least once and then until each stops making changes.
508508
while (true) {
509509
SmallVector<CopyValueInst *, 4> modifiedCopyValueInsts;

lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -978,9 +978,10 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
978978
auto *insertionPoint = &*successor->begin();
979979
insertDestroyBeforeInstruction(insertionPoint, getCurrentDef(),
980980
consumes, getCallbacks());
981-
LLVM_DEBUG(llvm::dbgs()
982-
<< " Destroy after terminator " << instruction
983-
<< " at beginning of " << successor << "\n");
981+
LLVM_DEBUG(llvm::dbgs() << " Destroy after terminator "
982+
<< *instruction << " at beginning of ";
983+
successor->printID(llvm::dbgs(), false);
984+
llvm::dbgs() << "\n";);
984985
}
985986
continue;
986987
}

stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ public func reflect<T: Error>(error: T) {
508508
let error: Error = error
509509
let errorPointerValue = unsafeBitCast(error, to: UInt.self)
510510
reflect(instanceAddress: errorPointerValue, kind: .ErrorExistential)
511+
withExtendedLifetime(error) {}
511512
}
512513

513514
// Like reflect<T: Error>(error: T), but calls projectExistentialAndUnwrapClass
@@ -523,6 +524,7 @@ public func reflectUnwrappingClassExistential<T: Error>(error: T) {
523524
kind: .ErrorExistential,
524525
shouldUnwrapClassExistential: true)
525526
anyPointer.deallocate()
527+
withExtendedLifetime(error) {}
526528
}
527529

528530
// Reflect an `Enum`

test/AutoDiff/SILGen/autodiff_builtins.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ func test_context_builtins_with_type<T>(t: T) {
9696

9797
// CHECK-LABEL: sil{{.*}}@test_context_builtins_with_type : $@convention(thin) <T> (@in_guaranteed T) -> () {
9898
// CHECK: bb0({{%.*}} : $*T):
99-
// CHECK: [[CTX:%.*]] = builtin "autoDiffCreateLinearMapContextWithType"<T>({{%.*}} : $@thick T.Type) : $Builtin.NativeObject // users: {{.*}}
100-
// CHECK: [[BORROWED_CTX:%.*]] = begin_borrow [lexical] [var_decl] [[CTX]] : $Builtin.NativeObject // users: {{.*}}
99+
// CHECK: [[CTX:%.*]] = builtin "autoDiffCreateLinearMapContextWithType"<T>({{%.*}} : $@thick T.Type) : $Builtin.NativeObject
100+
// CHECK: [[CTX_LIFETIME:%.*]] = move_value [lexical] [var_decl] [[CTX]]
101+
// CHECK: [[BORROWED_CTX:%.*]] = begin_borrow [[CTX_LIFETIME]]
101102
// CHECK: [[BUF:%.*]] = builtin "autoDiffProjectTopLevelSubcontext"([[BORROWED_CTX]] : $Builtin.NativeObject) : $Builtin.RawPointer // users: {{.*}}
103+
// CHECK: [[BORROWED_CTX:%.*]] = begin_borrow [[CTX_LIFETIME]]
102104
// CHECK: [[BUF:%.*]] = builtin "autoDiffAllocateSubcontextWithType"<T>([[BORROWED_CTX]] : $Builtin.NativeObject, {{.*}} : $@thick T.Type) : $Builtin.RawPointer // users: {{.*}}
103-
// CHECK: destroy_value [[CTX]]
105+
// CHECK: destroy_value [[CTX_LIFETIME]]

test/DebugInfo/guard-let-scope3.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class S {
1515
// CHECK: debug_value {{.*}} : $Optional<C>, let, name "x", {{.*}}, scope [[X1]]
1616
// CHECK: debug_value {{.*}} : $C, let, name "x", {{.*}}, scope [[X2]]
1717
// FIXME: This source location is a little wild.
18-
// CHECK-NEXT: strong_retain{{.*}}:[[@LINE+4]]:12, scope [[X2]]
18+
// CHECK-NEXT: release_value{{.*}}:[[@LINE+5]]:3, scope [[X2]]
1919
throw MyError()
2020
// CHECK: function_ref {{.*}}MyError{{.*}}:[[@LINE-1]]:13, scope [[GUARD]]
2121
}

test/SILGen/cf_members.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public func foo(_ x: Double) {
6868
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
6969
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu0_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
7070
// CHECK: [[C:%.*]] = apply [[THUNK]]([[ZVAL]])
71-
// CHECK: [[BORROWED_C:%.*]] = begin_borrow [lexical] [var_decl] [[C]]
71+
// CHECK: [[C_MOVE:%.*]] = move_value [lexical] [var_decl] [[C]]
72+
// CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C_MOVE]]
7273
// CHECK: [[C_COPY:%.*]] = copy_value [[BORROWED_C]]
7374
// CHECK: [[BORROWED_C2:%.*]] = begin_borrow [[C_COPY]]
7475
let c: (Double) -> Struct1 = z.translate(radians:)
@@ -102,7 +103,8 @@ public func foo(_ x: Double) {
102103
// CHECK: [[ZVAL:%.*]] = load [trivial] [[READ]]
103104
// CHECK: [[THUNK:%.*]] = function_ref @$s10cf_members3fooyySdFSo10IAMStruct1VSdcADcfu4_ : $@convention(thin) (Struct1) -> @owned @callee_guaranteed (Double) -> Struct1
104105
// CHECK: [[F:%.*]] = apply [[THUNK]]([[ZVAL]])
105-
// CHECK: [[BORROWED_F:%.*]] = begin_borrow [lexical] [var_decl] [[F]]
106+
// CHECK: [[MOVED_F:%.*]] = move_value [lexical] [var_decl] [[F]]
107+
// CHECK: [[BORROWED_F:%.*]] = begin_borrow [[MOVED_F]]
106108
// CHECK: [[F_COPY:%.*]] = copy_value [[BORROWED_F]]
107109
// CHECK: [[BORROWED_F2:%.*]] = begin_borrow [[F_COPY]]
108110
let f = z.scale

0 commit comments

Comments
 (0)