Merge pull request #16512 from nkcsgexi/cherry-migrator-05-10
[4.2] cherry-pick migrator changes
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index d17c66d..7890a9b 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -670,10 +670,11 @@
BeginAccessInst *createBeginAccess(SILLocation loc, SILValue address,
SILAccessKind accessKind,
SILAccessEnforcement enforcement,
- bool noNestedConflict) {
+ bool noNestedConflict,
+ bool fromBuiltin) {
return insert(new (getModule()) BeginAccessInst(
getSILDebugLocation(loc), address, accessKind, enforcement,
- noNestedConflict));
+ noNestedConflict, fromBuiltin));
}
EndAccessInst *createEndAccess(SILLocation loc, SILValue address,
@@ -686,18 +687,19 @@
createBeginUnpairedAccess(SILLocation loc, SILValue address, SILValue buffer,
SILAccessKind accessKind,
SILAccessEnforcement enforcement,
- bool noNestedConflict) {
+ bool noNestedConflict,
+ bool fromBuiltin) {
return insert(new (getModule()) BeginUnpairedAccessInst(
getSILDebugLocation(loc), address, buffer, accessKind, enforcement,
- noNestedConflict));
+ noNestedConflict, fromBuiltin));
}
- EndUnpairedAccessInst *createEndUnpairedAccess(SILLocation loc,
- SILValue buffer,
- SILAccessEnforcement enforcement,
- bool aborted) {
+ EndUnpairedAccessInst *
+ createEndUnpairedAccess(SILLocation loc, SILValue buffer,
+ SILAccessEnforcement enforcement, bool aborted,
+ bool fromBuiltin) {
return insert(new (getModule()) EndUnpairedAccessInst(
- getSILDebugLocation(loc), buffer, enforcement, aborted));
+ getSILDebugLocation(loc), buffer, enforcement, aborted, fromBuiltin));
}
AssignInst *createAssign(SILLocation Loc, SILValue Src, SILValue DestAddr) {
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index cfe18d2..643df68 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -792,7 +792,8 @@
getOpValue(Inst->getOperand()),
Inst->getAccessKind(),
Inst->getEnforcement(),
- Inst->hasNoNestedConflict()));
+ Inst->hasNoNestedConflict(),
+ Inst->isFromBuiltin()));
}
template <typename ImplClass>
@@ -814,18 +815,19 @@
getOpValue(Inst->getBuffer()),
Inst->getAccessKind(),
Inst->getEnforcement(),
- Inst->hasNoNestedConflict()));
+ Inst->hasNoNestedConflict(),
+ Inst->isFromBuiltin()));
}
template <typename ImplClass>
void SILCloner<ImplClass>::visitEndUnpairedAccessInst(
EndUnpairedAccessInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
- doPostProcess(
- Inst, getBuilder().createEndUnpairedAccess(getOpLocation(Inst->getLoc()),
- getOpValue(Inst->getOperand()),
- Inst->getEnforcement(),
- Inst->isAborting()));
+ doPostProcess(Inst,
+ getBuilder().createEndUnpairedAccess(
+ getOpLocation(Inst->getLoc()),
+ getOpValue(Inst->getOperand()), Inst->getEnforcement(),
+ Inst->isAborting(), Inst->isFromBuiltin()));
}
template <typename ImplClass>
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 24078a2..4d511aa 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -3258,12 +3258,14 @@
BeginAccessInst(SILDebugLocation loc, SILValue lvalue,
SILAccessKind accessKind, SILAccessEnforcement enforcement,
- bool noNestedConflict)
+ bool noNestedConflict, bool fromBuiltin)
: UnaryInstructionBase(loc, lvalue, lvalue->getType()) {
SILInstruction::Bits.BeginAccessInst.AccessKind = unsigned(accessKind);
SILInstruction::Bits.BeginAccessInst.Enforcement = unsigned(enforcement);
SILInstruction::Bits.BeginAccessInst.NoNestedConflict =
unsigned(noNestedConflict);
+ SILInstruction::Bits.BeginAccessInst.FromBuiltin =
+ unsigned(fromBuiltin);
static_assert(unsigned(SILAccessKind::Last) < (1 << 2),
"reserve sufficient bits for serialized SIL");
@@ -3307,6 +3309,13 @@
SILInstruction::Bits.BeginAccessInst.NoNestedConflict = noNestedConflict;
}
+ /// Return true if this access marker was emitted for a user-controlled
+ /// Builtin. Return false if this access marker was auto-generated by the
+ /// compiler to enforce formal access that derives from the language.
+ bool isFromBuiltin() const {
+ return SILInstruction::Bits.BeginAccessInst.FromBuiltin;
+ }
+
SILValue getSource() const {
return getOperand();
}
@@ -3387,7 +3396,8 @@
BeginUnpairedAccessInst(SILDebugLocation loc, SILValue addr, SILValue buffer,
SILAccessKind accessKind,
SILAccessEnforcement enforcement,
- bool noNestedConflict)
+ bool noNestedConflict,
+ bool fromBuiltin)
: InstructionBase(loc), Operands(this, addr, buffer) {
SILInstruction::Bits.BeginUnpairedAccessInst.AccessKind =
unsigned(accessKind);
@@ -3395,6 +3405,8 @@
unsigned(enforcement);
SILInstruction::Bits.BeginUnpairedAccessInst.NoNestedConflict =
unsigned(noNestedConflict);
+ SILInstruction::Bits.BeginUnpairedAccessInst.FromBuiltin =
+ unsigned(fromBuiltin);
}
public:
@@ -3429,6 +3441,13 @@
noNestedConflict;
}
+ /// Return true if this access marker was emitted for a user-controlled
+ /// Builtin. Return false if this access marker was auto-generated by the
+ /// compiler to enforce formal access that derives from the language.
+ bool isFromBuiltin() const {
+ return SILInstruction::Bits.BeginUnpairedAccessInst.FromBuiltin;
+ }
+
SILValue getSource() const {
return Operands[0].get();
}
@@ -3457,11 +3476,13 @@
private:
EndUnpairedAccessInst(SILDebugLocation loc, SILValue buffer,
- SILAccessEnforcement enforcement, bool aborting = false)
+ SILAccessEnforcement enforcement, bool aborting,
+ bool fromBuiltin)
: UnaryInstructionBase(loc, buffer) {
SILInstruction::Bits.EndUnpairedAccessInst.Enforcement
= unsigned(enforcement);
SILInstruction::Bits.EndUnpairedAccessInst.Aborting = aborting;
+ SILInstruction::Bits.EndUnpairedAccessInst.FromBuiltin = fromBuiltin;
}
public:
@@ -3487,6 +3508,13 @@
unsigned(enforcement);
}
+ /// Return true if this access marker was emitted for a user-controlled
+ /// Builtin. Return false if this access marker was auto-generated by the
+ /// compiler to enforce formal access that derives from the language.
+ bool isFromBuiltin() const {
+ return SILInstruction::Bits.EndUnpairedAccessInst.FromBuiltin;
+ }
+
SILValue getBuffer() const {
return getOperand();
}
diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h
index e0c7340..7138e82 100644
--- a/include/swift/SIL/SILNode.h
+++ b/include/swift/SIL/SILNode.h
@@ -263,24 +263,28 @@
SWIFT_INLINE_BITFIELD(BeginAccessInst, SingleValueInstruction,
NumSILAccessKindBits+NumSILAccessEnforcementBits
- + 1,
+ + 1 + 1,
AccessKind : NumSILAccessKindBits,
Enforcement : NumSILAccessEnforcementBits,
- NoNestedConflict : 1
+ NoNestedConflict : 1,
+ FromBuiltin : 1
);
SWIFT_INLINE_BITFIELD(BeginUnpairedAccessInst, NonValueInstruction,
- NumSILAccessKindBits + NumSILAccessEnforcementBits + 1,
+ NumSILAccessKindBits + NumSILAccessEnforcementBits
+ + 1 + 1,
AccessKind : NumSILAccessKindBits,
Enforcement : NumSILAccessEnforcementBits,
- NoNestedConflict : 1);
+ NoNestedConflict : 1,
+ FromBuiltin : 1);
SWIFT_INLINE_BITFIELD(EndAccessInst, NonValueInstruction, 1,
Aborting : 1
);
SWIFT_INLINE_BITFIELD(EndUnpairedAccessInst, NonValueInstruction,
- NumSILAccessEnforcementBits + 1,
+ NumSILAccessEnforcementBits + 1 + 1,
Enforcement : NumSILAccessEnforcementBits,
- Aborting : 1);
+ Aborting : 1,
+ FromBuiltin : 1);
SWIFT_INLINE_BITFIELD(StoreInst, NonValueInstruction,
NumStoreOwnershipQualifierBits,
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index 0918b71..eda81fe 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -367,17 +367,6 @@
/// pointer.
bool isPointerSizeAndAligned();
- /// Return true if the layout of `toType` is an ABI compatible prefix of
- /// `fromType` ignoring reference types. `fromType` may be larger than
- /// `toType` and still be unsafe castable. `fromType` may contain references
- /// in positions where `toType` does not contain references and still be
- /// unsafe castable. This is used solely to determine whether an address cast
- /// can be promoted to a cast between aggregates of scalar values without
- /// confusing IRGen.
- static bool canPerformABICompatibleUnsafeCastValue(SILType fromType,
- SILType toType,
- SILModule &M);
-
/// True if `operTy` can be cast by single-reference value into `resultTy`.
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 1ae4bd0..562aa69 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -55,7 +55,7 @@
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t VERSION_MINOR = 411; // Last change: copy_block_without_escaping
+const uint16_t VERSION_MINOR = 412; // Last change: add begin_access [builtin].
using DeclIDField = BCFixed<31>;
diff --git a/include/swift/Strings.h b/include/swift/Strings.h
index 38a687a..4d02d9d 100644
--- a/include/swift/Strings.h
+++ b/include/swift/Strings.h
@@ -13,9 +13,6 @@
#ifndef SWIFT_STRINGS_H
#define SWIFT_STRINGS_H
-#include "swift/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
-
namespace swift {
/// The extension for serialized modules.
@@ -92,10 +89,6 @@
constexpr static const char BUILTIN_TYPE_NAME_SILTOKEN[] = "Builtin.SILToken";
/// The name of the Builtin type for Word
constexpr static const char BUILTIN_TYPE_NAME_WORD[] = "Builtin.Word";
-
-constexpr static StringLiteral OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY =
- "optimize.sil.preserve_exclusivity";
-
} // end namespace swift
#endif // SWIFT_STRINGS_H
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index b4fe9d4..1baba4a 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -4228,11 +4228,12 @@
static ExclusivityFlags getExclusivityFlags(SILModule &M,
SILAccessKind kind,
- bool noNestedConflict) {
+ bool noNestedConflict,
+ bool fromBuiltin) {
auto flags = getExclusivityAction(kind);
// In old Swift compatibility modes, downgrade this to a warning.
- if (M.getASTContext().LangOpts.isSwiftVersion3())
+ if (!fromBuiltin && M.getASTContext().LangOpts.isSwiftVersion3())
flags |= ExclusivityFlags::WarningOnly;
if (!noNestedConflict)
@@ -4264,7 +4265,7 @@
template <class BeginAccessInst>
static ExclusivityFlags getExclusivityFlags(BeginAccessInst *i) {
return getExclusivityFlags(i->getModule(), i->getAccessKind(),
- i->hasNoNestedConflict());
+ i->hasNoNestedConflict(), i->isFromBuiltin());
}
void IRGenSILFunction::visitBeginAccessInst(BeginAccessInst *access) {
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index 02b2b60..73bb33f 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -2087,7 +2087,8 @@
auto *convInstr = cast<BeginAccessInst>(instr);
newInstr = resultTyBuilder.createBeginAccess(
Loc, convInstr->getOperand(), convInstr->getAccessKind(),
- convInstr->getEnforcement(), convInstr->hasNoNestedConflict());
+ convInstr->getEnforcement(), convInstr->hasNoNestedConflict(),
+ convInstr->isFromBuiltin());
break;
}
case SILInstructionKind::EnumInst: {
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index 0deae67..9500bf9 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -3434,6 +3434,7 @@
ParsedEnum<SILAccessEnforcement> enforcement;
ParsedEnum<bool> aborting;
ParsedEnum<bool> noNestedConflict;
+ ParsedEnum<bool> fromBuiltin;
bool isBeginAccess = (Opcode == SILInstructionKind::BeginAccessInst ||
Opcode == SILInstructionKind::BeginUnpairedAccessInst);
@@ -3465,6 +3466,10 @@
auto setNoNestedConflict = [&](bool value) {
maybeSetEnum(isBeginAccess, noNestedConflict, value, attr, identLoc);
};
+ auto setFromBuiltin = [&](bool value) {
+ maybeSetEnum(Opcode != SILInstructionKind::EndAccessInst, fromBuiltin,
+ value, attr, identLoc);
+ };
if (attr == "unknown") {
setEnforcement(SILAccessEnforcement::Unknown);
@@ -3486,6 +3491,8 @@
setAborting(true);
} else if (attr == "no_nested_conflict") {
setNoNestedConflict(true);
+ } else if (attr == "builtin") {
+ setFromBuiltin(true);
} else {
P.diagnose(identLoc, diag::unknown_attribute, attr);
}
@@ -3510,6 +3517,9 @@
if (isBeginAccess && !noNestedConflict.isSet())
noNestedConflict.Value = false;
+ if (!fromBuiltin.isSet())
+ fromBuiltin.Value = false;
+
SILValue addrVal;
SourceLoc addrLoc;
if (parseTypedValueRef(addrVal, addrLoc, B))
@@ -3534,16 +3544,16 @@
if (Opcode == SILInstructionKind::BeginAccessInst) {
ResultVal =
B.createBeginAccess(InstLoc, addrVal, *kind, *enforcement,
- *noNestedConflict);
+ *noNestedConflict, *fromBuiltin);
} else if (Opcode == SILInstructionKind::EndAccessInst) {
ResultVal = B.createEndAccess(InstLoc, addrVal, *aborting);
} else if (Opcode == SILInstructionKind::BeginUnpairedAccessInst) {
ResultVal = B.createBeginUnpairedAccess(InstLoc, addrVal, bufferVal,
*kind, *enforcement,
- *noNestedConflict);
+ *noNestedConflict, *fromBuiltin);
} else {
- ResultVal = B.createEndUnpairedAccess(InstLoc, addrVal,
- *enforcement, *aborting);
+ ResultVal = B.createEndUnpairedAccess(InstLoc, addrVal, *enforcement,
+ *aborting, *fromBuiltin);
}
break;
}
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index 75732df..880dae3 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -388,7 +388,8 @@
auto left = cast<BeginAccessInst>(LHS);
return left->getAccessKind() == right->getAccessKind()
&& left->getEnforcement() == right->getEnforcement()
- && left->hasNoNestedConflict() == right->hasNoNestedConflict();
+ && left->hasNoNestedConflict() == right->hasNoNestedConflict()
+ && left->isFromBuiltin() == right->isFromBuiltin();
}
bool visitEndAccessInst(const EndAccessInst *right) {
@@ -400,13 +401,15 @@
auto left = cast<BeginUnpairedAccessInst>(LHS);
return left->getAccessKind() == right->getAccessKind()
&& left->getEnforcement() == right->getEnforcement()
- && left->hasNoNestedConflict() == right->hasNoNestedConflict();
+ && left->hasNoNestedConflict() == right->hasNoNestedConflict()
+ && left->isFromBuiltin() == right->isFromBuiltin();
}
bool visitEndUnpairedAccessInst(const EndUnpairedAccessInst *right) {
auto left = cast<EndUnpairedAccessInst>(LHS);
return left->getEnforcement() == right->getEnforcement()
- && left->isAborting() == right->isAborting();
+ && left->isAborting() == right->isAborting()
+ && left->isFromBuiltin() == right->isFromBuiltin();
}
bool visitStrongReleaseInst(const StrongReleaseInst *RHS) {
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 551da90..95b5e05 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1842,6 +1842,7 @@
*this << '[' << getSILAccessKindName(BAI->getAccessKind()) << "] ["
<< getSILAccessEnforcementName(BAI->getEnforcement()) << "] "
<< (BAI->hasNoNestedConflict() ? "[no_nested_conflict] " : "")
+ << (BAI->isFromBuiltin() ? "[builtin] " : "")
<< getIDAndType(BAI->getOperand());
}
void visitEndAccessInst(EndAccessInst *EAI) {
@@ -1852,12 +1853,14 @@
*this << '[' << getSILAccessKindName(BAI->getAccessKind()) << "] ["
<< getSILAccessEnforcementName(BAI->getEnforcement()) << "] "
<< (BAI->hasNoNestedConflict() ? "[no_nested_conflict] " : "")
+ << (BAI->isFromBuiltin() ? "[builtin] " : "")
<< getIDAndType(BAI->getSource()) << ", "
<< getIDAndType(BAI->getBuffer());
}
void visitEndUnpairedAccessInst(EndUnpairedAccessInst *EAI) {
- *this << (EAI->isAborting() ? "[abort] " : "")
- << '[' << getSILAccessEnforcementName(EAI->getEnforcement()) << "] "
+ *this << (EAI->isAborting() ? "[abort] " : "") << '['
+ << getSILAccessEnforcementName(EAI->getEnforcement()) << "] "
+ << (EAI->isFromBuiltin() ? "[builtin] " : "")
<< getIDAndType(EAI->getOperand());
}
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index 2bfb8e7..e2160c5 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -110,193 +110,6 @@
return false;
}
-// Allow casting a struct by value when all elements in toType correspond to
-// an element of the same size or larger laid out in the same order in
-// fromType. The assumption is that if fromType has larger elements, or
-// additional elements, their presence cannot induce a more compact layout of
-// the overlapping elements.
-//
-// struct {A, B} -> A is castable
-// struct {A, B, C} -> struct {A, B} is castable
-// struct { struct {A, B}, C} -> struct {A, B} is castable
-// struct { A, B, C} -> struct { struct {A, B}, C} is NOT castable
-//
-// FIXME: This is unnecessarily conservative given the current ABI
-// (TypeLayout.rst). It would be simpler to flatten both `from` and `to` types,
-// exploding all structs and tuples, then trivially check if `to` is a prefix.
-static bool canUnsafeCastStruct(SILType fromType, StructDecl *fromStruct,
- SILType toType, SILModule &M) {
- auto fromRange = fromStruct->getStoredProperties();
- if (fromRange.begin() == fromRange.end())
- return false;
-
- // Can the first element of fromStruct be cast by value into toType?
- SILType fromEltTy = fromType.getFieldType(*fromRange.begin(), M);
- if (SILType::canPerformABICompatibleUnsafeCastValue(fromEltTy, toType, M))
- return true;
-
- // Otherwise, flatten one level of struct elements on each side.
- StructDecl *toStruct = toType.getStructOrBoundGenericStruct();
- if (!toStruct)
- return false;
-
- auto toRange = toStruct->getStoredProperties();
- for (auto toI = toRange.begin(), toE = toRange.end(),
- fromI = fromRange.begin(), fromE = fromRange.end();
- toI != toE; ++toI, ++fromI) {
-
- if (fromI == fromE)
- return false; // fromType is a struct with fewer elements.
-
- SILType fromEltTy = fromType.getFieldType(*fromI, M);
- SILType toEltTy = toType.getFieldType(*toI, M);
- if (!SILType::canPerformABICompatibleUnsafeCastValue(fromEltTy, toEltTy, M))
- return false;
- }
- // fromType's overlapping elements are compatible.
- return true;
-}
-
-// Allow casting a tuple by value when all elements in toType correspond to an
-// element of the same size or larger in fromType in the same order.
-static bool canUnsafeCastTuple(SILType fromType, CanTupleType fromTupleTy,
- SILType toType, SILModule &M) {
- unsigned numFromElts = fromTupleTy->getNumElements();
- // Can the first element of fromTupleTy be cast by value into toType?
- if (numFromElts != 0
- && SILType::canPerformABICompatibleUnsafeCastValue(
- fromType.getTupleElementType(0), toType, M)) {
- return true;
- }
- // Otherwise, flatten one level of tuple elements on each side.
- auto toTupleTy = dyn_cast<TupleType>(toType.getSwiftRValueType());
- if (!toTupleTy)
- return false;
-
- unsigned numToElts = toTupleTy->getNumElements();
- if (numFromElts < numToElts)
- return false;
-
- for (unsigned i = 0; i != numToElts; ++i) {
- if (!SILType::canPerformABICompatibleUnsafeCastValue(
- fromType.getTupleElementType(i), toType.getTupleElementType(i),
- M)) {
- return false;
- }
- }
- return true;
-}
-
-// Allow casting an enum by value when toType is an enum and each elements is
-// individually castable to toType. An enum cannot be smaller than its payload.
-static bool canUnsafeCastEnum(SILType fromType, EnumDecl *fromEnum,
- SILType toType, SILModule &M) {
- unsigned numToElements = 0;
- SILType toElementTy;
- if (EnumDecl *toEnum = toType.getEnumOrBoundGenericEnum()) {
- for (auto toElement : toEnum->getAllElements()) {
- ++numToElements;
- if (!toElement->hasAssociatedValues())
- continue;
- // Bail on multiple payloads.
- if (!toElementTy.isNull())
- return false;
- toElementTy = toType.getEnumElementType(toElement, M);
- }
- } else {
- // If toType is not an enum, handle it like a singleton
- numToElements = 1;
- toElementTy = toType;
- }
- // If toType has more elements, it may be larger.
- auto fromElements = fromEnum->getAllElements();
- if (static_cast<ptrdiff_t>(numToElements) >
- std::distance(fromElements.begin(), fromElements.end()))
- return false;
-
- if (toElementTy.isNull())
- return true;
-
- // If any of the fromElements can be cast by value to the singleton toElement,
- // then the overall enum can be cast by value.
- for (auto fromElement : fromElements) {
- if (!fromElement->hasAssociatedValues())
- continue;
-
- auto fromElementTy = fromType.getEnumElementType(fromElement, M);
- if (SILType::canPerformABICompatibleUnsafeCastValue(fromElementTy,
- toElementTy, M))
- return true;
- }
- return false;
-}
-
-static bool canUnsafeCastScalars(SILType fromType, SILType toType,
- SILModule &M) {
- CanType fromCanTy = fromType.getSwiftRValueType();
- bool isToPointer = toType.isPointerSizeAndAligned();
-
- unsigned LeastFromWidth = 0;
- // Like UnsafeRefBitCast, allow class existentials to be truncated to
- // single-pointer references. Unlike UnsafeRefBitCast, this also supports raw
- // pointers and words.
- if (fromType.isPointerSizeAndAligned()
- || fromCanTy.isAnyClassReferenceType()) {
-
- // Allow casting from a value that contains an aligned pointer into another
- // pointer value regardless of the fixed width.
- if (isToPointer)
- return true;
-
- LeastFromWidth = BuiltinIntegerWidth::pointer().getLeastWidth();
-
- } else if (auto fromIntTy = dyn_cast<BuiltinIntegerType>(fromCanTy)) {
- if (fromIntTy->isFixedWidth())
- LeastFromWidth = fromIntTy->getFixedWidth();
- }
-
- unsigned GreatestToWidth = UINT_MAX;
- if (isToPointer) {
- GreatestToWidth = BuiltinIntegerWidth::pointer().getGreatestWidth();
-
- } else if (auto toIntTy = dyn_cast<BuiltinIntegerType>(
- toType.getSwiftRValueType())) {
- if (toIntTy->isFixedWidth())
- GreatestToWidth = toIntTy->getFixedWidth();
- }
- return LeastFromWidth >= GreatestToWidth;
-}
-
-bool SILType::canPerformABICompatibleUnsafeCastValue(SILType fromType,
- SILType toType,
- SILModule &M) {
- if (fromType == toType)
- return true;
-
- // Unwrap single element structs.
- if (StructDecl *toStruct = toType.getStructOrBoundGenericStruct()) {
- auto toRange = toStruct->getStoredProperties();
- if (toRange.begin() != toRange.end()
- && std::next(toRange.begin()) == toRange.end()) {
- toType = toType.getFieldType(*toRange.begin(), M);
- }
- }
- if (canUnsafeCastScalars(fromType, toType, M))
- return true;
-
- if (StructDecl *fromStruct = fromType.getStructOrBoundGenericStruct())
- return canUnsafeCastStruct(fromType, fromStruct, toType, M);
-
- if (CanTupleType fromTupleTy =
- dyn_cast<TupleType>(fromType.getSwiftRValueType())) {
- return canUnsafeCastTuple(fromType, fromTupleTy, toType, M);
- }
- if (EnumDecl *fromEnum = fromType.getEnumOrBoundGenericEnum())
- return canUnsafeCastEnum(fromType, fromEnum, toType, M);
-
- return false;
-}
-
// Reference cast from representations with single pointer low bits.
// Only reference cast to simple single pointer representations.
//
diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp
index aa72932..781e3d7 100644
--- a/lib/SILGen/SILGenBuiltin.cpp
+++ b/lib/SILGen/SILGenBuiltin.cpp
@@ -581,7 +581,8 @@
/*invariant*/ false);
SGF.B.createBeginUnpairedAccess(loc, addr, buffer, SILAccessKind::Modify,
SILAccessEnforcement::Dynamic,
- /*noNestedConflict*/ false);
+ /*noNestedConflict*/ false,
+ /*fromBuiltin*/ true);
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
}
@@ -617,7 +618,8 @@
// use will be trivially optimized away.
SGF.B.createBeginUnpairedAccess(loc, addr, unusedBuffer, SILAccessKind::Read,
SILAccessEnforcement::Dynamic,
- /*noNestedConflict*/ true);
+ /*noNestedConflict*/ true,
+ /*fromBuiltin*/ true);
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
}
@@ -641,7 +643,8 @@
/*strict*/ true,
/*invariant*/ false);
SGF.B.createEndUnpairedAccess(loc, buffer, SILAccessEnforcement::Dynamic,
- /*aborted*/ false);
+ /*aborted*/ false,
+ /*fromBuiltin*/ true);
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
}
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 5d81218..ac89fd4 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -466,7 +466,8 @@
if (enforcement == SILAccessEnforcement::Dynamic) {
SGF.B.createBeginUnpairedAccess(loc, addr, unpairedAccesses->Buffer,
silAccessKind, enforcement,
- /*hasNoNestedConflict=*/false);
+ /*hasNoNestedConflict=*/false,
+ /*fromBuiltin=*/false);
unpairedAccesses->NumAccesses++;
}
return addr;
@@ -474,7 +475,8 @@
// Enter the access.
addr = SGF.B.createBeginAccess(loc, addr, silAccessKind, enforcement,
- /*hasNoNestedConflict=*/false);
+ /*hasNoNestedConflict=*/false,
+ /*fromBuiltin=*/false);
// Push a writeback to end it.
auto accessedMV = ManagedValue::forLValue(addr);
@@ -508,7 +510,8 @@
auto BAI =
SGF.B.createBeginAccess(loc, address, kind, SILAccessEnforcement::Unsafe,
- /*hasNoNestedConflict=*/false);
+ /*hasNoNestedConflict=*/false,
+ /*fromBuiltin=*/false);
beginAccessPtr = BeginAccessPtr(BAI, DeleterCheck());
return BAI;
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index b1dac7e..ea6d9f2 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -794,7 +794,8 @@
"multiple unpaired accesses not supported");
SGF.B.createEndUnpairedAccess(loc, callbackStorage,
SILAccessEnforcement::Dynamic,
- /*aborting*/ false);
+ /*aborting*/ false,
+ /*fromBuiltin*/ false);
});
}
diff --git a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
index 60e1797..6f353d3 100644
--- a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
+++ b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
@@ -31,7 +31,6 @@
#include "swift/Basic/Range.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
-#include "swift/Strings.h"
#include "llvm/Support/CommandLine.h"
using namespace swift;
@@ -112,6 +111,12 @@
// updated the SIL, short of erasing the marker itself, and return true.
bool AccessMarkerElimination::checkAndEliminateMarker(SILInstruction *inst) {
if (auto beginAccess = dyn_cast<BeginAccessInst>(inst)) {
+ // Builtins used by the standard library must emit markers regardless of the
+ // current compiler options so that any user code that initiates access via
+ // the standard library is fully enforced.
+ if (beginAccess->isFromBuiltin())
+ return false;
+
// Leave dynamic accesses in place, but delete all others.
if (shouldPreserveAccess(beginAccess->getEnforcement()))
return false;
@@ -126,6 +131,11 @@
// begin_unpaired_access instructions will be directly removed and
// simply replaced with their operand.
if (auto BUA = dyn_cast<BeginUnpairedAccessInst>(inst)) {
+ // Builtins used by the standard library must emit markers regardless of the
+ // current compiler options.
+ if (BUA->isFromBuiltin())
+ return false;
+
if (shouldPreserveAccess(BUA->getEnforcement()))
return false;
@@ -134,6 +144,11 @@
// end_unpaired_access instructions will be directly removed and
// simply replaced with their operand.
if (auto EUA = dyn_cast<EndUnpairedAccessInst>(inst)) {
+ // Builtins used by the standard library must emit markers regardless of the
+ // current compiler options.
+ if (EUA->isFromBuiltin())
+ return false;
+
if (shouldPreserveAccess(EUA->getEnforcement()))
return false;
@@ -174,12 +189,6 @@
void run() override {
auto &M = *getModule();
for (auto &F : M) {
- if (F.hasSemanticsAttr(OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY)) {
- DEBUG(llvm::dbgs() << "Skipping " << F.getName() << ". Found "
- << OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY << " tag!\n");
- continue;
- }
-
bool removedAny = AccessMarkerElimination(&F).stripMarkers();
// Only invalidate analyses if we removed some markers.
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
index b2c65d6..d857567 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
@@ -208,68 +208,7 @@
return Builder.createUpcast(UADCI->getLoc(), UADCI->getOperand(),
UADCI->getType());
- // See if we have all loads from this unchecked_addr_cast. If we do, load the
- // original type and create the appropriate bitcast.
-
- // First if our UADCI has not users, bail. This will be eliminated by DCE.
- if (UADCI->use_empty())
- return nullptr;
-
- SILType InputTy = UADCI->getOperand()->getType();
- SILType OutputTy = UADCI->getType();
-
- // If either type is address only, do not do anything here.
- if (InputTy.isAddressOnly(Mod) || OutputTy.isAddressOnly(Mod))
- return nullptr;
-
- bool InputIsTrivial = InputTy.isTrivial(Mod);
- bool OutputIsTrivial = OutputTy.isTrivial(Mod);
-
- // If our input is trivial and our output type is not, do not do
- // anything. This is to ensure that we do not change any types reference
- // semantics from trivial -> reference counted.
- if (InputIsTrivial && !OutputIsTrivial)
- return nullptr;
-
- // Check that the input type can be value cast to the output type. It is
- // possible to cast the address of a smaller InputType to the address of a
- // larger OutputType (the actual memory object must be large enough to hold
- // both types). However, such address casts cannot be converted to value
- // casts.
- if (!SILType::canPerformABICompatibleUnsafeCastValue(InputTy, OutputTy,
- UADCI->getModule())) {
- return nullptr;
- }
- // For each user U of the unchecked_addr_cast...
- for (auto U : getNonDebugUses(UADCI))
- // Check if it is load. If it is not a load, bail...
- if (!isa<LoadInst>(U->getUser()))
- return nullptr;
-
- SILValue Op = UADCI->getOperand();
- SILLocation Loc = UADCI->getLoc();
-
- // Ok, we have all loads. Lets simplify this. Go back through the loads a
- // second time, rewriting them into a load + bitcast from our source.
- auto UsesRange = getNonDebugUses(UADCI);
- for (auto UI = UsesRange.begin(), E = UsesRange.end(); UI != E;) {
- // Grab the original load.
- LoadInst *L = cast<LoadInst>(UI->getUser());
- UI++;
-
- // Insert a new load from our source and bitcast that as appropriate.
- LoadInst *NewLoad =
- Builder.createLoad(Loc, Op, LoadOwnershipQualifier::Unqualified);
- auto *BitCast = Builder.createUncheckedBitCast(Loc, NewLoad,
- OutputTy.getObjectType());
- // Replace all uses of the old load with the new bitcasted result and erase
- // the old load.
- replaceInstUsesWith(*L, BitCast);
- eraseInstFromFunction(*L);
- }
-
- // Delete the old cast.
- return eraseInstFromFunction(*UADCI);
+ return nullptr;
}
SILInstruction *
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 3e4ae65..1c2ad04 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -1720,10 +1720,11 @@
ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
auto accessKind = SILAccessKind(Attr & 0x3);
auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x3);
- bool noNestedConflict = Attr >> 4;
+ bool noNestedConflict = (Attr >> 4) & 0x01;
+ bool fromBuiltin = (Attr >> 5) & 0x01;
ResultVal =
Builder.createBeginAccess(Loc, op, accessKind, enforcement,
- noNestedConflict);
+ noNestedConflict, fromBuiltin);
break;
}
case SILInstructionKind::EndAccessInst: {
@@ -1740,17 +1741,21 @@
ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2));
auto accessKind = SILAccessKind(Attr & 0x3);
auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x03);
- bool noNestedConflict = Attr >> 4;
+ bool noNestedConflict = (Attr >> 4) & 0x01;
+ bool fromBuiltin = (Attr >> 5) & 0x01;
ResultVal = Builder.createBeginUnpairedAccess(
- Loc, source, buffer, accessKind, enforcement, noNestedConflict);
+ Loc, source, buffer, accessKind, enforcement, noNestedConflict,
+ fromBuiltin);
break;
}
case SILInstructionKind::EndUnpairedAccessInst: {
SILValue op = getLocalValue(
ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
bool aborted = Attr & 0x1;
- auto enforcement = SILAccessEnforcement(Attr >> 1);
- ResultVal = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted);
+ auto enforcement = SILAccessEnforcement((Attr >> 1) & 0x03);
+ bool fromBuiltin = (Attr >> 3) & 0x01;
+ ResultVal = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted,
+ fromBuiltin);
break;
}
case SILInstructionKind::StoreUnownedInst: {
diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h
index 225be47..d1e30da 100644
--- a/lib/Serialization/SILFormat.h
+++ b/lib/Serialization/SILFormat.h
@@ -415,7 +415,7 @@
using SILOneOperandExtraAttributeLayout = BCRecordLayout<
SIL_ONE_OPERAND_EXTRA_ATTR,
SILInstOpCodeField,
- BCFixed<5>, // Optional attributes
+ BCFixed<6>, // Optional attributes
TypeIDField, SILTypeCategoryField, ValueIDField
>;
@@ -435,7 +435,7 @@
using SILTwoOperandsExtraAttributeLayout = BCRecordLayout<
SIL_TWO_OPERANDS_EXTRA_ATTR,
SILInstOpCodeField,
- BCFixed<5>, // Optional attributes
+ BCFixed<6>, // Optional attributes
TypeIDField,
SILTypeCategoryField,
ValueIDField,
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 13780e6..79278d0 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -1596,7 +1596,8 @@
auto *BAI = cast<BeginAccessInst>(&SI);
unsigned attr = unsigned(BAI->getAccessKind())
+ (unsigned(BAI->getEnforcement()) << 2)
- + (BAI->hasNoNestedConflict() << 4);
+ + (BAI->hasNoNestedConflict() << 4)
+ + (BAI->isFromBuiltin() << 5);
SILValue operand = BAI->getOperand();
SILOneOperandExtraAttributeLayout::emitRecord(
@@ -1626,7 +1627,8 @@
auto *BAI = cast<BeginUnpairedAccessInst>(&SI);
unsigned attr = unsigned(BAI->getAccessKind())
+ (unsigned(BAI->getEnforcement()) << 2)
- + (unsigned(BAI->hasNoNestedConflict()) << 4);
+ + (unsigned(BAI->hasNoNestedConflict()) << 4)
+ + (unsigned(BAI->isFromBuiltin()) << 5);
SILValue source = BAI->getSource();
SILValue buffer = BAI->getBuffer();
@@ -1645,7 +1647,8 @@
unsigned abbrCode = SILAbbrCodes[SILOneOperandExtraAttributeLayout::Code];
auto *EAI = cast<EndUnpairedAccessInst>(&SI);
unsigned attr = unsigned(EAI->isAborting())
- + (unsigned(EAI->getEnforcement()) << 1);
+ + (unsigned(EAI->getEnforcement()) << 1)
+ + (unsigned(EAI->isFromBuiltin()) << 3);
SILValue operand = EAI->getOperand();
SILOneOperandExtraAttributeLayout::emitRecord(
diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift
index bc1a42e..65adf76 100644
--- a/stdlib/public/core/KeyPath.swift
+++ b/stdlib/public/core/KeyPath.swift
@@ -646,41 +646,6 @@
}
}
-// _semantics("optimize.sil.preserve_exclusivity" forces the compiler to
-// generate access markers regardless of the current build settings. This way,
-// user code that accesses keypaths are properly enforced even if the standard
-// library has exclusivity checking internally disabled. The semantic attribute
-// must be consistently applied to both the begin and end unpaired access
-// markers, otherwise the runtime will fail catastrophically and unpredictably.
-// This relies on Swift module serialization occurring before these _semantic
-// function are inlined, since inlining would unpredictably cause the attribute
-// to be dropped.
-//
-// An exclusivity violation will report the caller's stack frame location.
-// Runtime diagnostics will be improved by inlining this function. However, this
-// cannot be marked @transparent because it can't be inlined prior to
-// serialization.
-@inlinable
-@inline(__always)
-@_semantics("optimize.sil.preserve_exclusivity")
-func beginAccessHelper<T>(_ address: Builtin.RawPointer, _ accessRecordPtr: Builtin.RawPointer, _ type: T.Type) {
- Builtin.beginUnpairedModifyAccess(address, accessRecordPtr, type)
-}
-
-@inlinable
-@inline(__always)
-@_semantics("optimize.sil.preserve_exclusivity")
-func endAccessHelper(_ accessRecordPtr: Builtin.RawPointer) {
- Builtin.endUnpairedAccess(accessRecordPtr)
-}
-
-@inlinable
-@inline(__always)
-@_semantics("optimize.sil.preserve_exclusivity")
-func instantaneousAccessHelper<T>(_ address: Builtin.RawPointer, _ type: T.Type) {
- Builtin.performInstantaneousReadAccess(address, T.self)
-}
-
// A class that maintains ownership of another object while a mutable projection
// into it is underway. The lifetime of the instance of this class is also used
// to begin and end exclusive 'modify' access to the projected address.
@@ -735,7 +700,7 @@
// Begin a 'modify' access to the address. This access is ended in
// ClassHolder's deinitializer.
- beginAccessHelper(address._rawValue, accessRecordPtr, type)
+ Builtin.beginUnpairedModifyAccess(address._rawValue, accessRecordPtr, type)
return holder
}
@@ -745,7 +710,7 @@
let accessRecordPtr = Builtin.projectTailElems(self, AccessRecord.self)
// Ends the access begun in _create().
- endAccessHelper(accessRecordPtr)
+ Builtin.endUnpairedAccess(accessRecordPtr)
}
}
@@ -1296,7 +1261,8 @@
// Perform an instaneous record access on the address in order to
// ensure that the read will not conflict with an already in-progress
// 'modify' access.
- instantaneousAccessHelper(offsetAddress._rawValue, NewValue.self)
+ Builtin.performInstantaneousReadAccess(offsetAddress._rawValue,
+ NewValue.self)
return .continue(offsetAddress
.assumingMemoryBound(to: NewValue.self)
.pointee)
diff --git a/test/IRGen/preserve_exclusivity.swift b/test/IRGen/preserve_exclusivity.swift
index 119eea3..14e1a87 100644
--- a/test/IRGen/preserve_exclusivity.swift
+++ b/test/IRGen/preserve_exclusivity.swift
@@ -1,10 +1,7 @@
-// RUN: %target-swift-frontend -parse-stdlib -emit-ir -Onone %s | %FileCheck --check-prefix=IR-Onone %s
+// RUN: %target-swift-frontend -swift-version 3 -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -emit-ir -O %s | %FileCheck %s
+// RUN: %target-swift-frontend -swift-version 4 -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -emit-ir -O %s | %FileCheck %s
//
-// Check that access markers in @_semantics("optimize.sil.preserve_exclusivity") functions generate runtime calls.
-
-// RUN: %target-swift-frontend -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -emit-ir -O %s | %FileCheck --check-prefix=IR-O %s
-//
-// Check that the -O pipeline preserves the runtime calls for @_semantics("optimize.sil.preserve_exclusivity") functions.
+// Check that the -O pipeline always preserves the runtime calls for Builtin access markers and that the KeyPath implementation is fully inlined.
@_silgen_name("marker1")
func marker1() -> ()
@@ -15,122 +12,44 @@
@_silgen_name("marker3")
func marker3() -> ()
-@_silgen_name("marker4")
-func marker4() -> ()
+// IR-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity11beginAccessyyBp_BpxmtlF"(i8*, i8*, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
+// IR: call void @swift_beginAccess
+// IR-NEXT: ret void
-@_silgen_name("marker5")
-func marker5() -> ()
-
-@_silgen_name("marker6")
-func marker6() -> ()
-
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1)
-// IR-Onone: call void @swift_beginAccess
-// IR-Onone-NEXT: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
-// IR-O: call void @swift_beginAccess
-// IR-O-NEXT: ret void
-
-@_semantics("optimize.sil.preserve_exclusivity")
-public func beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
+public func beginAccess<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker1()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity8endNoOptyyBpF"(i8*)
-// IR-Onone: call void @swift_endAccess
-// IR-Onone-NEXT: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity8endNoOptyyBpF"(i8*)
-// IR-O: call void @swift_endAccess
-// IR-O-NEXT: ret void
-@_semantics("optimize.sil.preserve_exclusivity")
-public func endNoOpt(_ address: Builtin.RawPointer) {
+// CHECK-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity9endAccessyyBpF"(i8*{{.*}})
+// CHECK: call void @swift_endAccess
+// CHECK-NEXT: ret void
+public func endAccess(_ address: Builtin.RawPointer) {
marker2()
Builtin.endUnpairedAccess(address)
}
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity9readNoOptyyBp_xmtlF"(i8*, %swift.type*, %swift.type* %T1)
-// IR-Onone: call void @swift_beginAccess
-// IR-Onone: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity9readNoOptyyBp_xmtlF"(i8*, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
-// IR-O: call void @swift_beginAccess
-// IR-O: ret void
+// CHECK-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity10readAccessyyBp_xmtlF"(i8*, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
+// CHECK: call void @swift_beginAccess
+// CHECK: ret void
@_semantics("optimize.sil.preserve_exclusivity")
-public func readNoOpt<T1>(_ address: Builtin.RawPointer, _ ty1: T1.Type) {
+public func readAccess<T1>(_ address: Builtin.RawPointer, _ ty1: T1.Type) {
marker3()
Builtin.performInstantaneousReadAccess(address, ty1);
}
-// Make sure testNoOpt properly inlines in our functions.
+// Make sure testAccess properly inlines in our functions.
//
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity9testNoOptyyBpF"(i8*)
-// IR-O: call swiftcc void @marker1
-// IR-O: call void @swift_beginAccess
-// IR-O: call swiftcc void @marker2
-// IR-O: call void @swift_endAccess
-// IR-O: call swiftcc void @marker3
-// IR-O: call void @swift_beginAccess
-// IR-O: ret void
-public func testNoOpt(_ k1: Builtin.RawPointer) {
- beginNoOpt(k1, k1, Builtin.RawPointer.self)
- endNoOpt(k1)
- readNoOpt(k1, Builtin.RawPointer.self)
-}
-
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity8beginOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1)
-// IR-Onone: call void @swift_beginAccess
-// IR-Onone-NEXT: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity8beginOptyyBp_BpxmtlF"(i8*{{.*}}, i8*{{.*}}, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
-// IR-O-NEXT: entry
-// IR-O-NEXT: call swiftcc void @marker4
-// IR-O-NEXT: ret void
-
-public func beginOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
- marker4()
- Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
-}
-
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity6endOptyyBpF"(i8*)
-// IR-Onone: call void @swift_endAccess
-// IR-Onone-NEXT: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity6endOptyyBpF"(i8*{{.*}})
-// IR-O-NEXT: entry
-// IR-O-NEXT: call swiftcc void @marker5
-// IR-O-NEXT: ret void
-
-public func endOpt(_ address: Builtin.RawPointer) {
- marker5()
- Builtin.endUnpairedAccess(address)
-}
-
-// IR-Onone-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity7readOptyyBp_xmtlF"(i8*, %swift.type*, %swift.type* %T1)
-// IR-Onone: call void @swift_beginAccess
-// IR-Onone: ret void
-
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity7readOptyyBp_xmtlF"(i8*{{.*}}, %swift.type*{{.*}}, %swift.type*{{.*}} %T1)
-// IR-O-NEXT: entry
-// IR-O-NEXT: call swiftcc void @marker6
-// IR-O-NEXT: ret void
-
-public func readOpt<T1>(_ address: Builtin.RawPointer, _ ty1: T1.Type) {
- marker6()
- Builtin.performInstantaneousReadAccess(address, ty1);
-}
-
-// Make sure testOpt properly inlines in our functions.
-//
-// IR-O-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity7testOptyyBpF"(i8*{{.*}})
-// IR-O: call swiftcc void @marker4
-// IR-O: call swiftcc void @marker5
-// IR-O: call swiftcc void @marker6
-// IR-O: ret void
-public func testOpt(_ k1: Builtin.RawPointer) {
- beginOpt(k1, k1, Builtin.RawPointer.self)
- endOpt(k1)
- readOpt(k1, Builtin.RawPointer.self)
+// CHECK-LABEL: define {{.*}}swiftcc void @"$S20preserve_exclusivity10testAccessyyBpF"(i8*)
+// CHECK: call swiftcc void @marker1
+// CHECK: call void @swift_beginAccess
+// CHECK: call swiftcc void @marker2
+// CHECK: call void @swift_endAccess
+// CHECK: call swiftcc void @marker3
+// CHECK: call void @swift_beginAccess
+// CHECK: ret void
+public func testAccess(_ k1: Builtin.RawPointer) {
+ beginAccess(k1, k1, Builtin.RawPointer.self)
+ endAccess(k1)
+ readAccess(k1, Builtin.RawPointer.self)
}
diff --git a/test/Interpreter/enforce_exclusive_access.swift b/test/Interpreter/enforce_exclusive_access.swift
index 4b34899..722e6d7 100644
--- a/test/Interpreter/enforce_exclusive_access.swift
+++ b/test/Interpreter/enforce_exclusive_access.swift
@@ -308,13 +308,18 @@
c[keyPath: getF] += c[keyPath: getF] + 1 // no-trap
}
-// This does not trap, for now, because the standard library (and thus KeyPath) is
-// compiled in Swift 3 mode and we currently log rather than trap in Swift mode.
ExclusiveAccessTestSuite.test("KeyPathInoutKeyPathWriteClassStoredProp")
+ .skip(.custom(
+ { _isFastAssertConfiguration() },
+ reason: "this trap is not guaranteed to happen in -Ounchecked"))
+ .crashOutputMatches("Previous access (a modification) started at")
+ .crashOutputMatches("Current access (a modification) started at")
+ .code
{
let getF = \ClassWithStoredProperty.f
let c = ClassWithStoredProperty()
+ expectCrashLater()
modifyAndPerform(&c[keyPath: getF]) {
c[keyPath: getF] = 12
}
@@ -322,10 +327,18 @@
// This does not currently trap because the standard library is compiled in Swift 3 mode,
// which logs.
-ExclusiveAccessTestSuite.test("KeyPathInoutKeyPathReadClassStoredProp") {
+ExclusiveAccessTestSuite.test("KeyPathInoutKeyPathReadClassStoredProp")
+ .skip(.custom(
+ { _isFastAssertConfiguration() },
+ reason: "this trap is not guaranteed to happen in -Ounchecked"))
+ .crashOutputMatches("Previous access (a modification) started at")
+ .crashOutputMatches("Current access (a read) started at")
+ .code
+{
let getF = \ClassWithStoredProperty.f
let c = ClassWithStoredProperty()
+ expectCrashLater()
modifyAndPerform(&c[keyPath: getF]) {
let y = c[keyPath: getF]
_blackHole(y)
diff --git a/test/Interpreter/enforce_exclusive_access_backtrace.swift b/test/Interpreter/enforce_exclusive_access_backtrace.swift
index b50b114..9c80313 100644
--- a/test/Interpreter/enforce_exclusive_access_backtrace.swift
+++ b/test/Interpreter/enforce_exclusive_access_backtrace.swift
@@ -44,34 +44,3 @@
var c = C()
withUnsafePointer(to: &c.f) { _ = fputs(String(format: "c.f: 0x%lx\n", Int(bitPattern: $0)), stderr) }
// CHECK: c.f: [[C_F_ADDR:0x.*]]
-
-// Key path accesses are performed in the Standard Library. The Standard Library
-// is currently compiled in Swift 3 mode and the compiler currently logs conflicts
-// (rather than trapping on them) code compiled in Swift 3 mode. For this reason
-// conflicts where the second conflicting access is via a key path will log rather than
-// trap.
-
-fputs("Overlapping Key Path Write Accesses\n", stderr);
-writeAndPerform(&c[keyPath: \C.f]) {
- c[keyPath: \C.f] = 8
- // CHECK-LABEL: Overlapping Key Path Write Accesses
- // CHECK: Simultaneous accesses to [[C_F_ADDR]], but modification requires exclusive access.
- // CHECK: Previous access (a modification)
- // CHECK: Current access (a modification)
- // CHECK: a.out {{.*}} closure
- // CHECK: a.out {{.*}} writeAndPerform
- // CHECK: a.out {{.*}} main
-}
-
-fputs("Overlapping Key Path Write Access and Key Path Read Access\n", stderr);
-writeAndPerform(&c[keyPath: \C.f]) {
- let x = c[keyPath: \C.f]
- _blackHole(x)
- // CHECK-LABEL: Overlapping Key Path Write Access and Key Path Read Access
- // CHECK: Simultaneous accesses to [[C_F_ADDR]], but modification requires exclusive access.
- // CHECK: Previous access (a modification)
- // CHECK: Current access (a read)
- // CHECK: a.out {{.*}} closure
- // CHECK: a.out {{.*}} writeAndPerform
- // CHECK: a.out {{.*}} main
-}
diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil
index f67e554..32c7f39 100644
--- a/test/SIL/Parser/basic.sil
+++ b/test/SIL/Parser/basic.sil
@@ -1663,6 +1663,29 @@
return %20 : $()
}
+// CHECK-LABEL: sil @test_builtin_access : $@convention(thin) (@guaranteed A) -> () {
+// CHECK: begin_access [read] [dynamic] [builtin]
+// CHECK: begin_unpaired_access [read] [dynamic] [builtin]
+// CHECK: end_unpaired_access [dynamic] [builtin]
+// CHECK-LABEL: } // end sil function 'test_builtin_access'
+sil @test_builtin_access : $(@guaranteed A) -> () {
+bb0(%0 : $A):
+ %1 = alloc_stack $Any
+ %2 = ref_element_addr %0 : $A, #A.property
+ %6 = begin_access [read] [dynamic] [builtin] %2 : $*Any
+ copy_addr %6 to %1 : $*Any
+ end_access %6 : $*Any
+ %9 = alloc_stack $Builtin.UnsafeValueBuffer
+ begin_unpaired_access [read] [dynamic] [builtin] %2 : $*Any, %9 : $*Builtin.UnsafeValueBuffer
+ copy_addr %2 to %1 : $*Any
+ end_unpaired_access [dynamic] [builtin] %9 : $*Builtin.UnsafeValueBuffer
+ destroy_addr %1 : $*Any
+ dealloc_stack %9 : $*Builtin.UnsafeValueBuffer
+ dealloc_stack %1 : $*Any
+ %20 = tuple ()
+ return %20 : $()
+}
+
struct EmptyStruct {}
sil @test_empty_destructure : $@convention(thin) () -> () {
diff --git a/test/SILGen/builtins.swift b/test/SILGen/builtins.swift
index d8ef79f..85cc9ee 100644
--- a/test/SILGen/builtins.swift
+++ b/test/SILGen/builtins.swift
@@ -373,7 +373,7 @@
func beginUnpairedModifyAccess<T1>(address: Builtin.RawPointer, scratch: Builtin.RawPointer, ty1: T1.Type) {
// CHECK: [[P2A_ADDR:%.*]] = pointer_to_address %0
// CHECK: [[P2A_SCRATCH:%.*]] = pointer_to_address %1
- // CHECK: begin_unpaired_access [modify] [dynamic] [[P2A_ADDR]] : $*T1, [[P2A_SCRATCH]] : $*Builtin.UnsafeValueBuffer
+ // CHECK: begin_unpaired_access [modify] [dynamic] [builtin] [[P2A_ADDR]] : $*T1, [[P2A_SCRATCH]] : $*Builtin.UnsafeValueBuffer
// CHECK: [[RESULT:%.*]] = tuple ()
// CHECK: [[RETURN:%.*]] = tuple ()
// CHECK: return [[RETURN]] : $()
@@ -385,7 +385,7 @@
func performInstantaneousReadAccess<T1>(address: Builtin.RawPointer, scratch: Builtin.RawPointer, ty1: T1.Type) {
// CHECK: [[P2A_ADDR:%.*]] = pointer_to_address %0
// CHECK: [[SCRATCH:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
- // CHECK: begin_unpaired_access [read] [dynamic] [no_nested_conflict] [[P2A_ADDR]] : $*T1, [[SCRATCH]] : $*Builtin.UnsafeValueBuffer
+ // CHECK: begin_unpaired_access [read] [dynamic] [no_nested_conflict] [builtin] [[P2A_ADDR]] : $*T1, [[SCRATCH]] : $*Builtin.UnsafeValueBuffer
// CHECK-NOT: end_{{.*}}access
// CHECK: [[RESULT:%.*]] = tuple ()
// CHECK: [[RETURN:%.*]] = tuple ()
diff --git a/test/SILGen/preserve_exclusivity.swift b/test/SILGen/preserve_exclusivity.swift
deleted file mode 100644
index 7902e3d..0000000
--- a/test/SILGen/preserve_exclusivity.swift
+++ /dev/null
@@ -1,118 +0,0 @@
-// RUN: %target-swift-frontend -parse-stdlib -emit-silgen %s | %FileCheck --check-prefix=SILGEN %s
-//
-// Check that SILGen emits the correct SIL attributes for @_semantics("optimize.sil.preserve_exclusivity")/
-
-// RUN: %target-swift-frontend -parse-stdlib -parse-stdlib -emit-sil -Onone %s | %FileCheck --check-prefix=CANONICAL %s
-//
-// Check that -Onone pipeline does not eliminate the attribute or access markers.
-
-@_silgen_name("marker1")
-func marker1() -> ()
-
-@_silgen_name("marker2")
-func marker2() -> ()
-
-@_silgen_name("marker3")
-func marker3() -> ()
-
-@_silgen_name("marker4")
-func marker4() -> ()
-
-@_silgen_name("marker5")
-func marker5() -> ()
-
-@_silgen_name("marker6")
-func marker6() -> ()
-
-// SILGEN-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// SILGEN: begin_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF
-
-// CANONICAL-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// CANONICAL: begin_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF
-
-@_semantics("optimize.sil.preserve_exclusivity")
-public func beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
- marker1()
- Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
-}
-
-// SILGEN-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity8endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// SILGEN: end_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity8endNoOptyyBpF'
-
-// CANONICAL-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity8endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// CANONICAL: end_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity8endNoOptyyBpF'
-
-@_semantics("optimize.sil.preserve_exclusivity")
-public func endNoOpt(_ address: Builtin.RawPointer) {
- marker2()
- Builtin.endUnpairedAccess(address)
-}
-
-// SILGEN-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity9readNoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// SILGEN: begin_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity9readNoOptyyBp_BpmtF'
-
-// CANONICAL-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity9readNoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// CANONICAL: begin_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity9readNoOptyyBp_BpmtF'
-
-@_semantics("optimize.sil.preserve_exclusivity")
-public func readNoOpt(_ address: Builtin.RawPointer, _ ty1: Builtin.RawPointer.Type) {
- marker3()
- Builtin.performInstantaneousReadAccess(address, ty1);
-}
-
-public func testNoOpt(_ k1: Builtin.RawPointer) {
- beginNoOpt(k1, k1, Builtin.RawPointer.self)
- endNoOpt(k1)
- readNoOpt(k1, Builtin.RawPointer.self)
-}
-
-// SILGEN-LABEL: sil @$S20preserve_exclusivity8beginOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// SILGEN: begin_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity8beginOptyyBp_BpxmtlF'
-
-// CANONICAL-LABEL: sil @$S20preserve_exclusivity8beginOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// CANONICAL: begin_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity8beginOptyyBp_BpxmtlF'
-
-public func beginOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
- marker4()
- Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
-}
-
-// SILGEN-LABEL: sil @$S20preserve_exclusivity6endOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// SILGEN: end_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity6endOptyyBpF'
-
-// CANONICAL-LABEL: sil @$S20preserve_exclusivity6endOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// CANONICAL: end_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity6endOptyyBpF'
-
-public func endOpt(_ address: Builtin.RawPointer) {
- marker5()
- Builtin.endUnpairedAccess(address)
-}
-
-// SILGEN-LABEL: sil @$S20preserve_exclusivity7readOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// SILGEN: begin_unpaired_access
-// SILGEN: } // end sil function '$S20preserve_exclusivity7readOptyyBp_BpmtF'
-
-// CANONICAL-LABEL: sil @$S20preserve_exclusivity7readOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// CANONICAL: begin_unpaired_access
-// CANONICAL: } // end sil function '$S20preserve_exclusivity7readOptyyBp_BpmtF'
-
-public func readOpt(_ address: Builtin.RawPointer, _ ty1: Builtin.RawPointer.Type) {
- marker6()
- Builtin.performInstantaneousReadAccess(address, ty1);
-}
-
-public func testOpt(_ k1: Builtin.RawPointer) {
- beginOpt(k1, k1, Builtin.RawPointer.self)
- endOpt(k1)
- readOpt(k1, Builtin.RawPointer.self)
-}
diff --git a/test/SILOptimizer/cast_promote.sil b/test/SILOptimizer/cast_promote.sil
deleted file mode 100644
index d28b0b2..0000000
--- a/test/SILOptimizer/cast_promote.sil
+++ /dev/null
@@ -1,304 +0,0 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine | %FileCheck %s
-
-sil_stage canonical
-
-import Builtin
-import Swift
-import SwiftShims
-
-public class Base {}
-
-@objc
-public protocol ObjCProto {}
-
-public protocol NativeProto {}
-
-// CHECK-LABEL: sil @promote_super : $@convention(thin) <T where T : Base> (@owned AnyObject) -> @owned T {
-// CHECK: bb0(%0 : $AnyObject):
-// CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T
-sil @promote_super : $@convention(thin) <T where T : Base> (@owned AnyObject) -> @owned T {
-bb0(%0 : $AnyObject):
- %1 = alloc_stack $AnyObject
- store %0 to %1 : $*AnyObject
- %3 = unchecked_addr_cast %1 : $*AnyObject to $*T
- %4 = load %3 : $*T
- dealloc_stack %1 : $*AnyObject
- return %4 : $T
-}
-
-// CHECK-LABEL: sil @promote_anyobject : $@convention(thin) <T where T : AnyObject> (@owned AnyObject) -> @owned T {
-// CHECK: bb0(%0 : $AnyObject):
-// CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T
-sil @promote_anyobject : $@convention(thin) <T where T : AnyObject> (@owned AnyObject) -> @owned T {
-bb0(%0 : $AnyObject):
- %1 = alloc_stack $AnyObject
- store %0 to %1 : $*AnyObject
- %3 = unchecked_addr_cast %1 : $*AnyObject to $*T
- %4 = load %3 : $*T
- dealloc_stack %1 : $*AnyObject
- return %4 : $T
-}
-
-// CHECK-LABEL: sil @promote_objc : $@convention(thin) <T where T : ObjCProto> (@owned AnyObject) -> @owned T {
-// CHECK: bb0(%0 : $AnyObject):
-// CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T
-sil @promote_objc : $@convention(thin) <T where T : ObjCProto> (@owned AnyObject) -> @owned T {
-bb0(%0 : $AnyObject):
- %1 = alloc_stack $AnyObject
- store %0 to %1 : $*AnyObject
- %3 = unchecked_addr_cast %1 : $*AnyObject to $*T
- %4 = load %3 : $*T
- dealloc_stack %1 : $*AnyObject
- return %4 : $T
-}
-
-// CHECK-LABEL: sil @promote_objcproto : $@convention(thin) (@owned AnyObject) -> @owned ObjCProto {
-// CHECK: bb0(%0 : $AnyObject):
-// CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $ObjCProto
-sil @promote_objcproto : $@convention(thin) (@owned AnyObject) -> @owned ObjCProto {
-bb0(%0 : $AnyObject):
- %1 = alloc_stack $AnyObject
- store %0 to %1 : $*AnyObject
- %3 = unchecked_addr_cast %1 : $*AnyObject to $*ObjCProto
- %4 = load %3 : $*ObjCProto
- dealloc_stack %1 : $*AnyObject
- return %4 : $ObjCProto
-}
-
-// CHECK-LABEL: sil @nopromote_nativeproto : $@convention(thin) (@owned AnyObject) -> @out NativeProto {
-// CHECK: bb0(%0 : $*NativeProto, %1 : $AnyObject):
-// CHECK: unchecked_addr_cast %{{.*}} : $*AnyObject to $*NativeProto
-sil @nopromote_nativeproto : $@convention(thin) (@owned AnyObject) -> @out NativeProto {
-bb0(%0 : $*NativeProto, %1 : $AnyObject):
- %3 = alloc_stack $AnyObject
- store %1 to %3 : $*AnyObject
- %5 = unchecked_addr_cast %3 : $*AnyObject to $*NativeProto
- copy_addr %5 to [initialization] %0 : $*NativeProto
- dealloc_stack %3 : $*AnyObject
- strong_release %1 : $AnyObject
- %9 = tuple ()
- return %9 : $()
-}
-
-class B {}
-
-// CHECK-LABEL: sil @load_uncheckedaddrcast_to_uncheckedrefcast_load : $@convention(thin) (@inout Optional<B>) -> (Builtin.NativeObject, Optional<Builtin.NativeObject>) {
-// CHECK-NOT: unchecked_addr_cast
-// CHECK: unchecked_ref_cast
-// CHECK-NOT: unchecked_addr_cast
-// CHECK: unchecked_ref_cast
-// CHECK-NOT: unchecked_addr_cast
-sil @load_uncheckedaddrcast_to_uncheckedrefcast_load : $@convention(thin) (@inout Optional<B>) -> (Builtin.NativeObject, Optional<Builtin.NativeObject>) {
-bb0(%0 : $*Optional<B>):
- %1 = unchecked_addr_cast %0 : $*Optional<B> to $*Builtin.NativeObject
- %2 = unchecked_addr_cast %0 : $*Optional<B> to $*Optional<Builtin.NativeObject>
- %3 = load %1 : $*Builtin.NativeObject
- %4 = load %2 : $*Optional<Builtin.NativeObject>
- %5 = tuple(%3 : $Builtin.NativeObject, %4 : $Optional<Builtin.NativeObject>)
- return %5 : $(Builtin.NativeObject, Optional<Builtin.NativeObject>)
-}
-
-struct rs_E {
- var ptr : Builtin.NativeObject
- var i : Int
-}
-struct rs_F {
- var e : rs_E
-}
-struct rs_D {
- var i : Int
-}
-struct rs_C {
- var d : rs_D
-}
-
-struct rs_B {
- var ptr : Builtin.NativeObject
-}
-struct rs_A {
- var b : rs_B
-}
-
-enum TwoStateEnum {
- case State1(rs_A)
- case State2(rs_C)
-}
-
-enum FakeOptional<T> {
- case nOne
- case some(T)
-}
-
-// CHECK-LABEL: sil @reinterpretcast_simplification_unchecked_addr : $@convention(thin) (@inout FakeOptional<rs_A>, @inout FakeOptional<rs_C>, @inout FakeOptional<rs_F>, @inout TwoStateEnum, @inout TwoStateEnum) -> (Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int) {
-// CHECK: bb0(
-// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_bitwise_cast
-// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_trivial_bit_cast
-// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_bitwise_cast
-// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_bitwise_cast
-// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_trivial_bit_cast
-// CHECK-NEXT: tuple
-// CHECK-NEXT: return
-sil @reinterpretcast_simplification_unchecked_addr
- : $@convention(thin) (@inout FakeOptional<rs_A>, @inout FakeOptional<rs_C>, @inout FakeOptional<rs_F>, @inout TwoStateEnum,
- @inout TwoStateEnum)
- -> (Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int) {
-bb0(%0 : $*FakeOptional<rs_A>, %1 : $*FakeOptional<rs_C>, %2 : $*FakeOptional<rs_F>, %3 : $*TwoStateEnum, %4 : $*TwoStateEnum):
- %5 = unchecked_addr_cast %0 : $*FakeOptional<rs_A> to $*Builtin.NativeObject
- %6 = unchecked_addr_cast %1 : $*FakeOptional<rs_C> to $*Int
- %7 = unchecked_addr_cast %2 : $*FakeOptional<rs_F> to $*Builtin.NativeObject
- %8 = unchecked_addr_cast %3 : $*TwoStateEnum to $*Builtin.NativeObject
- %9 = unchecked_addr_cast %4 : $*TwoStateEnum to $*Int
- %10 = load %5 : $*Builtin.NativeObject
- %11 = load %6 : $*Int
- %12 = load %7 : $*Builtin.NativeObject
- %13 = load %8 : $*Builtin.NativeObject
- %14 = load %9 : $*Int
- %15 = tuple(%10 : $Builtin.NativeObject, %11 : $Int, %12 : $Builtin.NativeObject, %13 : $Builtin.NativeObject, %14 : $Int)
- return %15 : $(Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int)
-}
-
-enum ValEnum {case X, Y, Z}
-
-struct PtrInt {
- var Ptr: Builtin.RawPointer
- var Val: Builtin.Int32
-}
-struct PtrInt2 {
- var Ptr: Builtin.RawPointer
- var Val1: Builtin.Int32
- var Val2: ValEnum
-}
-struct Agg {
- var pi: PtrInt
- var Val: ValEnum
-}
-
-// struct {A, B} -> A is safe
-// struct {A, B, C} -> struct {A, B} is safe
-// struct { struct {A, B}, C} -> struct {A, B} is safe
-// struct { struct {A, B}, C} -> struct {A, B, C} is NOT safe
-// CHECK-LABEL: sil @unchecked_addr_cast_struct_promote : $@convention(thin) (@inout PtrInt, @inout PtrInt2, @inout Agg) -> (Builtin.RawPointer, PtrInt, PtrInt, PtrInt2) {
-// CHECK: bb0(%0 : $*PtrInt, %1 : $*PtrInt2, %2 : $*Agg):
-// CHECK: load %0 : $*PtrInt
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $PtrInt to $Builtin.RawPointer
-// CHECK: load %1 : $*PtrInt2
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $PtrInt2 to $PtrInt
-// CHECK: load %2 : $*Agg
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $Agg to $PtrInt
-// CHECK: [[LOCAL:%.*]] = alloc_stack $Agg
-// CHECK: store %{{.*}} to [[LOCAL]] : $*Agg
-// CHECK: [[CAST:%.*]] = unchecked_addr_cast [[LOCAL]] : $*Agg to $*PtrInt2
-// CHECK: load [[CAST]] : $*PtrInt2
-// CHECK: dealloc_stack
-// CHECK: return
-sil @unchecked_addr_cast_struct_promote : $@convention(thin) (@inout PtrInt, @inout PtrInt2, @inout Agg) -> (Builtin.RawPointer, PtrInt, PtrInt, PtrInt2) {
-bb0(%0 : $*PtrInt, %1 : $*PtrInt2, %2 : $*Agg):
- %3 = load %0 : $*PtrInt
- %4 = alloc_stack $PtrInt
- store %3 to %4 : $*PtrInt
- %6 = unchecked_addr_cast %4 : $*PtrInt to $*Builtin.RawPointer
- %7 = load %6 : $*Builtin.RawPointer
- %8 = load %1 : $*PtrInt2
- %9 = alloc_stack $PtrInt2
- store %8 to %9 : $*PtrInt2
- %11 = unchecked_addr_cast %9 : $*PtrInt2 to $*PtrInt
- %12 = load %11 : $*PtrInt
- %13 = load %2 : $*Agg
- %14 = alloc_stack $Agg
- store %13 to %14 : $*Agg
- %16 = unchecked_addr_cast %14 : $*Agg to $*PtrInt
- %17 = load %16 : $*PtrInt
- %18 = alloc_stack $Agg
- store %13 to %18 : $*Agg
- %20 = unchecked_addr_cast %18 : $*Agg to $*PtrInt2
- %21 = load %20 : $*PtrInt2
- %22 = tuple (%7 : $Builtin.RawPointer, %12 : $PtrInt, %17 : $PtrInt, %21 : $PtrInt2)
- dealloc_stack %18 : $*Agg
- dealloc_stack %14 : $*Agg
- dealloc_stack %9 : $*PtrInt2
- dealloc_stack %4 : $*PtrInt
- return %22 : $(Builtin.RawPointer, PtrInt, PtrInt, PtrInt2)
-}
-
-public enum E0 {}
-public enum E0_ {}
-public enum E1 {case A}
-public enum E2 {case A, B}
-public enum E3 {case A, B, C}
-
-public enum PB2 {case A, B(Int)}
-public enum PX2 {case X(Int), Y}
-public enum PAB2 {case A(Int), B(Int)}
-public enum PXY2 {case X(Int), Y(Int)}
-public enum PX3 {case X(Int), Y, Z}
-
-// enum {} -> enum {} is safe
-// enum {A, B} -> enum {X} is safe
-// enum {A, B(Int)} -> Int is safe
-// enum {A, B(Int)} -> enum {X(Int), Y} is safe
-// enum {A, B(Int)} -> enum {X(Int), Y, Z} is NOT safe
-// enum {A(Int), B(Int)} -> enum {X(Int), Y(Int)} is NOT safe
-// CHECK-LABEL: sil @unchecked_addr_cast_enum_promote : $@convention(thin) (@inout E0, @inout E2, @inout PB2, @inout PAB2) -> (E0_, E1, Int, PX2, PX3, PXY2)
-// CHECK: load %0 : $*E0
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $E0 to $E0_
-// CHECK: load %1 : $*E2
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $E2 to $E1
-// CHECK: load %2 : $*PB2
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $PB2 to $Int
-// CHECK: unchecked_trivial_bit_cast %{{.*}} : $PB2 to $PX2
-// CHECK: alloc_stack $PB2
-// CHECK: store %{{.*}} to %{{.*}} : $*PB2
-// CHECK: unchecked_addr_cast %{{.*}} : $*PB2 to $*PX3
-// CHECK: load %{{.*}} : $*PX3
-// CHECK: load %3 : $*PAB2
-// CHECK: alloc_stack $PAB2
-// CHECK: store %{{.*}} to %{{.*}} : $*PAB2
-// CHECK: unchecked_addr_cast %{{.*}} : $*PAB2 to $*PXY2
-// CHECK: load %{{.*}} : $*PXY2
-// CHECK: dealloc_stack %{{.*}} : $*PAB2
-// CHECK: dealloc_stack %{{.*}} : $*PB2
-// CHECK: return %{{.*}} : $(E0_, E1, Int, PX2, PX3, PXY2)
-sil @unchecked_addr_cast_enum_promote : $@convention(thin) (@inout E0, @inout E2, @inout PB2, @inout PAB2) -> (E0_, E1, Int, PX2, PX3, PXY2) {
-bb0(%0 : $*E0, %1 : $*E2, %2 : $*PB2, %3 : $*PAB2):
- %9 = load %0 : $*E0 // user: %11
- %10 = alloc_stack $E0 // users: %11, %12, %43
- store %9 to %10 : $*E0 // id: %11
- %12 = unchecked_addr_cast %10 : $*E0 to $*E0_ // user: %13
- %13 = load %12 : $*E0_ // user: %37
- %14 = load %1 : $*E2 // user: %16
- %15 = alloc_stack $E2 // users: %16, %17, %42
- store %14 to %15 : $*E2 // id: %16
- %17 = unchecked_addr_cast %15 : $*E2 to $*E1 // user: %18
- %18 = load %17 : $*E1 // user: %37
- %19 = load %2 : $*PB2 // users: %21, %25, %29
- %20 = alloc_stack $PB2 // users: %21, %22, %41
- store %19 to %20 : $*PB2 // id: %21
- %22 = unchecked_addr_cast %20 : $*PB2 to $*Int // user: %23
- %23 = load %22 : $*Int // user: %37
- %24 = alloc_stack $PB2 // users: %25, %26, %40
- store %19 to %24 : $*PB2 // id: %25
- %26 = unchecked_addr_cast %24 : $*PB2 to $*PX2 // user: %27
- %27 = load %26 : $*PX2 // user: %37
- %28 = alloc_stack $PB2 // users: %29, %30, %39
- store %19 to %28 : $*PB2 // id: %29
- %30 = unchecked_addr_cast %28 : $*PB2 to $*PX3 // user: %31
- %31 = load %30 : $*PX3 // user: %37
- %32 = load %3 : $*PAB2 // user: %34
- %33 = alloc_stack $PAB2 // users: %34, %35, %38
- store %32 to %33 : $*PAB2 // id: %34
- %35 = unchecked_addr_cast %33 : $*PAB2 to $*PXY2 // user: %36
- %36 = load %35 : $*PXY2 // user: %37
- %37 = tuple (%13 : $E0_, %18 : $E1, %23 : $Int, %27 : $PX2, %31 : $PX3, %36 : $PXY2) // user: %44
- dealloc_stack %33 : $*PAB2 // id: %38
- dealloc_stack %28 : $*PB2 // id: %39
- dealloc_stack %24 : $*PB2 // id: %40
- dealloc_stack %20 : $*PB2 // id: %41
- dealloc_stack %15 : $*E2 // id: %42
- dealloc_stack %10 : $*E0 // id: %43
- return %37 : $(E0_, E1, Int, PX2, PX3, PXY2) // id: %44
-}
diff --git a/test/SILOptimizer/preserve_exclusivity.swift b/test/SILOptimizer/preserve_exclusivity.swift
deleted file mode 100644
index 9ba7e28..0000000
--- a/test/SILOptimizer/preserve_exclusivity.swift
+++ /dev/null
@@ -1,150 +0,0 @@
-// RUN: %target-swift-frontend -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -emit-sil -O %s | %FileCheck %s
-//
-// The -O pipeline should respect
-// @_semantics("optimize.sil.preserve_exclusivity") and avoid eliminating access
-// markers as long as the semantics call is not inlined.
-
-// RUN: %empty-directory(%t)
-// RUN: %target-swift-frontend -parse-stdlib -emit-module -O -primary-file %s -emit-module-path %t/preserve_exclusivity.swiftmodule
-// RUN: %target-sil-opt %t/preserve_exclusivity.swiftmodule -emit-sorted-sil -verify -o - | %FileCheck --check-prefix=DESERIALIZED %s
-//
-// Access markers cannot be stripped prior to module serialization, even when their functions are inlined.
-
-@usableFromInline
-@_silgen_name("marker1")
-func marker1() -> ()
-
-@usableFromInline
-@_silgen_name("marker2")
-func marker2() -> ()
-
-@usableFromInline
-@_silgen_name("marker3")
-func marker3() -> ()
-
-@usableFromInline
-@_silgen_name("marker4")
-func marker4() -> ()
-
-@usableFromInline
-@_silgen_name("marker5")
-func marker5() -> ()
-
-@usableFromInline
-@_silgen_name("marker6")
-func marker6() -> ()
-
-// CHECK-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity13f1_beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// CHECK: begin_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f1_beginNoOptyyBp_BpxmtlF'
-
-// DESERIALIZED-LABEL: sil [serialized] [_semantics "optimize.sil.preserve_exclusivity"] [canonical] @$S20preserve_exclusivity13f1_beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// DESERIALIZED: begin_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f1_beginNoOptyyBp_BpxmtlF'
-
-@inlinable
-@_semantics("optimize.sil.preserve_exclusivity")
-public func f1_beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
- marker1()
- Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
-}
-
-// CHECK-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity13f2___endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// CHECK: end_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f2___endNoOptyyBpF'
-
-// DESERIALIZED-LABEL: sil [serialized] [_semantics "optimize.sil.preserve_exclusivity"] [canonical] @$S20preserve_exclusivity13f2___endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// DESERIALIZED: end_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f2___endNoOptyyBpF'
-
-@inlinable
-@_semantics("optimize.sil.preserve_exclusivity")
-public func f2___endNoOpt(_ address: Builtin.RawPointer) {
- marker2()
- Builtin.endUnpairedAccess(address)
-}
-
-// CHECK-LABEL: sil [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity13f3__readNoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// CHECK: begin_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f3__readNoOptyyBp_BpmtF
-
-// DESERIALIZED-LABEL: sil [serialized] [_semantics "optimize.sil.preserve_exclusivity"] [canonical] @$S20preserve_exclusivity13f3__readNoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// DESERIALIZED: begin_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f3__readNoOptyyBp_BpmtF
-
-@inlinable
-@_semantics("optimize.sil.preserve_exclusivity")
-public func f3__readNoOpt(_ address: Builtin.RawPointer, _ ty1: Builtin.RawPointer.Type) {
- marker3()
- Builtin.performInstantaneousReadAccess(address, ty1);
-}
-
-// DESERIALIZED-LABEL: sil [serialized] [canonical] @$S20preserve_exclusivity13f4__testNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// DESERIALIZED: marker1
-// DESERIALIZED: begin_unpaired_access
-// DESERIALIZED: marker2
-// DESERIALIZED: end_unpaired_access
-// DESERIALIZED: marker3
-// DESERIALIZED: begin_unpaired_access
-// DESERIALIZED: return
-
-@inlinable
-public func f4__testNoOpt(_ k1: Builtin.RawPointer) {
- f1_beginNoOpt(k1, k1, Builtin.RawPointer.self)
- f2___endNoOpt(k1)
- f3__readNoOpt(k1, Builtin.RawPointer.self)
-}
-
-// CHECK-LABEL: sil @$S20preserve_exclusivity13f5_beginDoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// CHECK-NOT: begin_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f5_beginDoOptyyBp_BpxmtlF'
-
-// DESERIALIZED-LABEL: sil [serialized] [canonical] @$S20preserve_exclusivity13f5_beginDoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
-// DESERIALIZED-NOT: begin_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f5_beginDoOptyyBp_BpxmtlF'
-
-@inlinable
-public func f5_beginDoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
- marker4()
- Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
-}
-
-// CHECK-LABEL: sil @$S20preserve_exclusivity13f6___endDoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// CHECK-NOT: end_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f6___endDoOptyyBpF'
-
-// DESERIALIZED-LABEL: sil [serialized] [canonical] @$S20preserve_exclusivity13f6___endDoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// DESERIALIZED-NOT: end_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f6___endDoOptyyBpF'
-
-@inlinable
-public func f6___endDoOpt(_ address: Builtin.RawPointer) {
- marker5()
- Builtin.endUnpairedAccess(address)
-}
-
-// CHECK-LABEL: sil @$S20preserve_exclusivity13f7__readDoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// CHECK-NOT: begin_unpaired_access
-// CHECK: } // end sil function '$S20preserve_exclusivity13f7__readDoOptyyBp_BpmtF'
-
-// DESERIALIZED-LABEL: sil [serialized] [canonical] @$S20preserve_exclusivity13f7__readDoOptyyBp_BpmtF : $@convention(thin) (Builtin.RawPointer, @thin Builtin.RawPointer.Type) -> () {
-// DESERIALIZED-NOT: begin_unpaired_access
-// DESERIALIZED: } // end sil function '$S20preserve_exclusivity13f7__readDoOptyyBp_BpmtF'
-
-@inlinable
-public func f7__readDoOpt(_ address: Builtin.RawPointer, _ ty1: Builtin.RawPointer.Type) {
- marker6()
- Builtin.performInstantaneousReadAccess(address, ty1);
-}
-
-// DESERIALIZED-LABEL: sil [serialized] [canonical] @$S20preserve_exclusivity13f8__testDoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
-// DESERIALIZED: marker4
-// DESERIALIZED: marker5
-// DESERIALIZED: marker6
-// DESERIALIZED: return
-@inlinable
-public func f8__testDoOpt(_ k1: Builtin.RawPointer) {
- f5_beginDoOpt(k1, k1, Builtin.RawPointer.self)
- f6___endDoOpt(k1)
- f7__readDoOpt(k1, Builtin.RawPointer.self)
-}
diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil
index 0f4a3af..994feaa 100644
--- a/test/SILOptimizer/sil_combine.sil
+++ b/test/SILOptimizer/sil_combine.sil
@@ -404,8 +404,8 @@
// CHECK-LABEL: sil @a2p_p2a_reinterpret_cast_word_raw_pointer
// CHECK: bb0
+// CHECK-NEXT: unchecked_addr_cast
// CHECK-NEXT: load
-// CHECK-NEXT: unchecked_trivial_bit_cast
// CHECK-NEXT: return
sil @a2p_p2a_reinterpret_cast_word_raw_pointer : $@convention(thin) (@inout Builtin.Word, Builtin.RawPointer) -> Int32 {
bb0(%0 : $*Builtin.Word, %1 : $Builtin.RawPointer):
@@ -1133,9 +1133,9 @@
// CHECK-LABEL: sil @unchecked_addr_cast_formation : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
// CHECK: bb0([[INPUT_PTR:%[0-9]+]] : $*Builtin.NativeObject):
-// CHECK-NEXT: [[INPUT_VALUE:%[0-9]+]] = load [[INPUT_PTR]] : $*Builtin.NativeObject
-// CHECK-NEXT: [[CAST_VALUE:%[0-9]+]] = unchecked_trivial_bit_cast [[INPUT_VALUE]] : $Builtin.NativeObject to $Builtin.Word
-// CHECK-NEXT: return
+// CHECK-NEXT: [[ADDR_CAST:%[0-9]+]] = unchecked_addr_cast [[INPUT_PTR]] : $*Builtin.NativeObject to $*Builtin.Word
+// CHECK-NEXT: [[RETURN_VALUE:%[0-9]+]] = load [[ADDR_CAST]] : $*Builtin.Word
+// CHECK-NEXT: return [[RETURN_VALUE]]
sil @unchecked_addr_cast_formation : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
bb0(%0 : $*Builtin.NativeObject):
%1 = address_to_pointer %0 : $*Builtin.NativeObject to $Builtin.RawPointer
@@ -1146,9 +1146,10 @@
// CHECK-LABEL: sil @unchecked_addr_cast_forwarding : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
// CHECK: bb0([[INPUT_PTR:%[0-9]+]] : $*Builtin.NativeObject):
-// CHECK-NEXT: [[INPUT_VALUE:%[0-9]+]] = load [[INPUT_PTR]] : $*Builtin.NativeObject
-// CHECK-NEXT: [[CAST_VALUE:%[0-9]+]] = unchecked_trivial_bit_cast [[INPUT_VALUE]] : $Builtin.NativeObject to $Builtin.Word
-// CHECK-NEXT: return
+// CHECK-NEXT: [[ADDR_CAST:%[0-9]+]] = unchecked_addr_cast [[INPUT_PTR]] : $*Builtin.NativeObject to $*Builtin.Word
+// CHECK-NEXT: debug_value [[ADDR_CAST]]
+// CHECK-NEXT: [[RETURN_VALUE:%[0-9]+]] = load [[ADDR_CAST]] : $*Builtin.Word
+// CHECK-NEXT: return [[RETURN_VALUE]]
sil @unchecked_addr_cast_forwarding : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
bb0(%0 : $*Builtin.NativeObject):
%1 = unchecked_addr_cast %0 : $*Builtin.NativeObject to $*Builtin.RawPointer
diff --git a/test/Serialization/Inputs/def_basic.sil b/test/Serialization/Inputs/def_basic.sil
index b14ff89..a3b1a25 100644
--- a/test/Serialization/Inputs/def_basic.sil
+++ b/test/Serialization/Inputs/def_basic.sil
@@ -1287,6 +1287,31 @@
return %20 : $()
}
+// CHECK-LABEL: sil public_external [transparent] [serialized] @test_builtin_access : $@convention(thin) (@guaranteed A) -> () {
+// CHECK: begin_access [read] [dynamic] [builtin]
+// CHECK: end_access
+// CHECK: begin_unpaired_access [read] [dynamic] [builtin]
+// CHECK: end_unpaired_access [dynamic] [builtin]
+// CHECK-LABEL: } // end sil function 'test_builtin_access'
+sil [transparent] [serialized] @test_builtin_access : $@convention(thin) (@guaranteed A) -> () {
+bb0(%0 : $A):
+ %1 = alloc_stack $Any
+ %2 = ref_element_addr %0 : $A, #A.property
+ %6 = begin_access [dynamic] [read] [builtin] %2 : $*Any
+ copy_addr %6 to %1 : $*Any
+ end_access %6 : $*Any
+ destroy_addr %1 : $*Any
+ %9 = alloc_stack $Builtin.UnsafeValueBuffer
+ begin_unpaired_access [read] [dynamic] [builtin] %2 : $*Any, %9 : $*Builtin.UnsafeValueBuffer
+ copy_addr %2 to %1 : $*Any
+ end_unpaired_access [dynamic] [builtin] %9 : $*Builtin.UnsafeValueBuffer
+ destroy_addr %1 : $*Any
+ dealloc_stack %9 : $*Builtin.UnsafeValueBuffer
+ dealloc_stack %1 : $*Any
+ %20 = tuple ()
+ return %20 : $()
+}
+
public class Foo {
subscript (x: Int, y: Int) -> Int32 { get set }
var x: Int
@@ -1494,6 +1519,7 @@
%152 = function_ref @a_regular_thunk: $@convention(thin) () -> ()
%153 = function_ref @weak_unowned: $@convention(thin) (@owned WeakUnownedTest, @owned AnyObject) -> ()
%154 = function_ref @test_access : $@convention(thin) (@guaranteed A) -> ()
+ %155 = function_ref @test_builtin_access : $@convention(thin) (@guaranteed A) -> ()
%r = tuple ()
return %r : $()
diff --git a/validation-test/stdlib/OpenCLSDKOverlay.swift b/validation-test/stdlib/OpenCLSDKOverlay.swift
index 58959c5..e877aeb 100644
--- a/validation-test/stdlib/OpenCLSDKOverlay.swift
+++ b/validation-test/stdlib/OpenCLSDKOverlay.swift
@@ -194,7 +194,7 @@
kernel!, 3,
0, MemoryLayout<cl_mem>.size, inputPtr,
1, MemoryLayout<cl_mem>.size, outputPtr,
- 2, MemoryLayout.size(ofValue: count), countPtr)
+ 2, MemoryLayout.size(ofValue: countPtr.pointee), countPtr)
}
}
}