Skip to content

Commit 1293360

Browse files
author
ematejska
authored
Merge pull request #11150 from rjmccall/nonaccessing-pointer-conversions-4.0
[4.0] Allow pointer comparisons and KVO methods to avoid initiating formal accesses
2 parents f511dd1 + d980972 commit 1293360

16 files changed

+446
-104
lines changed

include/swift/AST/Expr.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,22 @@ class alignas(8) Expr {
347347
enum { NumTupleShuffleExprBits = NumImplicitConversionExprBits + 1 };
348348
static_assert(NumTupleShuffleExprBits <= 32, "fits in an unsigned");
349349

350+
class InOutToPointerExprBitfields {
351+
friend class InOutToPointerExpr;
352+
unsigned : NumImplicitConversionExprBits;
353+
unsigned IsNonAccessing : 1;
354+
};
355+
enum { NumInOutToPointerExprBits = NumImplicitConversionExprBits + 1 };
356+
static_assert(NumInOutToPointerExprBits <= 32, "fits in an unsigned");
357+
358+
class ArrayToPointerExprBitfields {
359+
friend class ArrayToPointerExpr;
360+
unsigned : NumImplicitConversionExprBits;
361+
unsigned IsNonAccessing : 1;
362+
};
363+
enum { NumArrayToPointerExprBits = NumImplicitConversionExprBits + 1 };
364+
static_assert(NumArrayToPointerExprBits <= 32, "fits in an unsigned");
365+
350366
class ApplyExprBitfields {
351367
friend class ApplyExpr;
352368
unsigned : NumExprBits;
@@ -434,6 +450,8 @@ class alignas(8) Expr {
434450
CheckedCastExprBitfields CheckedCastExprBits;
435451
CollectionUpcastConversionExprBitfields CollectionUpcastConversionExprBits;
436452
TupleShuffleExprBitfields TupleShuffleExprBits;
453+
InOutToPointerExprBitfields InOutToPointerExprBits;
454+
ArrayToPointerExprBitfields ArrayToPointerExprBits;
437455
ObjCSelectorExprBitfields ObjCSelectorExprBits;
438456
KeyPathExprBitfields KeyPathExprBits;
439457
};
@@ -2745,8 +2763,19 @@ class InjectIntoOptionalExpr : public ImplicitConversionExpr {
27452763
class InOutToPointerExpr : public ImplicitConversionExpr {
27462764
public:
27472765
InOutToPointerExpr(Expr *subExpr, Type ty)
2748-
: ImplicitConversionExpr(ExprKind::InOutToPointer, subExpr, ty) {}
2749-
2766+
: ImplicitConversionExpr(ExprKind::InOutToPointer, subExpr, ty) {
2767+
InOutToPointerExprBits.IsNonAccessing = false;
2768+
}
2769+
2770+
/// Is this conversion "non-accessing"? That is, is it only using the
2771+
/// pointer for its identity, as opposed to actually accessing the memory?
2772+
bool isNonAccessing() const {
2773+
return InOutToPointerExprBits.IsNonAccessing;
2774+
}
2775+
void setNonAccessing(bool nonAccessing = true) {
2776+
InOutToPointerExprBits.IsNonAccessing = nonAccessing;
2777+
}
2778+
27502779
static bool classof(const Expr *E) {
27512780
return E->getKind() == ExprKind::InOutToPointer;
27522781
}
@@ -2756,8 +2785,19 @@ class InOutToPointerExpr : public ImplicitConversionExpr {
27562785
class ArrayToPointerExpr : public ImplicitConversionExpr {
27572786
public:
27582787
ArrayToPointerExpr(Expr *subExpr, Type ty)
2759-
: ImplicitConversionExpr(ExprKind::ArrayToPointer, subExpr, ty) {}
2788+
: ImplicitConversionExpr(ExprKind::ArrayToPointer, subExpr, ty) {
2789+
ArrayToPointerExprBits.IsNonAccessing = false;
2790+
}
27602791

2792+
/// Is this conversion "non-accessing"? That is, is it only using the
2793+
/// pointer for its identity, as opposed to actually accessing the memory?
2794+
bool isNonAccessing() const {
2795+
return ArrayToPointerExprBits.IsNonAccessing;
2796+
}
2797+
void setNonAccessing(bool nonAccessing = true) {
2798+
ArrayToPointerExprBits.IsNonAccessing = nonAccessing;
2799+
}
2800+
27612801
static bool classof(const Expr *E) {
27622802
return E->getKind() == ExprKind::ArrayToPointer;
27632803
}

include/swift/AST/Identifier.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class Identifier {
6868
}
6969

7070
bool empty() const { return Pointer == nullptr; }
71+
72+
bool is(StringRef string) const { return str().equals(string); }
7173

7274
/// isOperator - Return true if this identifier is an operator, false if it is
7375
/// a normal identifier.
@@ -239,7 +241,7 @@ class DeclBaseName {
239241
}
240242

241243
bool operator==(StringRef Str) const {
242-
return !isSpecial() && getIdentifier().str() == Str;
244+
return !isSpecial() && getIdentifier().is(Str);
243245
}
244246
bool operator!=(StringRef Str) const { return !(*this == Str); }
245247

@@ -325,7 +327,7 @@ class DeclName {
325327
MutableArrayRef<Identifier> getArgumentNames() {
326328
return {getTrailingObjects<Identifier>(), NumArgs};
327329
}
328-
330+
329331
/// Uniquing for the ASTContext.
330332
static void Profile(llvm::FoldingSetNodeID &id, DeclBaseName baseName,
331333
ArrayRef<Identifier> argumentNames);
@@ -430,14 +432,16 @@ class DeclName {
430432
/// True if this name is a simple one-component name equal to the
431433
/// given string.
432434
bool isSimpleName(StringRef name) const {
433-
if (!isSimpleName())
434-
return false;
435+
return isSimpleName() && getBaseName() == name;
436+
}
435437

436-
if (getBaseName().isSpecial())
437-
return false;
438+
/// True if this name is a compound name equal to the given base name and
439+
/// argument names.
440+
bool isCompoundName(DeclBaseName base, ArrayRef<StringRef> args) const;
438441

439-
return getBaseIdentifier().str().equals(name);
440-
}
442+
/// True if this name is a compound name equal to the given normal
443+
/// base name and argument names.
444+
bool isCompoundName(StringRef base, ArrayRef<StringRef> args) const;
441445

442446
/// True if this name is an operator.
443447
bool isOperator() const {

lib/AST/ASTDumper.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,12 +2111,14 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
21112111
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21122112
}
21132113
void visitInOutToPointerExpr(InOutToPointerExpr *E) {
2114-
printCommon(E, "inout_to_pointer") << '\n';
2114+
printCommon(E, "inout_to_pointer")
2115+
<< (E->isNonAccessing() ? " nonaccessing" : "") << '\n';
21152116
printRec(E->getSubExpr());
21162117
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21172118
}
21182119
void visitArrayToPointerExpr(ArrayToPointerExpr *E) {
2119-
printCommon(E, "array_to_pointer") << '\n';
2120+
printCommon(E, "array_to_pointer")
2121+
<< (E->isNonAccessing() ? " nonaccessing" : "") << '\n';
21202122
printRec(E->getSubExpr());
21212123
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21222124
}

lib/AST/Identifier.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,30 @@ int DeclName::compare(DeclName other) const {
104104
return argNames.size() < otherArgNames.size() ? -1 : 1;
105105
}
106106

107+
static bool equals(ArrayRef<Identifier> idents, ArrayRef<StringRef> strings) {
108+
if (idents.size() != strings.size())
109+
return false;
110+
for (size_t i = 0, e = idents.size(); i != e; ++i) {
111+
if (!idents[i].is(strings[i]))
112+
return false;
113+
}
114+
return true;
115+
}
116+
117+
bool DeclName::isCompoundName(DeclBaseName baseName,
118+
ArrayRef<StringRef> argNames) const {
119+
return (isCompoundName() &&
120+
getBaseName() == baseName &&
121+
equals(getArgumentNames(), argNames));
122+
}
123+
124+
bool DeclName::isCompoundName(StringRef baseName,
125+
ArrayRef<StringRef> argNames) const {
126+
return (isCompoundName() &&
127+
getBaseName() == baseName &&
128+
equals(getArgumentNames(), argNames));
129+
}
130+
107131
void DeclName::dump() const {
108132
llvm::errs() << *this << "\n";
109133
}

lib/SILGen/LValue.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ class LValue {
396396
void addMemberComponent(SILGenFunction &SGF, SILLocation loc,
397397
AbstractStorageDecl *storage,
398398
SubstitutionList subs,
399+
LValueOptions options,
399400
bool isSuper,
400401
AccessKind accessKind,
401402
AccessSemantics accessSemantics,
@@ -406,6 +407,7 @@ class LValue {
406407
void addMemberVarComponent(SILGenFunction &SGF, SILLocation loc,
407408
VarDecl *var,
408409
SubstitutionList subs,
410+
LValueOptions options,
409411
bool isSuper,
410412
AccessKind accessKind,
411413
AccessSemantics accessSemantics,
@@ -415,6 +417,7 @@ class LValue {
415417
void addMemberSubscriptComponent(SILGenFunction &SGF, SILLocation loc,
416418
SubscriptDecl *subscript,
417419
SubstitutionList subs,
420+
LValueOptions options,
418421
bool isSuper,
419422
AccessKind accessKind,
420423
AccessSemantics accessSemantics,

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,7 +2826,10 @@ class ArgEmitter {
28262826
bool emitDelayedConversion(InOutToPointerExpr *pointerExpr,
28272827
OriginalArgument original) {
28282828
auto info = SGF.getPointerAccessInfo(pointerExpr->getType());
2829-
LValue lv = SGF.emitLValue(pointerExpr->getSubExpr(), info.AccessKind);
2829+
LValueOptions options;
2830+
options.IsNonAccessing = pointerExpr->isNonAccessing();
2831+
LValue lv = SGF.emitLValue(pointerExpr->getSubExpr(), info.AccessKind,
2832+
options);
28302833
DelayedArguments.emplace_back(info, std::move(lv), pointerExpr, original);
28312834
Args.push_back(ManagedValue());
28322835
return true;
@@ -2841,7 +2844,9 @@ class ArgEmitter {
28412844
if (auto inoutType = arrayExpr->getType()->getAs<InOutType>()) {
28422845
auto info = SGF.getArrayAccessInfo(pointerExpr->getType(),
28432846
inoutType->getObjectType());
2844-
LValue lv = SGF.emitLValue(arrayExpr, info.AccessKind);
2847+
LValueOptions options;
2848+
options.IsNonAccessing = pointerExpr->isNonAccessing();
2849+
LValue lv = SGF.emitLValue(arrayExpr, info.AccessKind, options);
28452850
DelayedArguments.emplace_back(info, std::move(lv), pointerExpr,
28462851
original);
28472852
Args.push_back(ManagedValue());

lib/SILGen/SILGenConstructor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ static LValue emitLValueForMemberInit(SILGenFunction &SGF, SILLocation loc,
765765
->getInOutObjectType()->getCanonicalType();
766766
auto self = emitSelfForMemberInit(SGF, loc, selfDecl);
767767
return SGF.emitPropertyLValue(loc, self, selfFormalType, property,
768-
AccessKind::Write,
768+
LValueOptions(), AccessKind::Write,
769769
AccessSemantics::DirectToStorage);
770770
}
771771

lib/SILGen/SILGenExpr.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ RValue SILGenFunction::emitRValueForPropertyLoad(
962962
// If the base is a reference type, just handle this as loading the lvalue.
963963
if (baseFormalType->hasReferenceSemantics()) {
964964
LValue LV = emitPropertyLValue(loc, base, baseFormalType, field,
965-
AccessKind::Read,
965+
LValueOptions(), AccessKind::Read,
966966
AccessSemantics::DirectToStorage);
967967
return emitLoadOfLValue(loc, std::move(LV), C, isGuaranteedValid);
968968
}
@@ -2673,10 +2673,11 @@ SILFunction *getOrCreateKeyPathSetter(SILGenFunction &SGF,
26732673
SmallVector<Substitution, 4> subsList;
26742674
if (subs.getGenericSignature())
26752675
subs.getGenericSignature()->getSubstitutions(subs, subsList);
2676-
2677-
lv.addMemberVarComponent(subSGF, loc, property, subsList, /*super*/ false,
2678-
AccessKind::Write, AccessSemantics::Ordinary,
2679-
strategy, propertyType);
2676+
2677+
LValueOptions lvOptions;
2678+
lv.addMemberVarComponent(subSGF, loc, property, subsList, lvOptions,
2679+
/*super*/ false, AccessKind::Write,
2680+
AccessSemantics::Ordinary, strategy, propertyType);
26802681

26812682
subSGF.emitAssignToLValue(loc,
26822683
RValue(subSGF, loc, propertyType, valueSubst),

lib/SILGen/SILGenForeignError.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ static void emitStoreToForeignErrorSlot(SILGenFunction &gen,
100100
LValue lvalue =
101101
gen.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot),
102102
bridgedErrorPtrType, pointeeProperty,
103+
LValueOptions(),
103104
AccessKind::Write,
104105
AccessSemantics::Ordinary);
105106
RValue rvalue(gen, loc, bridgedErrorProto,

lib/SILGen/SILGenFunction.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,28 @@ inline ApplyOptions &operator-=(ApplyOptions &lhs, ApplyOptions rhs) {
197197
return (lhs = (lhs - rhs));
198198
}
199199

200+
struct LValueOptions {
201+
bool IsNonAccessing = false;
202+
203+
/// Derive options for accessing the base of an l-value, given that
204+
/// applying the derived component might touch the memory.
205+
LValueOptions forComputedBaseLValue() const {
206+
auto copy = *this;
207+
208+
// Assume we're going to access the base.
209+
copy.IsNonAccessing = false;
210+
211+
return copy;
212+
}
213+
214+
/// Derive options for accessing the base of an l-value, given that
215+
/// applying the derived component will not touch the memory.
216+
LValueOptions forProjectedBaseLValue() const {
217+
auto copy = *this;
218+
return copy;
219+
}
220+
};
221+
200222
class PatternMatchContext;
201223

202224
/// A formal section of the function. This is a SILGen-only concept,
@@ -1740,7 +1762,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
17401762
ExistentialRepresentation repr);
17411763

17421764
/// Evaluate an Expr as an lvalue.
1743-
LValue emitLValue(Expr *E, AccessKind accessKind);
1765+
LValue emitLValue(Expr *E, AccessKind accessKind,
1766+
LValueOptions options = LValueOptions());
17441767

17451768
/// Emit a reference to a variable as an lvalue.
17461769
LValue emitLValueForAddressedNonMemberVarDecl(SILLocation loc, VarDecl *var,
@@ -1752,6 +1775,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
17521775
/// (without going through getters or setters).
17531776
LValue emitPropertyLValue(SILLocation loc, ManagedValue base,
17541777
CanType baseFormalType, VarDecl *var,
1778+
LValueOptions options,
17551779
AccessKind accessKind, AccessSemantics semantics);
17561780

17571781
struct PointerAccessInfo {

0 commit comments

Comments
 (0)