Skip to content

Commit

Permalink
Merge pull request swiftlang#8771 from rjmccall/ref-element-accesses
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci authored Apr 14, 2017
2 parents 5cb6ad1 + 5c725e6 commit e9d6b48
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 48 deletions.
4 changes: 4 additions & 0 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
/// \brief The current context where formal evaluation cleanups are managed.
FormalEvaluationContext FormalEvalContext;

/// \brief Values to end dynamic access enforcement on. A hack for
/// materializeForSet.
SmallVectorImpl<SILValue> *ValuesToEndAccessForMaterializeForSet = nullptr;

/// VarLoc - representation of an emitted local variable or constant. There
/// are three scenarios here:
///
Expand Down
118 changes: 73 additions & 45 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,65 @@ namespace {
}
};

class EndAccessPseudoComponent : public WritebackPseudoComponent {
public:
EndAccessPseudoComponent(const LValueTypeData &typeData)
: WritebackPseudoComponent(typeData) {}

private:
void writeback(SILGenFunction &SGF, SILLocation loc,
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
assert(base.isLValue());
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
}

void print(raw_ostream &OS) const override {
OS << "EndAccessPseudoComponent";
}
};
} // end anonymous namespace

static SILValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
SILValue addr, LValueTypeData typeData,
AccessKind accessKind,
SILAccessEnforcement enforcement) {
auto silAccessKind = [&] {
switch (accessKind) {
case AccessKind::Read:
return SILAccessKind::Read;
case AccessKind::Write:
case AccessKind::ReadWrite:
return SILAccessKind::Modify;
}
}();

// Hack for materializeForSet emission, where we can't safely
// push a begin/end access.
if (!SGF.InWritebackScope) {
assert(SGF.ValuesToEndAccessForMaterializeForSet);
if (enforcement == SILAccessEnforcement::Dynamic) {
// FIXME: begin access.
SGF.ValuesToEndAccessForMaterializeForSet->push_back(addr);
}
return addr;
}

// Enter the access.
addr = SGF.B.createBeginAccess(loc, addr, silAccessKind, enforcement);

// Push a writeback to end it.
auto accessedMV = ManagedValue::forLValue(addr);
std::unique_ptr<LogicalPathComponent>
component(new EndAccessPseudoComponent(typeData));
pushWriteback(SGF, loc, std::move(component), accessedMV,
MaterializedLValue());

return addr;
}

namespace {
class RefElementComponent : public PhysicalPathComponent {
VarDecl *Field;
SILType SubstFieldType;
Expand All @@ -399,9 +458,16 @@ namespace {
// Borrow the ref element addr using formal access. If we need the ref
// element addr, we will load it in this expression.
base = base.formalAccessBorrow(SGF, loc);
auto Res = SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
Field, SubstFieldType);
return ManagedValue::forLValue(Res);
SILValue result =
SGF.B.createRefElementAddr(loc, base.getUnmanagedValue(),
Field, SubstFieldType);

if (auto enforcement = SGF.getDynamicEnforcement(Field)) {
result = enterAccessScope(SGF, loc, result, getTypeData(),
accessKind, *enforcement);
}

return ManagedValue::forLValue(result);
}

void print(raw_ostream &OS) const override {
Expand Down Expand Up @@ -517,25 +583,6 @@ namespace {
}
};

class EndAccessPseudoComponent : public WritebackPseudoComponent {
public:
EndAccessPseudoComponent(const LValueTypeData &typeData)
: WritebackPseudoComponent(typeData) {}

private:
void writeback(SILGenFunction &SGF, SILLocation loc,
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
assert(base.isLValue());
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
}

void print(raw_ostream &OS) const override {
OS << "EndAccessPseudoComponent";
}
};

/// A physical path component which returns a literal address.
class ValueComponent : public PhysicalPathComponent {
ManagedValue Value;
Expand All @@ -560,30 +607,11 @@ namespace {
if (!Enforcement)
return Value;

assert(Value.isLValue() && "nonlvalue has enforcement?");
auto silAccessKind = [&] {
switch (accessKind) {
case AccessKind::Read:
return SILAccessKind::Read;
case AccessKind::Write:
case AccessKind::ReadWrite:
return SILAccessKind::Modify;
}
}();

// Enter the access.
auto accessedValue =
SGF.B.createBeginAccess(loc, Value.getValue(),
silAccessKind, *Enforcement);
auto accessedMV = ManagedValue::forLValue(accessedValue);

// Push a writeback to end it.
std::unique_ptr<LogicalPathComponent>
component(new EndAccessPseudoComponent(getTypeData()));
pushWriteback(SGF, loc, std::move(component), accessedMV,
MaterializedLValue());
SILValue addr = Value.getLValueAddress();
addr = enterAccessScope(SGF, loc, addr, getTypeData(),
accessKind, *Enforcement);

return ManagedValue::forLValue(accessedValue);
return ManagedValue::forLValue(addr);
}

bool isRValue() const override {
Expand Down
19 changes: 16 additions & 3 deletions lib/SILGen/SILGenMaterializeForSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ struct MaterializeForSetEmitter {
void emit(SILGenFunction &gen);

SILValue emitUsingStorage(SILGenFunction &gen, SILLocation loc,
ManagedValue self, RValue &&indices);
ManagedValue self, RValue &&indices,
SILValue callbackBuffer, SILFunction *&callback);

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

case AccessStrategy::Storage:
address = emitUsingStorage(gen, loc, self, std::move(indicesRV));
address = emitUsingStorage(gen, loc, self, std::move(indicesRV),
callbackBuffer, callbackFn);
break;

case AccessStrategy::Addressor:
Expand Down Expand Up @@ -730,11 +732,22 @@ SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F,
SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen,
SILLocation loc,
ManagedValue self,
RValue &&indices) {
RValue &&indices,
SILValue callbackBuffer,
SILFunction *&callback) {
LValue lvalue = buildLValue(gen, loc, self, std::move(indices),
AccessKind::ReadWrite);

SmallVector<SILValue, 4> valuesToEndAccessOf;
gen.ValuesToEndAccessForMaterializeForSet = &valuesToEndAccessOf;

ManagedValue address =
gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite);

if (!valuesToEndAccessOf.empty()) {
// FIXME: build callback to end access.
}

return address.getUnmanagedValue();
}

Expand Down
20 changes: 20 additions & 0 deletions test/SILGen/access_marker_gen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,23 @@ public struct HasTwoStoredProperties {
f = g
}
}

class C {
final var x: Int = 0
}

func testClassInstanceProperties(c: C) {
let y = c.x
c.x = y
}
// CHECK-LABEL: sil hidden @_T017access_marker_gen27testClassInstancePropertiesyAA1CC1c_tF :
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[CX]] : $*Int
// CHECK-NEXT: [[Y:%.*]] = load [trivial] [[ACCESS]]
// CHECK-NEXT: end_access [[ACCESS]]
// CHECK: [[C:%.*]] = begin_borrow %0 : $C
// CHECK-NEXT: [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[CX]] : $*Int
// CHECK-NEXT: assign [[Y]] to [[ACCESS]]
// CHECK-NEXT: end_access [[ACCESS]]

0 comments on commit e9d6b48

Please sign in to comment.