Skip to content

Commit e9d6b48

Browse files
authored
Merge pull request #8771 from rjmccall/ref-element-accesses
2 parents 5cb6ad1 + 5c725e6 commit e9d6b48

File tree

4 files changed

+113
-48
lines changed

4 files changed

+113
-48
lines changed

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
353353
/// \brief The current context where formal evaluation cleanups are managed.
354354
FormalEvaluationContext FormalEvalContext;
355355

356+
/// \brief Values to end dynamic access enforcement on. A hack for
357+
/// materializeForSet.
358+
SmallVectorImpl<SILValue> *ValuesToEndAccessForMaterializeForSet = nullptr;
359+
356360
/// VarLoc - representation of an emitted local variable or constant. There
357361
/// are three scenarios here:
358362
///

lib/SILGen/SILGenLValue.cpp

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,65 @@ namespace {
381381
}
382382
};
383383

384+
class EndAccessPseudoComponent : public WritebackPseudoComponent {
385+
public:
386+
EndAccessPseudoComponent(const LValueTypeData &typeData)
387+
: WritebackPseudoComponent(typeData) {}
388+
389+
private:
390+
void writeback(SILGenFunction &SGF, SILLocation loc,
391+
ManagedValue base,
392+
MaterializedLValue materialized,
393+
bool isFinal) override {
394+
assert(base.isLValue());
395+
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
396+
}
397+
398+
void print(raw_ostream &OS) const override {
399+
OS << "EndAccessPseudoComponent";
400+
}
401+
};
402+
} // end anonymous namespace
403+
404+
static SILValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
405+
SILValue addr, LValueTypeData typeData,
406+
AccessKind accessKind,
407+
SILAccessEnforcement enforcement) {
408+
auto silAccessKind = [&] {
409+
switch (accessKind) {
410+
case AccessKind::Read:
411+
return SILAccessKind::Read;
412+
case AccessKind::Write:
413+
case AccessKind::ReadWrite:
414+
return SILAccessKind::Modify;
415+
}
416+
}();
417+
418+
// Hack for materializeForSet emission, where we can't safely
419+
// push a begin/end access.
420+
if (!SGF.InWritebackScope) {
421+
assert(SGF.ValuesToEndAccessForMaterializeForSet);
422+
if (enforcement == SILAccessEnforcement::Dynamic) {
423+
// FIXME: begin access.
424+
SGF.ValuesToEndAccessForMaterializeForSet->push_back(addr);
425+
}
426+
return addr;
427+
}
428+
429+
// Enter the access.
430+
addr = SGF.B.createBeginAccess(loc, addr, silAccessKind, enforcement);
431+
432+
// Push a writeback to end it.
433+
auto accessedMV = ManagedValue::forLValue(addr);
434+
std::unique_ptr<LogicalPathComponent>
435+
component(new EndAccessPseudoComponent(typeData));
436+
pushWriteback(SGF, loc, std::move(component), accessedMV,
437+
MaterializedLValue());
438+
439+
return addr;
440+
}
441+
442+
namespace {
384443
class RefElementComponent : public PhysicalPathComponent {
385444
VarDecl *Field;
386445
SILType SubstFieldType;
@@ -399,9 +458,16 @@ namespace {
399458
// Borrow the ref element addr using formal access. If we need the ref
400459
// element addr, we will load it in this expression.
401460
base = base.formalAccessBorrow(SGF, loc);
402-
auto Res = SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
403-
Field, SubstFieldType);
404-
return ManagedValue::forLValue(Res);
461+
SILValue result =
462+
SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
463+
Field, SubstFieldType);
464+
465+
if (auto enforcement = SGF.getDynamicEnforcement(Field)) {
466+
result = enterAccessScope(SGF, loc, result, getTypeData(),
467+
accessKind, *enforcement);
468+
}
469+
470+
return ManagedValue::forLValue(result);
405471
}
406472

407473
void print(raw_ostream &OS) const override {
@@ -517,25 +583,6 @@ namespace {
517583
}
518584
};
519585

520-
class EndAccessPseudoComponent : public WritebackPseudoComponent {
521-
public:
522-
EndAccessPseudoComponent(const LValueTypeData &typeData)
523-
: WritebackPseudoComponent(typeData) {}
524-
525-
private:
526-
void writeback(SILGenFunction &SGF, SILLocation loc,
527-
ManagedValue base,
528-
MaterializedLValue materialized,
529-
bool isFinal) override {
530-
assert(base.isLValue());
531-
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
532-
}
533-
534-
void print(raw_ostream &OS) const override {
535-
OS << "EndAccessPseudoComponent";
536-
}
537-
};
538-
539586
/// A physical path component which returns a literal address.
540587
class ValueComponent : public PhysicalPathComponent {
541588
ManagedValue Value;
@@ -560,30 +607,11 @@ namespace {
560607
if (!Enforcement)
561608
return Value;
562609

563-
assert(Value.isLValue() && "nonlvalue has enforcement?");
564-
auto silAccessKind = [&] {
565-
switch (accessKind) {
566-
case AccessKind::Read:
567-
return SILAccessKind::Read;
568-
case AccessKind::Write:
569-
case AccessKind::ReadWrite:
570-
return SILAccessKind::Modify;
571-
}
572-
}();
573-
574-
// Enter the access.
575-
auto accessedValue =
576-
SGF.B.createBeginAccess(loc, Value.getValue(),
577-
silAccessKind, *Enforcement);
578-
auto accessedMV = ManagedValue::forLValue(accessedValue);
579-
580-
// Push a writeback to end it.
581-
std::unique_ptr<LogicalPathComponent>
582-
component(new EndAccessPseudoComponent(getTypeData()));
583-
pushWriteback(SGF, loc, std::move(component), accessedMV,
584-
MaterializedLValue());
610+
SILValue addr = Value.getLValueAddress();
611+
addr = enterAccessScope(SGF, loc, addr, getTypeData(),
612+
accessKind, *Enforcement);
585613

586-
return ManagedValue::forLValue(accessedValue);
614+
return ManagedValue::forLValue(addr);
587615
}
588616

589617
bool isRValue() const override {

lib/SILGen/SILGenMaterializeForSet.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ struct MaterializeForSetEmitter {
388388
void emit(SILGenFunction &gen);
389389

390390
SILValue emitUsingStorage(SILGenFunction &gen, SILLocation loc,
391-
ManagedValue self, RValue &&indices);
391+
ManagedValue self, RValue &&indices,
392+
SILValue callbackBuffer, SILFunction *&callback);
392393

393394
SILValue emitUsingAddressor(SILGenFunction &gen, SILLocation loc,
394395
ManagedValue self, RValue &&indices,
@@ -559,7 +560,8 @@ void MaterializeForSetEmitter::emit(SILGenFunction &gen) {
559560
llvm_unreachable("materializeForSet should never engage in behavior init");
560561

561562
case AccessStrategy::Storage:
562-
address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
563+
address = emitUsingStorage(gen, loc, self, std::move(indicesRV),
564+
callbackBuffer, callbackFn);
563565
break;
564566

565567
case AccessStrategy::Addressor:
@@ -730,11 +732,22 @@ SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
730732
SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen,
731733
SILLocation loc,
732734
ManagedValue self,
733-
RValue &&indices) {
735+
RValue &&indices,
736+
SILValue callbackBuffer,
737+
SILFunction *&callback) {
734738
LValue lvalue = buildLValue(gen, loc, self, std::move(indices),
735739
AccessKind::ReadWrite);
740+
741+
SmallVector<SILValue, 4> valuesToEndAccessOf;
742+
gen.ValuesToEndAccessForMaterializeForSet = &valuesToEndAccessOf;
743+
736744
ManagedValue address =
737745
gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite);
746+
747+
if (!valuesToEndAccessOf.empty()) {
748+
// FIXME: build callback to end access.
749+
}
750+
738751
return address.getUnmanagedValue();
739752
}
740753

test/SILGen/access_marker_gen.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,23 @@ public struct HasTwoStoredProperties {
9191
f = g
9292
}
9393
}
94+
95+
class C {
96+
final var x: Int = 0
97+
}
98+
99+
func testClassInstanceProperties(c: C) {
100+
let y = c.x
101+
c.x = y
102+
}
103+
// CHECK-LABEL: sil hidden @_T017access_marker_gen27testClassInstancePropertiesyAA1CC1c_tF :
104+
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
105+
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
106+
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[CX]] : $*Int
107+
// CHECK-NEXT: [[Y:%.*]] = load [trivial] [[ACCESS]]
108+
// CHECK-NEXT: end_access [[ACCESS]]
109+
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
110+
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
111+
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[CX]] : $*Int
112+
// CHECK-NEXT: assign [[Y]] to [[ACCESS]]
113+
// CHECK-NEXT: end_access [[ACCESS]]

0 commit comments

Comments
 (0)