Skip to content

Commit 9069cc7

Browse files
authored
Merge pull request #40423 from gottesmm/address-only-let-checker
[move-function] Implement move checking for address only lets
2 parents 0398252 + 6f7f235 commit 9069cc7

35 files changed

+1557
-41
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ NOTE(sil_movekillscopyablevalue_use_here, none,
741741
NOTE(sil_movekillscopyablevalue_value_consumed_in_loop, none,
742742
"cyclic move here. move will occur multiple times in the loop", ())
743743
ERROR(sil_movekillscopyablevalue_move_applied_to_unsupported_move, none,
744-
"_move applied to value that the compiler does not supporting checking.",
744+
"_move applied to value that the compiler does not support checking",
745745
())
746746

747747
#define UNDEFINE_DIAGNOSTIC_MACROS

include/swift/SIL/BasicBlockDatastructures.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class BasicBlockSetVector {
4343
iterator begin() const { return vector.begin(); }
4444
iterator end() const { return vector.end(); }
4545

46+
llvm::iterator_range<iterator> getRange() const {
47+
return llvm::make_range(begin(), end());
48+
}
49+
4650
bool empty() const { return vector.empty(); }
4751

4852
bool contains(SILBasicBlock *block) const { return set.contains(block); }

include/swift/SIL/SILBuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,13 @@ class SILBuilder {
12711271
MoveValueInst(getSILDebugLocation(loc), operand));
12721272
}
12731273

1274+
MarkUnresolvedMoveAddrInst *createMarkUnresolvedMoveAddr(SILLocation loc,
1275+
SILValue srcAddr,
1276+
SILValue takeAddr) {
1277+
return insert(new (getModule()) MarkUnresolvedMoveAddrInst(
1278+
getSILDebugLocation(loc), srcAddr, takeAddr));
1279+
}
1280+
12741281
UnconditionalCheckedCastInst *
12751282
createUnconditionalCheckedCast(SILLocation Loc, SILValue op,
12761283
SILType destLoweredTy,

include/swift/SIL/SILCloner.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,16 @@ SILCloner<ImplClass>::visitCopyAddrInst(CopyAddrInst *Inst) {
13411341
Inst->isInitializationOfDest()));
13421342
}
13431343

1344+
template <typename ImplClass>
1345+
void SILCloner<ImplClass>::visitMarkUnresolvedMoveAddrInst(
1346+
MarkUnresolvedMoveAddrInst *Inst) {
1347+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1348+
auto *MVI = getBuilder().createMarkUnresolvedMoveAddr(
1349+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getSrc()),
1350+
getOpValue(Inst->getDest()));
1351+
recordClonedInstruction(Inst, MVI);
1352+
}
1353+
13441354
template<typename ImplClass>
13451355
void
13461356
SILCloner<ImplClass>::visitBindMemoryInst(BindMemoryInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,10 @@ struct SILDebugVariable {
17931793
Implicit == V.Implicit && Type == V.Type && Loc == V.Loc &&
17941794
Scope == V.Scope;
17951795
}
1796+
1797+
bool isLet() const { return Name.size() && Constant; }
1798+
1799+
bool isVar() const { return Name.size() && !Constant; }
17961800
};
17971801

17981802
/// A DebugVariable where storage for the strings has been
@@ -2004,7 +2008,20 @@ class AllocStackInst final
20042008
auto VI = TailAllocatedDebugVariable(RawValue);
20052009
return VI.get(getDecl(), getTrailingObjects<char>(), AuxVarType, VarDeclLoc,
20062010
VarDeclScope, DIExprElements);
2007-
};
2011+
}
2012+
2013+
bool isLet() const {
2014+
if (auto varInfo = getVarInfo())
2015+
return varInfo->isLet();
2016+
return false;
2017+
}
2018+
2019+
bool isVar() const {
2020+
if (auto varInfo = getVarInfo())
2021+
return varInfo->isVar();
2022+
return false;
2023+
}
2024+
20082025
void setArgNo(unsigned N) {
20092026
auto RawValue = SILNode::Bits.AllocStackInst.VarInfo;
20102027
auto VI = TailAllocatedDebugVariable(RawValue);
@@ -7424,6 +7441,35 @@ class MoveValueInst
74247441
void setAllowsDiagnostics(bool newValue) { allowDiagnostics = newValue; }
74257442
};
74267443

7444+
/// Equivalent to a copy_addr to [init] except that it is used for diagnostics
7445+
/// and should not be pattern matched. During the diagnostic passes, the "move
7446+
/// function" checker for addresses always converts this to a copy_addr [init]
7447+
/// (if we emitted a diagnostic and proved we could not emit a move here) or a
7448+
/// copy_addr [take][init] if we can. So this should never occur in canonical
7449+
/// SIL.
7450+
class MarkUnresolvedMoveAddrInst
7451+
: public InstructionBase<SILInstructionKind::MarkUnresolvedMoveAddrInst,
7452+
NonValueInstruction>,
7453+
public CopyLikeInstruction {
7454+
friend class SILBuilder;
7455+
7456+
FixedOperandList<2> Operands;
7457+
7458+
MarkUnresolvedMoveAddrInst(SILDebugLocation DebugLoc, SILValue srcAddr,
7459+
SILValue takeAddr)
7460+
: InstructionBase(DebugLoc), Operands(this, srcAddr, takeAddr) {}
7461+
7462+
public:
7463+
SILValue getSrc() const { return Operands[Src].get(); }
7464+
SILValue getDest() const { return Operands[Dest].get(); }
7465+
7466+
void setSrc(SILValue V) { Operands[Src].set(V); }
7467+
void setDest(SILValue V) { Operands[Dest].set(V); }
7468+
7469+
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
7470+
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
7471+
};
7472+
74277473
/// Given an object reference, return true iff it is non-nil and refers
74287474
/// to a native swift object with strong reference count of 1.
74297475
class IsUniqueInst

include/swift/SIL/SILNodes.def

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,15 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
591591
SingleValueInstruction, None, MayRelease)
592592
// A move_value is an OSSA only instruction. Its result does not have any side
593593
// effects relative to other OSSA values like copy_value.
594-
SINGLE_VALUE_INST(MoveValueInst, move_value,
595-
SingleValueInstruction, None, DoesNotRelease)
594+
SINGLE_VALUE_INST(MoveValueInst, move_value, SingleValueInstruction, None,
595+
DoesNotRelease)
596+
597+
// A move_addr is a Raw SIL only instruction that is equivalent to a copy_addr
598+
// [init]. It is lowered during the diagnostic passes to a copy_addr [init] if
599+
// the move checker found uses that prevented us from converting this to a
600+
// move or if we do not find such uses, a copy_addr [init] [take].
601+
NON_VALUE_INST(MarkUnresolvedMoveAddrInst, mark_unresolved_move_addr,
602+
SILInstruction, None, DoesNotRelease)
596603

597604
// IsUnique does not actually write to memory but should be modeled
598605
// as such. Its operand is a pointer to an object reference. The

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,9 @@ PASS(MoveKillsCopyableValuesChecker, "sil-move-kills-copyable-values-checker",
427427
"to _move do not have any uses later than the _move")
428428
PASS(LexicalLifetimeEliminator, "sil-lexical-lifetime-eliminator",
429429
"Pass that removes lexical lifetime markers from borrows and alloc stack")
430+
PASS(MoveKillsCopyableAddressesChecker, "sil-move-kills-copyable-addresses-checker",
431+
"Pass that checks that any copyable (non-move only) address that is passed "
432+
"to _move do not have any uses later than the _move")
430433
PASS(PruneVTables, "prune-vtables",
431434
"Mark class methods that do not require vtable dispatch")
432435
PASS_RANGE(AllPasses, AADumper, PruneVTables)

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,9 @@ class IRGenSILFunction :
12621262
void visitDeallocPartialRefInst(DeallocPartialRefInst *i);
12631263

12641264
void visitCopyAddrInst(CopyAddrInst *i);
1265+
void visitMarkUnresolvedMoveAddrInst(MarkUnresolvedMoveAddrInst *mai) {
1266+
llvm_unreachable("Valid only when ownership is enabled");
1267+
}
12651268
void visitDestroyAddrInst(DestroyAddrInst *i);
12661269

12671270
void visitBindMemoryInst(BindMemoryInst *i);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ OPERAND_OWNERSHIP(TrivialUse, CheckedCastAddrBranch)
143143
OPERAND_OWNERSHIP(TrivialUse, CondBranch)
144144
OPERAND_OWNERSHIP(TrivialUse, CondFail)
145145
OPERAND_OWNERSHIP(TrivialUse, CopyAddr)
146+
OPERAND_OWNERSHIP(TrivialUse, MarkUnresolvedMoveAddr)
146147
OPERAND_OWNERSHIP(TrivialUse, DeallocStack)
147148
OPERAND_OWNERSHIP(TrivialUse, DeinitExistentialAddr)
148149
OPERAND_OWNERSHIP(TrivialUse, DestroyAddr)

lib/SIL/IR/SILInstruction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,10 @@ bool SILInstruction::mayRelease() const {
11671167
return CopyAddr->isInitializationOfDest() ==
11681168
IsInitialization_t::IsNotInitialization;
11691169
}
1170+
// mark_unresolved_move_addr is equivalent to a copy_addr [init], so a release
1171+
// does not occur.
1172+
case SILInstructionKind::MarkUnresolvedMoveAddrInst:
1173+
return false;
11701174

11711175
case SILInstructionKind::BuiltinInst: {
11721176
auto *BI = cast<BuiltinInst>(this);

lib/SIL/IR/SILPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,11 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
17031703
*this << getIDAndType(CI->getDest());
17041704
}
17051705

1706+
void visitMarkUnresolvedMoveAddrInst(MarkUnresolvedMoveAddrInst *CI) {
1707+
*this << Ctx.getID(CI->getSrc()) << " to ";
1708+
*this << getIDAndType(CI->getDest());
1709+
}
1710+
17061711
void visitBindMemoryInst(BindMemoryInst *BI) {
17071712
*this << getIDAndType(BI->getBase()) << ", ";
17081713
*this << getIDAndType(BI->getIndex()) << " to ";

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4771,6 +4771,34 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
47714771
IsInitialization_t(IsInit));
47724772
break;
47734773
}
4774+
case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
4775+
UnresolvedValueName SrcLName;
4776+
SILValue DestLVal;
4777+
SourceLoc ToLoc, DestLoc;
4778+
Identifier ToToken;
4779+
if (parseValueName(SrcLName) ||
4780+
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
4781+
"to") ||
4782+
parseTypedValueRef(DestLVal, DestLoc, B) ||
4783+
parseSILDebugLocation(InstLoc, B))
4784+
return true;
4785+
4786+
if (ToToken.str() != "to") {
4787+
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
4788+
return true;
4789+
}
4790+
4791+
if (!DestLVal->getType().isAddress()) {
4792+
P.diagnose(DestLoc, diag::sil_invalid_instr_operands);
4793+
return true;
4794+
}
4795+
4796+
SILValue SrcLVal =
4797+
getLocalValue(SrcLName, DestLVal->getType(), InstLoc, B);
4798+
ResultVal = B.createMarkUnresolvedMoveAddr(InstLoc, SrcLVal, DestLVal);
4799+
break;
4800+
}
4801+
47744802
case SILInstructionKind::BindMemoryInst: {
47754803
SILValue IndexVal;
47764804
SILType EltTy;

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,11 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
631631
return RuntimeEffect::MetaData | RuntimeEffect::RefCounting;
632632
return RuntimeEffect::MetaData;
633633
}
634+
// Equialent to a copy_addr [init]
635+
case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
636+
return RuntimeEffect::MetaData | RuntimeEffect::RefCounting;
637+
}
638+
634639
case SILInstructionKind::StoreInst:
635640
switch (cast<StoreInst>(inst)->getOwnershipQualifier()) {
636641
case StoreOwnershipQualifier::Unqualified:

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,9 @@ bool swift::memInstMustInitialize(Operand *memOper) {
19041904
auto *CAI = cast<CopyAddrInst>(memInst);
19051905
return CAI->getDest() == address && CAI->isInitializationOfDest();
19061906
}
1907+
case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
1908+
return cast<MarkUnresolvedMoveAddrInst>(memInst)->getDest() == address;
1909+
}
19071910
case SILInstructionKind::InitExistentialAddrInst:
19081911
case SILInstructionKind::InitEnumDataAddrInst:
19091912
case SILInstructionKind::InjectEnumAddrInst:
@@ -2346,6 +2349,11 @@ void swift::visitAccessedAddress(SILInstruction *I,
23462349
visitor(&I->getAllOperands()[CopyAddrInst::Dest]);
23472350
return;
23482351

2352+
case SILInstructionKind::MarkUnresolvedMoveAddrInst:
2353+
visitor(&I->getAllOperands()[MarkUnresolvedMoveAddrInst::Src]);
2354+
visitor(&I->getAllOperands()[MarkUnresolvedMoveAddrInst::Dest]);
2355+
return;
2356+
23492357
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
23502358
case SILInstructionKind::Store##Name##Inst:
23512359
#include "swift/AST/ReferenceStorage.def"

lib/SIL/Utils/MemoryLocations.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ bool MemoryLocations::analyzeLocationUsesRecursively(SILValue V, unsigned locIdx
365365
case SILInstructionKind::SwitchEnumAddrInst:
366366
case SILInstructionKind::WitnessMethodInst:
367367
break;
368+
case SILInstructionKind::MarkUnresolvedMoveAddrInst:
369+
// We do not want the memory lifetime verifier to verify move_addr inst
370+
// since the MarkUnresolvedMoveAddrChecker will validate that its uses
371+
// are correct.
372+
return false;
368373
default:
369374
return false;
370375
}

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -701,17 +701,18 @@ swift::findTransitiveUsesForAddress(SILValue projectedAddress,
701701
}
702702
// First, eliminate "end point uses" that we just need to check liveness at
703703
// and do not need to check transitive uses of.
704-
if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) || isIncidentalUse(user)
705-
|| isa<StoreInst>(user) || isa<DestroyAddrInst>(user)
706-
|| isa<AssignInst>(user) || isa<YieldInst>(user)
707-
|| isa<LoadUnownedInst>(user) || isa<StoreUnownedInst>(user)
708-
|| isa<EndApplyInst>(user) || isa<LoadWeakInst>(user)
709-
|| isa<StoreWeakInst>(user) || isa<AssignByWrapperInst>(user)
710-
|| isa<BeginUnpairedAccessInst>(user)
711-
|| isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user)
712-
|| isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user)
713-
|| isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user)
714-
|| isa<IsUniqueInst>(user)) {
704+
if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) ||
705+
isa<MarkUnresolvedMoveAddrInst>(user) || isIncidentalUse(user) ||
706+
isa<StoreInst>(user) || isa<DestroyAddrInst>(user) ||
707+
isa<AssignInst>(user) || isa<YieldInst>(user) ||
708+
isa<LoadUnownedInst>(user) || isa<StoreUnownedInst>(user) ||
709+
isa<EndApplyInst>(user) || isa<LoadWeakInst>(user) ||
710+
isa<StoreWeakInst>(user) || isa<AssignByWrapperInst>(user) ||
711+
isa<BeginUnpairedAccessInst>(user) ||
712+
isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) ||
713+
isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) ||
714+
isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
715+
isa<IsUniqueInst>(user)) {
715716
leafUse(op);
716717
continue;
717718
}

lib/SIL/Verifier/LoadBorrowImmutabilityChecker.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ bool GatherWritesVisitor::visitUse(Operand *op, AccessUseType useTy) {
170170
}
171171
return true;
172172

173+
case SILInstructionKind::MarkUnresolvedMoveAddrInst:
174+
if (cast<MarkUnresolvedMoveAddrInst>(user)->getDest() == op->get()) {
175+
writeAccumulator.push_back(op);
176+
return true;
177+
}
178+
179+
// This operand is the move source, we just return true. This is because
180+
// mark_unresolved_move_addr semantically is treated as a copy_addr of the
181+
// source. The checker determines if we can convert it to a move.
182+
return true;
183+
173184
// If this value is dependent on another, conservatively consider it a write.
174185
//
175186
// FIXME: explain why a mark_dependence effectively writes to storage.

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,14 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
354354
genBits(state, CAI->getDest());
355355
break;
356356
}
357+
case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
358+
auto *MMAI = cast<MarkUnresolvedMoveAddrInst>(&I);
359+
// We do not treat the move addr inst as invalidating its src since we
360+
// are going to prove that we do not inappropriately reuse the memory
361+
// later.
362+
genBits(state, MMAI->getDest());
363+
break;
364+
}
357365
case SILInstructionKind::InjectEnumAddrInst: {
358366
auto *IEAI = cast<InjectEnumAddrInst>(&I);
359367
int enumIdx = locations.getLocationIdx(IEAI->getOperand());

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ struct ImmutableAddressUseVerifier {
592592
break;
593593
case SILInstructionKind::EndAccessInst:
594594
break;
595+
case SILInstructionKind::MarkUnresolvedMoveAddrInst:
596+
// We model mark_unresolved_move_addr as a copy_addr [init]. So no
597+
// mutation can happen. The checker will prove eventually that we can
598+
// convert it to a copy_addr [take] [init].
599+
break;
595600
case SILInstructionKind::CopyAddrInst:
596601
if (isConsumingOrMutatingCopyAddrUse(use))
597602
return true;
@@ -2637,6 +2642,18 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
26372642
"cannot directly copy type with inaccessible ABI");
26382643
}
26392644

2645+
void checkMarkUnresolvedMoveAddrInst(MarkUnresolvedMoveAddrInst *SI) {
2646+
require(F.hasOwnership(), "Only valid in OSSA.");
2647+
require(F.getModule().getStage() == SILStage::Raw, "Only valid in Raw SIL");
2648+
require(SI->getSrc()->getType().isAddress(), "Src value should be lvalue");
2649+
require(SI->getDest()->getType().isAddress(),
2650+
"Dest address should be lvalue");
2651+
requireSameType(SI->getDest()->getType(), SI->getSrc()->getType(),
2652+
"Store operand type and dest type mismatch");
2653+
require(F.isTypeABIAccessible(SI->getDest()->getType()),
2654+
"cannot directly copy type with inaccessible ABI");
2655+
}
2656+
26402657
void checkRetainValueInst(RetainValueInst *I) {
26412658
require(I->getOperand()->getType().isObject(),
26422659
"Source value should be an object value");

lib/SILGen/SILGenLazyConformance.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
195195
SGM.useConformancesFromType(CAI->getDest()->getType().getASTType());
196196
}
197197

198+
void visitMarkUnresolvedMoveAddrInst(MarkUnresolvedMoveAddrInst *MAI) {
199+
SGM.useConformancesFromType(MAI->getSrc()->getType().getASTType());
200+
SGM.useConformancesFromType(MAI->getDest()->getType().getASTType());
201+
}
202+
198203
void visitCopyValueInst(CopyValueInst *CVI) {
199204
SGM.useConformancesFromType(CVI->getOperand()->getType().getASTType());
200205
}

0 commit comments

Comments
 (0)