Skip to content

Commit b065540

Browse files
authored
Merge pull request #72281 from jckarter/moveonly-optional-chain-3
SIL: Optimizer fixes for noncopyable optional chains.
2 parents 154f47e + 8a65c9b commit b065540

File tree

4 files changed

+26
-11
lines changed

4 files changed

+26
-11
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,9 @@ class SILBuilder {
14041404
assert(!operand->getType().isTrivial(getFunction()) &&
14051405
"Should not be passing trivial values to this api. Use instead "
14061406
"emitCopyValueOperation");
1407+
assert((getModule().getStage() == SILStage::Raw
1408+
|| !operand->getType().isMoveOnly())
1409+
&& "should not be copying move-only values in canonical SIL");
14071410
return insert(new (getModule())
14081411
CopyValueInst(getSILDebugLocation(Loc), operand));
14091412
}

lib/SILGen/SILGenLValue.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,9 @@ static ManagedValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
670670
SILAccessEnforcement enforcement,
671671
std::optional<ActorIsolation> actorIso,
672672
bool noNestedConflict = false) {
673-
return ManagedValue::forLValue(
674-
enterAccessScope(SGF, loc, base, addr.getValue(), typeData,
675-
accessKind, enforcement, actorIso, noNestedConflict));
673+
auto access = enterAccessScope(SGF, loc, base, addr.getValue(), typeData,
674+
accessKind, enforcement, actorIso, noNestedConflict);
675+
return ManagedValue::forLValue(access);
676676
}
677677

678678
// Find the base of the formal access at `address`. If the base requires an
@@ -4415,11 +4415,9 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
44154415
SILAccessEnforcement::Static,
44164416
std::nullopt,
44174417
/*no nested conflict*/ true);
4418-
} else {
4419-
// Take ownership of the base.
4420-
optBase = SGF.emitFormalAccessManagedRValueWithCleanup(e,
4421-
optBase.getValue());
44224418
}
4419+
// Take ownership of the base.
4420+
optBase = SGF.emitManagedRValueWithCleanup(optBase.getValue());
44234421
}
44244422
}
44254423
// Bind the value, branching to the destination address if there's no
@@ -4440,11 +4438,16 @@ LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e,
44404438
// Reset the insertion point at the end of hasValueBB so we can
44414439
// continue to emit code there.
44424440
SGF.B.setInsertionPoint(someBB);
4443-
4441+
44444442
// Project out the payload on the success branch. We can just use a
44454443
// naked ValueComponent here; this is effectively a separate l-value.
44464444
ManagedValue optPayload =
44474445
getPayloadOfOptionalValue(SGF, e, optBase, valueTypeData, accessKind);
4446+
// Disable the cleanup if consuming since the consumer should pull straight
4447+
// from the address we give them.
4448+
if (optBase.getType().isMoveOnly() && isConsumeAccess(baseAccessKind)) {
4449+
optPayload = ManagedValue::forLValue(optPayload.forward(SGF));
4450+
}
44484451
LValue valueLV;
44494452
valueLV.add<ValueComponent>(optPayload, std::nullopt, valueTypeData,
44504453
/*is rvalue*/optBase.getType().isObject());

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,9 +1471,15 @@ SILInstruction *SILCombiner::visitCondBranchInst(CondBranchInst *CBI) {
14711471
if (!CBI->getTrueArgs().empty() || !CBI->getFalseArgs().empty())
14721472
return nullptr;
14731473
auto EnumOperandTy = SEI->getEnumOperand()->getType();
1474-
// Type should be loadable
1475-
if (!EnumOperandTy.isLoadable(*SEI->getFunction()))
1474+
// Type should be loadable and copyable.
1475+
// TODO: Generalize to work without copying address-only or noncopyable
1476+
// values.
1477+
if (!EnumOperandTy.isLoadable(*SEI->getFunction())) {
14761478
return nullptr;
1479+
}
1480+
if (EnumOperandTy.isMoveOnly()) {
1481+
return nullptr;
1482+
}
14771483

14781484
// Result of the select_enum should be a boolean.
14791485
if (SEI->getType() != CBI->getCondition()->getType())

test/SILGen/moveonly_optional_operations_2.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func consumingSwitchSubject3(ncp: consuming NCPair) {
7474
// CHECK: [[PAIR_MARK:%.*]] = mark_unresolved_non_copyable_value [assignable_but_not_consumable] [[PAIR_ACCESS]]
7575
// CHECK: [[FIELD:%.*]] = struct_element_addr [[PAIR_MARK]]
7676
// CHECK: [[FIELD_ACCESS:%.*]] = begin_access [deinit] [static] [no_nested_conflict] [[FIELD]]
77-
// CHECK: cond_br {{.*}}, [[SOME_BB:bb[0-9]+]],
77+
// CHECK: cond_br {{.*}}, [[SOME_BB:bb[0-9]+]], [[NONE_BB:bb[0-9]+]]
7878
// CHECK: [[SOME_BB]]:
7979
// CHECK: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[FIELD_ACCESS]]
8080
// CHECK: [[PAYLOAD:%.*]] = load [take] [[PAYLOAD_ADDR]]
@@ -85,6 +85,9 @@ func consumingSwitchSubject3(ncp: consuming NCPair) {
8585
// CHECK-NEXT: end_access [[PAIR_ACCESS]]
8686
// CHECK-NEXT: inject_enum_addr
8787
// CHECK-NEXT: br
88+
// CHECK: [[NONE_BB]]:
89+
// CHECK: destroy_addr [[FIELD_ACCESS]]
90+
// CHECK-NEXT: end_access [[FIELD_ACCESS]]
8891

8992
switch ncp.first?.c3() {
9093
default:

0 commit comments

Comments
 (0)