Merge pull request #20952 from xwu/stdlib-style-fixes
diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def
index 432f60e..f88c975 100644
--- a/include/swift/AST/Builtins.def
+++ b/include/swift/AST/Builtins.def
@@ -478,14 +478,6 @@
BUILTIN_MISC_OPERATION(SToUCheckedTrunc, "s_to_u_checked_trunc", "n", Special)
BUILTIN_MISC_OPERATION(UToUCheckedTrunc, "u_to_u_checked_trunc", "n", Special)
-/// Checked conversions for signed <-> unsigned integers of the same size.
-/// Returns a tuple containing the conversion result as well as
-/// the sign error / overflow bit.
-BUILTIN_MISC_OPERATION(SUCheckedConversion,
- "s_to_u_checked_conversion", "n", Special)
-BUILTIN_MISC_OPERATION(USCheckedConversion,
- "u_to_s_checked_conversion", "n", Special)
-
/// IntToFPWithOverflow has type (Integer) -> Float
BUILTIN_MISC_OPERATION(IntToFPWithOverflow, "itofp_with_overflow", "n", Special)
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index dd1d1e9..658fef3 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -5631,10 +5631,6 @@
return getSelfAccessKind() == SelfAccessKind::__Consuming;
}
- TypeLoc getReturnTypeLoc() const {
- return FnRetType;
- }
-
SelfAccessKind getSelfAccessKind() const {
return static_cast<SelfAccessKind>(Bits.FuncDecl.SelfAccess);
}
diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h
index b5c1313..ae3fc3e 100644
--- a/include/swift/SIL/PatternMatch.h
+++ b/include/swift/SIL/PatternMatch.h
@@ -715,13 +715,6 @@
// if any of the sub-matchers succeed.
//
-/// Matcher for any of the builtin checked conversions.
-template <typename T0>
-inline typename OneOf_match<BuiltinApplyTy<T0>, BuiltinApplyTy<T0>>::Ty
-m_CheckedConversion(const T0 &Op0) {
- return m_USCheckedConversion(Op0) || m_SUCheckedConversion(Op0);
-}
-
/// Matcher for any of the builtin ExtOrBitCast instructions.
template <typename T0>
inline typename OneOf_match<BuiltinApplyTy<T0>, BuiltinApplyTy<T0>>::Ty
diff --git a/include/swift/SILOptimizer/Utils/Existential.h b/include/swift/SILOptimizer/Utils/Existential.h
index 4ac1807..fa0f3c6 100644
--- a/include/swift/SILOptimizer/Utils/Existential.h
+++ b/include/swift/SILOptimizer/Utils/Existential.h
@@ -35,7 +35,7 @@
/// alloc_stack user \p ASIUser.
/// If the value is copied from another stack location, \p isCopied is set to
/// true.
-SILValue getAddressOfStackInit(AllocStackInst *ASI, SILInstruction *ASIUser,
+SILValue getAddressOfStackInit(SILValue allocStackAddr, SILInstruction *ASIUser,
bool &isCopied);
/// Find the init_existential, which could be used to determine a concrete
diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h
index f5cb3dc..f0348a0 100644
--- a/include/swift/SILOptimizer/Utils/Local.h
+++ b/include/swift/SILOptimizer/Utils/Local.h
@@ -127,6 +127,13 @@
SILValue Value,
SILType SrcTy,
SILType DestTy);
+/// Peek through trivial Enum initialization, typically for pointless
+/// Optionals.
+///
+/// The returned InitEnumDataAddr dominates the given
+/// UncheckedTakeEnumDataAddrInst.
+InitEnumDataAddrInst *
+findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI);
/// Returns a project_box if it is the next instruction after \p ABI and
/// and has \p ABI as operand. Otherwise it creates a new project_box right
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index 931af61..64abf0d 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -1106,19 +1106,6 @@
return getBuiltinFunction(Id, { InTy }, ResultTy);
}
-static ValueDecl *getCheckedConversionOperation(ASTContext &Context,
- Identifier Id,
- Type Ty) {
- Type BuiltinTy = Ty->getAs<BuiltinIntegerType>();
- if (!BuiltinTy)
- return nullptr;
-
- Type SignErrorBitTy = BuiltinIntegerType::get(1, Context);
- TupleTypeElt ResultElts[] = { BuiltinTy, SignErrorBitTy };
- Type ResultTy = TupleType::get(ResultElts, Context);
- return getBuiltinFunction(Id, { BuiltinTy }, ResultTy);
-}
-
static ValueDecl *getIntToFPWithOverflowOperation(ASTContext &Context,
Identifier Id, Type InputTy,
Type OutputTy) {
@@ -1853,11 +1840,6 @@
if (Types.size() != 2) return nullptr;
return getCheckedTruncOperation(Context, Id, Types[0], Types[1], false);
- case BuiltinValueKind::SUCheckedConversion:
- case BuiltinValueKind::USCheckedConversion:
- if (Types.size() != 1) return nullptr;
- return getCheckedConversionOperation(Context, Id, Types[0]);
-
case BuiltinValueKind::ClassifyBridgeObject:
if (!Types.empty()) return nullptr;
return getClassifyBridgeObject(Context, Id);
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index c88a2e9..adee7cf 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -749,7 +749,7 @@
AFD->getSignatureSourceRange());
if (FD) {
SN.TypeRange = charSourceRangeFromSourceRange(SM,
- FD->getReturnTypeLoc().getSourceRange());
+ FD->getBodyResultTypeLoc().getSourceRange());
}
pushStructureNode(SN, AFD);
} else if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp
index 8607de9..3dbbf68 100644
--- a/lib/IRGen/GenBuiltin.cpp
+++ b/lib/IRGen/GenBuiltin.cpp
@@ -758,22 +758,6 @@
return out.add(OverflowFlag);
}
- if (Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
- Builtin.ID == BuiltinValueKind::USCheckedConversion) {
- auto Ty =
- IGF.IGM.getStorageTypeForLowered(Builtin.Types[0]->getCanonicalType());
-
- // Report a sign error if the input parameter is a negative number, when
- // interpreted as signed.
- llvm::Value *Arg = args.claimNext();
- llvm::Value *Zero = llvm::ConstantInt::get(Ty, 0);
- llvm::Value *OverflowFlag = IGF.Builder.CreateICmpSLT(Arg, Zero);
-
- // Return the tuple: (the result (same as input), the overflow flag).
- out.add(Arg);
- return out.add(OverflowFlag);
- }
-
// We are currently emitting code for '_convertFromBuiltinIntegerLiteral',
// which will call the builtin and pass it a non-compile-time-const parameter.
if (Builtin.ID == BuiltinValueKind::IntToFPWithOverflow) {
diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp
index 155d6fe..2e4ddda 100644
--- a/lib/SIL/OperandOwnership.cpp
+++ b/lib/SIL/OperandOwnership.cpp
@@ -1122,7 +1122,6 @@
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SSubOver)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SToSCheckedTrunc)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SToUCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SUCheckedConversion)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, Shl)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, Sizeof)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, StaticReport)
@@ -1140,7 +1139,6 @@
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UIToFP)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UMulOver)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, URem)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, USCheckedConversion)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, USubOver)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UToSCheckedTrunc)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UToUCheckedTrunc)
diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp
index 7159493..5c3e131 100644
--- a/lib/SIL/ValueOwnership.cpp
+++ b/lib/SIL/ValueOwnership.cpp
@@ -479,8 +479,6 @@
CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToSCheckedTrunc)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToUCheckedTrunc)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToUCheckedTrunc)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, SUCheckedConversion)
-CONSTANT_OWNERSHIP_BUILTIN(Trivial, USCheckedConversion)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToFPWithOverflow)
// This is surprising, Builtin.unreachable returns a "Never" value which is
diff --git a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp
index 09e203f..21a7c05 100644
--- a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp
+++ b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp
@@ -492,18 +492,6 @@
return Result;
}
- // trunc(tuple_extract(conversion(extOrBitCast(x))))) -> x
- if (match(Op, m_TupleExtractInst(
- m_CheckedConversion(
- m_ExtOrBitCast(m_SILValue(Result))), 0))) {
- // If the top bit of Result is known to be 0, then
- // it is safe to replace the whole pattern by original bits of x
- if (Result->getType() == BI->getType()) {
- if (auto signBit = computeSignBit(Result))
- if (!signBit.getValue())
- return Result;
- }
- }
return SILValue();
}
@@ -639,23 +627,6 @@
switch (Builtin.ID) {
default: break;
- case BuiltinValueKind::SUCheckedConversion:
- case BuiltinValueKind::USCheckedConversion: {
- OperandValueArrayRef Args = BI->getArguments();
- const SILValue &Op = Args[0];
- if (auto signBit = computeSignBit(Op))
- if (!signBit.getValue())
- return Op;
- SILValue Result;
- // CheckedConversion(ExtOrBitCast(x)) -> x
- if (match(BI, m_CheckedConversion(m_ExtOrBitCast(m_SILValue(Result)))))
- if (Result->getType() == BI->getType().getTupleElementType(0)) {
- assert (!computeSignBit(Result).getValue() && "Sign bit should be 0");
- return Result;
- }
- }
- break;
-
case BuiltinValueKind::UToSCheckedTrunc:
case BuiltinValueKind::UToUCheckedTrunc:
case BuiltinValueKind::SToUCheckedTrunc:
diff --git a/lib/SILOptimizer/Analysis/ValueTracking.cpp b/lib/SILOptimizer/Analysis/ValueTracking.cpp
index 02b71d4..58d0e3a 100644
--- a/lib/SILOptimizer/Analysis/ValueTracking.cpp
+++ b/lib/SILOptimizer/Analysis/ValueTracking.cpp
@@ -296,25 +296,6 @@
continue;
}
- // Source and target type sizes are the same.
- // S->U conversion can only succeed if
- // the sign bit of its operand is 0, i.e. it is >= 0.
- // The sign bit of a result is 0 only if the sign
- // bit of a source operand is 0.
- case BuiltinValueKind::SUCheckedConversion:
- Value = BI->getArguments()[0];
- continue;
-
- // Source and target type sizes are the same.
- // U->S conversion can only succeed if
- // the top bit of its operand is 0, i.e.
- // it is representable as a signed integer >=0.
- // The sign bit of a result is 0 only if the sign
- // bit of a source operand is 0.
- case BuiltinValueKind::USCheckedConversion:
- Value = BI->getArguments()[0];
- continue;
-
// Sign bit of the operand is promoted.
case BuiltinValueKind::SExt:
Value = BI->getArguments()[0];
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
index 51dc183..c6fbe6b 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
@@ -722,6 +722,13 @@
SILValue existentialAddr =
cast<InitExistentialAddrInst>(InitExistential)->getOperand();
+ // If we peeked through an InitEnumDataAddr or some such, then don't assume we
+ // can reuse the copied value. It's likely destroyed by
+ // UncheckedTakeEnumDataInst before the copy.
+ auto *ASI = dyn_cast<AllocStackInst>(existentialAddr);
+ if (!ASI)
+ return false;
+
// Return true only if the given value is guaranteed to be initialized across
// the given call site.
//
diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
index d73f09b..2ca1417 100644
--- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
+++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
@@ -122,8 +122,6 @@
case BuiltinValueKind::SToUCheckedTrunc:
case BuiltinValueKind::SToSCheckedTrunc:
case BuiltinValueKind::UToUCheckedTrunc:
- case BuiltinValueKind::SUCheckedConversion:
- case BuiltinValueKind::USCheckedConversion:
case BuiltinValueKind::IntToFPWithOverflow:
case BuiltinValueKind::ZeroInitializer:
case BuiltinValueKind::Once:
diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp
index 0afc9a6..0b4de9a 100644
--- a/lib/SILOptimizer/Utils/ConstExpr.cpp
+++ b/lib/SILOptimizer/Utils/ConstExpr.cpp
@@ -210,8 +210,6 @@
if (!operand.isConstant())
return operand;
- // TODO: SUCheckedConversion/USCheckedConversion
-
// Implement support for s_to_s_checked_trunc_Int2048_Int64 and other
// checking integer truncates. These produce a tuple of the result value
// and an overflow bit.
diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp
index 259c08e..0bc6a21 100644
--- a/lib/SILOptimizer/Utils/ConstantFolding.cpp
+++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp
@@ -674,9 +674,7 @@
assert(Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
Builtin.ID == BuiltinValueKind::UToUCheckedTrunc ||
Builtin.ID == BuiltinValueKind::SToUCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::UToSCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
- Builtin.ID == BuiltinValueKind::USCheckedConversion);
+ Builtin.ID == BuiltinValueKind::UToSCheckedTrunc);
// Check if we are converting a constant integer.
OperandValueArrayRef Args = BI->getArguments();
@@ -688,11 +686,9 @@
auto SrcBitWidth = SrcVal.getBitWidth();
bool DstTySigned = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::UToSCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::USCheckedConversion);
+ Builtin.ID == BuiltinValueKind::UToSCheckedTrunc);
bool SrcTySigned = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::SToUCheckedTrunc ||
- Builtin.ID == BuiltinValueKind::SUCheckedConversion);
+ Builtin.ID == BuiltinValueKind::SToUCheckedTrunc);
// Get source type and bit width.
auto SrcTy = Builtin.Types[0]->castTo<AnyBuiltinIntegerType>();
@@ -705,44 +701,33 @@
bool OverflowError;
Type DstTy;
- // Process conversions signed <-> unsigned for same size integers.
- if (Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
- Builtin.ID == BuiltinValueKind::USCheckedConversion) {
- DstTy = SrcTy;
+ assert(Builtin.Types.size() == 2);
+ DstTy = Builtin.Types[1];
+ uint32_t DstBitWidth =
+ DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth();
+
+ assert((DstBitWidth < SrcBitWidth || !SrcTy->getWidth().isFixedWidth()) &&
+ "preconditions on builtin trunc operations should prevent"
+ "fixed-width truncations that actually extend");
+
+ // The only way a true extension can overflow is if the value is
+ // negative and the result is unsigned.
+ if (DstBitWidth > SrcBitWidth) {
+ OverflowError = (SrcTySigned && !DstTySigned && SrcVal.isNegative());
+ Result = (SrcTySigned ? SrcVal.sext(DstBitWidth)
+ : SrcVal.zext(DstBitWidth));
+
+ // A same-width change can overflow if the top bit disagrees.
+ } else if (DstBitWidth == SrcBitWidth) {
+ OverflowError = (SrcTySigned != DstTySigned && SrcVal.isNegative());
Result = SrcVal;
- // Report an error if the sign bit is set.
- OverflowError = SrcVal.isNegative();
- // Process the checked truncations.
+ // A truncation can overflow if the value changes.
} else {
- assert(Builtin.Types.size() == 2);
- DstTy = Builtin.Types[1];
- uint32_t DstBitWidth =
- DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth();
-
- assert((DstBitWidth < SrcBitWidth || !SrcTy->getWidth().isFixedWidth()) &&
- "preconditions on builtin trunc operations should prevent"
- "fixed-width truncations that actually extend");
-
- // The only way a true extension can overflow is if the value is
- // negative and the result is unsigned.
- if (DstBitWidth > SrcBitWidth) {
- OverflowError = (SrcTySigned && !DstTySigned && SrcVal.isNegative());
- Result = (SrcTySigned ? SrcVal.sext(DstBitWidth)
- : SrcVal.zext(DstBitWidth));
-
- // A same-width change can overflow if the top bit disagrees.
- } else if (DstBitWidth == SrcBitWidth) {
- OverflowError = (SrcTySigned != DstTySigned && SrcVal.isNegative());
- Result = SrcVal;
-
- // A truncation can overflow if the value changes.
- } else {
- Result = SrcVal.trunc(DstBitWidth);
- APInt Ext = (DstTySigned ? Result.sext(SrcBitWidth)
- : Result.zext(SrcBitWidth));
- OverflowError = (SrcVal != Ext);
- }
+ Result = SrcVal.trunc(DstBitWidth);
+ APInt Ext = (DstTySigned ? Result.sext(SrcBitWidth)
+ : Result.zext(SrcBitWidth));
+ OverflowError = (SrcVal != Ext);
}
// Check for overflow.
@@ -819,25 +804,19 @@
DstTySigned, DstTy, SrcAsString);
}
} else {
- if (Builtin.ID == BuiltinValueKind::SUCheckedConversion) {
+ // Try to print user-visible types if they are available.
+ if (!UserSrcTy.isNull()) {
diagnose(M.getASTContext(), Loc.getSourceLoc(),
- diag::integer_conversion_sign_error,
- UserDstTy.isNull() ? DstTy : UserDstTy);
- } else {
- // Try to print user-visible types if they are available.
- if (!UserSrcTy.isNull()) {
- diagnose(M.getASTContext(), Loc.getSourceLoc(),
- diag::integer_conversion_overflow,
- UserSrcTy, UserDstTy);
+ diag::integer_conversion_overflow,
+ UserSrcTy, UserDstTy);
- // Otherwise, print the Builtin Types.
- } else {
- // Since builtin types are sign-agnostic, print the signedness
- // separately.
- diagnose(M.getASTContext(), Loc.getSourceLoc(),
- diag::integer_conversion_overflow_builtin_types,
- SrcTySigned, SrcTy, DstTySigned, DstTy);
- }
+ // Otherwise, print the Builtin Types.
+ } else {
+ // Since builtin types are sign-agnostic, print the signedness
+ // separately.
+ diagnose(M.getASTContext(), Loc.getSourceLoc(),
+ diag::integer_conversion_overflow_builtin_types,
+ SrcTySigned, SrcTy, DstTySigned, DstTy);
}
}
@@ -1220,9 +1199,7 @@
case BuiltinValueKind::SToSCheckedTrunc:
case BuiltinValueKind::UToUCheckedTrunc:
case BuiltinValueKind::SToUCheckedTrunc:
- case BuiltinValueKind::UToSCheckedTrunc:
- case BuiltinValueKind::SUCheckedConversion:
- case BuiltinValueKind::USCheckedConversion: {
+ case BuiltinValueKind::UToSCheckedTrunc: {
return constantFoldAndCheckIntegerConversions(BI, Builtin, ResultsInError);
}
diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp
index 4192183..6e32257 100644
--- a/lib/SILOptimizer/Utils/Existential.cpp
+++ b/lib/SILOptimizer/Utils/Existential.cpp
@@ -10,12 +10,13 @@
//
//===----------------------------------------------------------------------===//
+#include "swift/SILOptimizer/Utils/Existential.h"
#include "swift/AST/Module.h"
#include "swift/AST/ProtocolConformance.h"
-#include "swift/SILOptimizer/Utils/Existential.h"
-#include "swift/SILOptimizer/Utils/CFG.h"
-#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/BasicBlockUtils.h"
+#include "swift/SIL/InstructionUtils.h"
+#include "swift/SILOptimizer/Utils/CFG.h"
+#include "swift/SILOptimizer/Utils/Local.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace swift;
@@ -122,11 +123,14 @@
/// alloc_stack user \p ASIUser.
/// If the value is copied from another stack location, \p isCopied is set to
/// true.
-SILValue swift::getAddressOfStackInit(AllocStackInst *ASI,
+///
+/// allocStackAddr may either itself be an AllocStackInst or an
+/// InitEnumDataAddrInst that projects the value of an AllocStackInst.
+SILValue swift::getAddressOfStackInit(SILValue allocStackAddr,
SILInstruction *ASIUser, bool &isCopied) {
SILInstruction *SingleWrite = nullptr;
// Check that this alloc_stack is initialized only once.
- for (auto Use : ASI->getUses()) {
+ for (auto Use : allocStackAddr->getUses()) {
auto *User = Use->getUser();
// Ignore instructions which don't write to the stack location.
@@ -138,7 +142,7 @@
continue;
}
if (auto *CAI = dyn_cast<CopyAddrInst>(User)) {
- if (CAI->getDest() == ASI) {
+ if (CAI->getDest() == allocStackAddr) {
if (SingleWrite)
return SILValue();
SingleWrite = CAI;
@@ -168,8 +172,13 @@
// A very simple dominance check. As ASI is an operand of ASIUser,
// SingleWrite dominates ASIUser if it is in the same block as ASI or ASIUser.
+ //
+ // If allocStack holds an Optional, then ASI is an InitEnumDataAddrInst
+ // projection and not strictly an operand of ASIUser. We rely on the guarantee
+ // that this InitEnumDataAddrInst must occur before the InjectEnumAddrInst
+ // that was the source of the existential address.
SILBasicBlock *BB = SingleWrite->getParent();
- if (BB != ASI->getParent() && BB != ASIUser->getParent())
+ if (BB != allocStackAddr->getParentBlock() && BB != ASIUser->getParent())
return SILValue();
if (auto *CAI = dyn_cast<CopyAddrInst>(SingleWrite)) {
@@ -179,6 +188,21 @@
SILValue CAISrc = CAI->getSrc();
if (auto *ASI = dyn_cast<AllocStackInst>(CAISrc))
return getAddressOfStackInit(ASI, CAI, isCopied);
+
+ // Recognize a stack location holding an Optional.
+ // %stack_adr = alloc_stack
+ // %data_adr = init_enum_data_addr %stk_adr
+ // %enum_adr = inject_enum_addr %stack_adr
+ // %copy_src = unchecked_take_enum_data_addr %enum_adr
+ // Replace %copy_src with %data_adr and recurse.
+ //
+ // TODO: a general Optional elimination sil-combine could
+ // supersede this check.
+ if (auto *UTEDAI = dyn_cast<UncheckedTakeEnumDataAddrInst>(CAISrc)) {
+ if (InitEnumDataAddrInst *IEDAI = findInitAddressForTrivialEnum(UTEDAI))
+ return getAddressOfStackInit(IEDAI, CAI, isCopied);
+ }
+
// Check if the CAISrc is a global_addr.
if (auto *GAI = dyn_cast<GlobalAddrInst>(CAISrc)) {
return findInitExistentialFromGlobalAddrAndCopyAddr(GAI, CAI);
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index 4f71557..3971d64 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -653,6 +653,51 @@
return B.createProjectBox(ABI->getLoc(), ABI, Index);
}
+// Peek through trivial Enum initialization, typically for pointless
+// Optionals.
+//
+// Given an UncheckedTakeEnumDataAddrInst, check that there are no
+// other uses of the Enum value and return the address used to initialized the
+// enum's payload:
+//
+// %stack_adr = alloc_stack
+// %data_adr = init_enum_data_addr %stk_adr
+// %enum_adr = inject_enum_addr %stack_adr
+// %copy_src = unchecked_take_enum_data_addr %enum_adr
+// dealloc_stack %stack_adr
+// (No other uses of %stack_adr.)
+InitEnumDataAddrInst *
+swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI) {
+ auto *ASI = dyn_cast<AllocStackInst>(UTEDAI->getOperand());
+ if (!ASI)
+ return nullptr;
+
+ SILInstruction *singleUser = nullptr;
+ for (auto use : ASI->getUses()) {
+ auto *user = use->getUser();
+ if (user == UTEDAI)
+ continue;
+
+ // As long as there's only one UncheckedTakeEnumDataAddrInst and one
+ // InitEnumDataAddrInst, we don't care how many InjectEnumAddr and
+ // DeallocStack users there are.
+ if (isa<InjectEnumAddrInst>(user) || isa<DeallocStackInst>(user))
+ continue;
+
+ if (singleUser)
+ return nullptr;
+
+ singleUser = user;
+ }
+ if (!singleUser)
+ return nullptr;
+
+ // Assume, without checking, that the returned InitEnumDataAddr dominates the
+ // given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I
+ // don't know where this is actually verified.
+ return dyn_cast<InitEnumDataAddrInst>(singleUser);
+}
+
//===----------------------------------------------------------------------===//
// String Concatenation Optimizer
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 3a34ed6..78b9c2b 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -4940,7 +4940,7 @@
break;
case InvalidMethod::Reason::ReturnType:
- tc.diagnose(invalidMethod.method->getReturnTypeLoc().getLoc(),
+ tc.diagnose(invalidMethod.method->getBodyResultTypeLoc().getLoc(),
diag::append_interpolation_void_or_discardable)
.fixItInsert(invalidMethod.method->getStartLoc(),
"@discardableResult ");
diff --git a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift
index 6cca91d..e568607 100644
--- a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift
+++ b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift
@@ -1,8 +1,8 @@
-//===--- SwiftPrivateThreadExtras.swift ----------------------------------===//
+//===--- SwiftPrivateThreadExtras.swift -----------------------------------===//
//
// This source file is part of the Swift.org open source project
//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
diff --git a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift
index d0be2eb..ae6932b 100644
--- a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift
+++ b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift
@@ -1,8 +1,8 @@
-//===--- ThreadBarriers.swift --------------------------------------------===//
+//===--- ThreadBarriers.swift ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
diff --git a/stdlib/public/Platform/winsdk.modulemap b/stdlib/public/Platform/winsdk.modulemap
index 1d69b29..e398a81 100644
--- a/stdlib/public/Platform/winsdk.modulemap
+++ b/stdlib/public/Platform/winsdk.modulemap
@@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
diff --git a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
index 43c932c..401497b 100644
--- a/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
+++ b/test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.h
@@ -30,11 +30,11 @@
#endif // __OBJC__
-#import <APINotesFrameworkTest/Classes.h>
-#import <APINotesFrameworkTest/Enums.h>
-#import <APINotesFrameworkTest/Globals.h>
-#import <APINotesFrameworkTest/ImportAsMember.h>
-#import <APINotesFrameworkTest/Properties.h>
-#import <APINotesFrameworkTest/Protocols.h>
-#import <APINotesFrameworkTest/Types.h>
-#import <APINotesFrameworkTest/SwiftWrapper.h>
+#include <APINotesFrameworkTest/Classes.h>
+#include <APINotesFrameworkTest/Enums.h>
+#include <APINotesFrameworkTest/Globals.h>
+#include <APINotesFrameworkTest/ImportAsMember.h>
+#include <APINotesFrameworkTest/Properties.h>
+#include <APINotesFrameworkTest/Protocols.h>
+#include <APINotesFrameworkTest/Types.h>
+#include <APINotesFrameworkTest/SwiftWrapper.h>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d4350d0..fde14c2 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -250,7 +250,7 @@
set(LIT_ARGS "${SWIFT_TEST_EXTRA_ARGS} ${LLVM_LIT_ARGS}")
separate_arguments(LIT_ARGS)
- if(NOT SWIFT_BUILD_STDLIB)
+ if(NOT SWIFT_BUILD_STDLIB AND NOT SWIFT_PATH_TO_EXTERNAL_STDLIB_BUILD)
list(APPEND LIT_ARGS
"--param" "test_sdk_overlay_dir=${SWIFTLIB_DIR}/${SWIFT_SDK_${SDK}_LIB_SUBDIR}")
endif()
diff --git a/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h b/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h
index c91801c..c027342 100644
--- a/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h
+++ b/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h
@@ -1,4 +1,4 @@
-#import "app-bridging-header-to-pch.h"
+#include "app-bridging-header-to-pch.h"
static inline int unit_test_function(int x) {
return x + 28;
diff --git a/test/SILOptimizer/devirt_specialized_conformance.swift b/test/SILOptimizer/devirt_specialized_conformance.swift
index 62cb05d..9f636c0 100644
--- a/test/SILOptimizer/devirt_specialized_conformance.swift
+++ b/test/SILOptimizer/devirt_specialized_conformance.swift
@@ -42,3 +42,32 @@
}
driver()
+
+// <rdar://problem/46322928> Failure to devirtualize a protocol method
+// applied to an opened existential blocks implemention of
+// DataProtocol.
+public protocol ContiguousBytes {
+ func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
+}
+
+extension Array : ContiguousBytes {}
+extension ContiguousArray : ContiguousBytes {}
+
+@inline(never)
+func takesPointer(_ p: UnsafeRawBufferPointer) {}
+
+// In specialized testWithUnsafeBytes<A>(_:), the conditional case and call to withUnsafeBytes must be eliminated.
+// CHECK-LABEL: sil shared [noinline] @$s30devirt_specialized_conformance19testWithUnsafeBytesyyxlFSayypG_Tg5 : $@convention(thin) (@guaranteed Array<Any>) -> () {
+// CHECK: bb0
+// CHECK-NOT: witness_method
+// CHECK: [[TAKES_PTR:%.*]] = function_ref @$s30devirt_specialized_conformance12takesPointeryySWF : $@convention(thin) (UnsafeRawBufferPointer) -> ()
+// CHECK: apply [[TAKES_PTR]](%{{.*}}) : $@convention(thin) (UnsafeRawBufferPointer) -> ()
+// CHECK-LABEL: } // end sil function '$s30devirt_specialized_conformance19testWithUnsafeBytesyyxlFSayypG_Tg5'
+@inline(never)
+func testWithUnsafeBytes<T>(_ t: T) {
+ if let cb = t as? ContiguousBytes {
+ cb.withUnsafeBytes { takesPointer($0) }
+ }
+}
+
+testWithUnsafeBytes([])
diff --git a/test/SILOptimizer/peephole_trunc_and_ext.sil b/test/SILOptimizer/peephole_trunc_and_ext.sil
index 171f00e..eab8a64 100644
--- a/test/SILOptimizer/peephole_trunc_and_ext.sil
+++ b/test/SILOptimizer/peephole_trunc_and_ext.sil
@@ -21,143 +21,6 @@
var value: Builtin.Word
}
-// peephole: Word(Int64(x >> 1)) -> (x >> 1)
-// CHECK-LABEL: sil @_TF4test29test_trunc_u_to_s_zext_lshr_1FSuSi : $@convention(thin) (BuiltinUWord) -> BuiltinWord
-// CHECK: builtin "lshr_Word"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-// test.test_trunc_u_to_s_zext_lshr_1 (BuiltinUWord) -> Swift.BuiltinWord
-sil @_TF4test29test_trunc_u_to_s_zext_lshr_1FSuSi : $@convention(thin) (BuiltinUWord) -> BuiltinWord {
-bb0(%0 : $BuiltinUWord):
- debug_value %0 : $BuiltinUWord, let, name "x" // id: %1
- %2 = integer_literal $Builtin.Word, 1 // user: %7
- br bb1 // id: %3
-
-bb1: // Preds: bb0
- br bb2 // id: %4
-
-bb2: // Preds: bb1
- %6 = struct_extract %0 : $BuiltinUWord, #BuiltinUWord.value // user: %7
- %7 = builtin "lshr_Word"(%6 : $Builtin.Word, %2 : $Builtin.Word) : $Builtin.Word // user: %8
- %8 = struct $BuiltinUWord (%7 : $Builtin.Word) // user: %11
- br bb3 // id: %9
-
-bb3: // Preds: bb2
- %11 = struct_extract %8 : $BuiltinUWord, #BuiltinUWord.value // user: %12
- %12 = builtin "zextOrBitCast_Word_Int64"(%11 : $Builtin.Word) : $Builtin.Int64 // user: %14
- %14 = builtin "u_to_s_checked_conversion_Int64"(%12 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) // users: %15, %16
- %15 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 0 // user: %18
- %16 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 1 // user: %17
- cond_fail %16 : $Builtin.Int1 // id: %17
- %18 = struct $Int64 (%15 : $Builtin.Int64) // user: %19
- %19 = struct_extract %18 : $Int64, #Int64._value // user: %21
- %21 = builtin "truncOrBitCast_Int64_Word"(%19 : $Builtin.Int64) : $Builtin.Word // user: %22
- %22 = struct $BuiltinWord (%21 : $Builtin.Word) // users: %23, %24
- debug_value %22 : $BuiltinWord, let, name "v1" // id: %23
- return %22 : $BuiltinWord // id: %24
-}
-
-
-// peephole: Word(Int64(x >> 10)) -> (x >> 1)
-// CHECK-LABEL: sil @_TF4test30test_trunc_u_to_s_zext_lshr_10FSuSi : $@convention(thin) (BuiltinUWord) -> BuiltinWord
-// CHECK: builtin "lshr_Word"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-// test.test_trunc_u_to_s_zext_lshr_10 (Swift.BuiltinUWord) -> Swift.BuiltinWord
-sil @_TF4test30test_trunc_u_to_s_zext_lshr_10FSuSi : $@convention(thin) (BuiltinUWord) -> BuiltinWord {
-bb0(%0 : $BuiltinUWord):
- debug_value %0 : $BuiltinUWord, let, name "x" // id: %1
- %2 = integer_literal $Builtin.Word, 10 // user: %7
- br bb1 // id: %3
-
-bb1: // Preds: bb0
- br bb2 // id: %4
-
-bb2: // Preds: bb1
- %6 = struct_extract %0 : $BuiltinUWord, #BuiltinUWord.value // user: %7
- %7 = builtin "lshr_Word"(%6 : $Builtin.Word, %2 : $Builtin.Word) : $Builtin.Word // user: %8
- %8 = struct $BuiltinUWord (%7 : $Builtin.Word) // user: %11
- br bb3 // id: %9
-
-bb3: // Preds: bb2
- %11 = struct_extract %8 : $BuiltinUWord, #BuiltinUWord.value // user: %12
- %12 = builtin "zextOrBitCast_Word_Int64"(%11 : $Builtin.Word) : $Builtin.Int64 // user: %14
- %14 = builtin "u_to_s_checked_conversion_Int64"(%12 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) // users: %15, %16
- %15 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 0 // user: %18
- %16 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 1 // user: %17
- cond_fail %16 : $Builtin.Int1 // id: %17
- %18 = struct $Int64 (%15 : $Builtin.Int64) // user: %19
- %19 = struct_extract %18 : $Int64, #Int64._value // user: %21
- %21 = builtin "truncOrBitCast_Int64_Word"(%19 : $Builtin.Int64) : $Builtin.Word // user: %22
- %22 = struct $BuiltinWord (%21 : $Builtin.Word) // users: %23, %24
- debug_value %22 : $BuiltinWord, let, name "v1" // id: %23
- return %22 : $BuiltinWord // id: %24
-}
-
-// no peephole: Word(Int64(x >> c)), where c is a variable
-// This should not trigger the optimization as it is not known if c > 0
-// CHECK-LABEL: sil @_TF4test31test_trunc_u_to_s_zext_lshr_varFTSuSu_Si : $@convention(thin) (BuiltinUWord, BuiltinUWord) -> BuiltinWord
-// CHECK: builtin "u_to_s_checked_conversion_Int64"
-// CHECK: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-// test.test_trunc_u_to_s_zext_lshr_var (Swift.BuiltinUWord, Swift.BuiltinUWord) -> Swift.BuiltinWord
-sil @_TF4test31test_trunc_u_to_s_zext_lshr_varFTSuSu_Si : $@convention(thin) (BuiltinUWord, BuiltinUWord) -> BuiltinWord {
-bb0(%0 : $BuiltinUWord, %1 : $BuiltinUWord):
- debug_value %0 : $BuiltinUWord, let, name "x" // id: %2
- debug_value %1 : $BuiltinUWord, let, name "c" // id: %3
- %4 = tuple ()
- %5 = tuple ()
- %6 = tuple ()
- %7 = tuple ()
- %8 = tuple ()
- %9 = tuple ()
- %10 = tuple ()
- %11 = tuple ()
- %12 = tuple ()
- br bb1 // id: %13
-
-bb1: // Preds: bb0
- %14 = integer_literal $Builtin.Word, 64 // user: %17
- %16 = struct_extract %1 : $BuiltinUWord, #BuiltinUWord.value // user: %17
- %17 = builtin "cmp_ult_Word"(%16 : $Builtin.Word, %14 : $Builtin.Word) : $Builtin.Int1 // user: %20
- %18 = integer_literal $Builtin.Int1, -1 // user: %20
- %20 = builtin "int_expect_Int1"(%17 : $Builtin.Int1, %18 : $Builtin.Int1) : $Builtin.Int1 // user: %21
- cond_br %20, bb2, bb3 // id: %21
-
-bb2: // Preds: bb1
- %23 = struct_extract %0 : $BuiltinUWord, #BuiltinUWord.value // user: %25
- %24 = struct_extract %1 : $BuiltinUWord, #BuiltinUWord.value // user: %25
- %25 = builtin "lshr_Word"(%23 : $Builtin.Word, %24 : $Builtin.Word) : $Builtin.Word // user: %26
- %26 = struct $BuiltinUWord (%25 : $Builtin.Word) // user: %35
- br bb4 // id: %27
-
-bb3: // Preds: bb1
- %28 = function_ref @fatalError : $@convention(thin) () -> Never // user: %32
- %29 = tuple ()
- %30 = tuple ()
- %31 = tuple ()
- %32 = apply %28() : $@convention(thin) () -> Never
- unreachable // id: %33
-
-bb4: // Preds: bb2
- %35 = struct_extract %26 : $BuiltinUWord, #BuiltinUWord.value // user: %36
- %36 = builtin "zextOrBitCast_Word_Int64"(%35 : $Builtin.Word) : $Builtin.Int64 // user: %38
- %38 = builtin "u_to_s_checked_conversion_Int64"(%36 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) // users: %39, %40
- %39 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 0 // user: %42
- %40 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 1 // user: %41
- cond_fail %40 : $Builtin.Int1 // id: %41
- %42 = struct $Int64 (%39 : $Builtin.Int64) // user: %43
- %43 = struct_extract %42 : $Int64, #Int64._value // user: %45
- %45 = builtin "truncOrBitCast_Int64_Word"(%43 : $Builtin.Int64) : $Builtin.Word // user: %46
- %46 = struct $BuiltinWord (%45 : $Builtin.Word) // users: %47, %48
- debug_value %46 : $BuiltinWord, let, name "v1" // id: %47
- return %46 : $BuiltinWord // id: %48
-}
-
// peephole: UInt16(Int32(x >> 1)) -> (x >> 1)
// CHECK-LABEL: sil @_TF4test36test_uint16_trunc_u_to_s_zext_lshr_1FVs6UInt16S0_ : $@convention(thin) (UInt16) -> UInt16
// CHECK: builtin "lshr_Int16"
@@ -233,60 +96,6 @@
return %20 : $Int16 // id: %22
}
-// No peephole for UWord(UInt64(x)), because it is not known if top bit of x is set
-// CHECK-LABEL: sil @_TF4test26test_trunc_s_to_u_zext_varFSiSu : $@convention(thin) (BuiltinWord) -> BuiltinUWord
-// This should not trigger the optimization as it is not known if top bit of x is set
-// CHECK: builtin "zextOrBitCast_Word_Int64"
-// CHECK: builtin "s_to_u_checked_conversion_Int64"
-// CHECK: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-// test.test_trunc_s_to_u_zext_var (Swift.BuiltinWord) -> Swift.BuiltinUWord
-sil @_TF4test26test_trunc_s_to_u_zext_varFSiSu : $@convention(thin) (BuiltinWord) -> BuiltinUWord {
-bb0(%0 : $BuiltinWord):
- debug_value %0 : $BuiltinWord, let, name "x" // id: %1
- %3 = struct_extract %0 : $BuiltinWord, #BuiltinWord.value // user: %4
- %4 = builtin "zextOrBitCast_Word_Int64"(%3 : $Builtin.Word) : $Builtin.Int64 // user: %6
- %6 = builtin "s_to_u_checked_conversion_Int64"(%4 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) // users: %7, %8
- %7 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 0 // user: %10
- %8 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 1 // user: %9
- cond_fail %8 : $Builtin.Int1 // id: %9
- %10 = struct $UInt64 (%7 : $Builtin.Int64) // user: %11
- %11 = struct_extract %10 : $UInt64, #UInt64._value // user: %13
- %13 = builtin "truncOrBitCast_Int64_Word"(%11 : $Builtin.Int64) : $Builtin.Word // user: %14
- %14 = struct $BuiltinUWord (%13 : $Builtin.Word) // user: %15
- return %14 : $BuiltinUWord // id: %15
-}
-
-
-// sizeof is known to return strictly positive values
-// peephole: UWord(UInt64(sizeof(Int.self))) -> sizeof(Int.self)
-// CHECK-LABEL: sil @_TF4test29test_trunc_s_to_u_zext_sizeofFT_Su : $@convention(thin) () -> BuiltinUWord
-// CHECK: builtin "sizeof"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "s_to_u_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-// test.test_trunc_s_to_u_zext_sizeof () -> Swift.BuiltinUWord
-sil @_TF4test29test_trunc_s_to_u_zext_sizeofFT_Su : $@convention(thin) () -> BuiltinUWord {
-bb0:
- %0 = metatype $@thin BuiltinWord.Type
- %2 = metatype $@thick BuiltinWord.Type // user: %3
- %3 = builtin "sizeof"<(BuiltinWord)>(%2 : $@thick (BuiltinWord).Type) : $Builtin.Word // user: %4
- %4 = struct $BuiltinWord (%3 : $Builtin.Word) // user: %6
- %6 = struct_extract %4 : $BuiltinWord, #BuiltinWord.value // user: %7
- %7 = builtin "zextOrBitCast_Word_Int64"(%6 : $Builtin.Word) : $Builtin.Int64 // user: %9
- %9 = builtin "s_to_u_checked_conversion_Int64"(%7 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) // users: %10, %11
- %10 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 0 // user: %13
- %11 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 1 // user: %12
- cond_fail %11 : $Builtin.Int1 // id: %12
- %13 = struct $UInt64 (%10 : $Builtin.Int64) // user: %14
- %14 = struct_extract %13 : $UInt64, #UInt64._value // user: %16
- %16 = builtin "truncOrBitCast_Int64_Word"(%14 : $Builtin.Int64) : $Builtin.Word // user: %17
- %17 = struct $BuiltinUWord (%16 : $Builtin.Word) // user: %18
- return %17 : $BuiltinUWord // id: %18
-}
-
-
// sizeof is known to return strictly positive values
// But Word ->Int64 is not a safe conversion
// No peephole for UInt16(UInt32(sizeof(Int.self)))
@@ -318,55 +127,6 @@
return %20 : $UInt16 // id: %21
}
-
-// peephole: UInt16(UInt32(Int16(x>>1))) -> x>>1
-// CHECK-LABEL: sil @_TF4test34test_int16_trunc_s_to_u_zext_int16FVs6UInt16S0_ : $@convention(thin) (UInt16) -> UInt16
-// CHECK: builtin "lshr_Int16"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int16"
-// CHECK-NOT: builtin "s_to_u_checked_conversion_Int16"
-// CHECK-NOT: builtin "sext_Int16_Int32"
-// CHECK-NOT: builtin "u_to_u_checked_trunc_Int32_Int16"
-// CHECK-NOT: tuple_extract
-// CHECK: return
-// test.test_int16_trunc_s_to_u_zext_int16 (Swift.UInt16) -> Swift.UInt16
-sil @_TF4test34test_int16_trunc_s_to_u_zext_int16FVs6UInt16S0_ : $@convention(thin) (UInt16) -> UInt16 {
-bb0(%0 : $UInt16):
- debug_value %0 : $UInt16, let, name "x" // id: %1
- %2 = integer_literal $Builtin.Int16, 1 // user: %7
- br bb1 // id: %3
-
-bb1: // Preds: bb0
- br bb2 // id: %4
-
-bb2: // Preds: bb1
- %6 = struct_extract %0 : $UInt16, #UInt16._value // user: %7
- %7 = builtin "lshr_Int16"(%6 : $Builtin.Int16, %2 : $Builtin.Int16) : $Builtin.Int16 // user: %8
- %8 = struct $UInt16 (%7 : $Builtin.Int16) // user: %10
- br bb3 // id: %9
-
-bb3: // Preds: bb2
- %10 = struct_extract %8 : $UInt16, #UInt16._value // user: %12
- %12 = builtin "u_to_s_checked_conversion_Int16"(%10 : $Builtin.Int16) : $(Builtin.Int16, Builtin.Int1) // users: %13, %14
- %13 = tuple_extract %12 : $(Builtin.Int16, Builtin.Int1), 0 // user: %16
- %14 = tuple_extract %12 : $(Builtin.Int16, Builtin.Int1), 1 // user: %15
- cond_fail %14 : $Builtin.Int1 // id: %15
- %16 = struct $Int16 (%13 : $Builtin.Int16) // user: %17
- %17 = struct_extract %16 : $Int16, #Int16._value // user: %19
- %19 = builtin "s_to_u_checked_conversion_Int16"(%17 : $Builtin.Int16) : $(Builtin.Int16, Builtin.Int1) // users: %20, %21
- %20 = tuple_extract %19 : $(Builtin.Int16, Builtin.Int1), 0 // user: %24
- %21 = tuple_extract %19 : $(Builtin.Int16, Builtin.Int1), 1 // user: %22
- cond_fail %21 : $Builtin.Int1 // id: %22
- %24 = builtin "sext_Int16_Int32"(%20 : $Builtin.Int16) : $Builtin.Int32 // user: %25
- %25 = struct $UInt32 (%24 : $Builtin.Int32) // user: %26
- %26 = struct_extract %25 : $UInt32, #UInt32._value // user: %28
- %28 = builtin "u_to_u_checked_trunc_Int32_Int16"(%26 : $Builtin.Int32) : $(Builtin.Int16, Builtin.Int1) // users: %29, %30
- %29 = tuple_extract %28 : $(Builtin.Int16, Builtin.Int1), 0 // user: %32
- %30 = tuple_extract %28 : $(Builtin.Int16, Builtin.Int1), 1 // user: %31
- cond_fail %30 : $Builtin.Int1 // id: %31
- %32 = struct $UInt16 (%29 : $Builtin.Int16) // user: %33
- return %32 : $UInt16 // id: %33
-}
-
// peephole: Int8(x & 127) -> remove overflow check
// CHECK-LABEL: sil @_TF22peephole_trunc_and_ext32test_s_to_s_checked_trunc_of_andFVs5Int32Vs4Int8 : $@convention(thin) (Int32) -> Int8
// CHECK: builtin "and_Int32"
diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil
index 08fda37..becb301 100644
--- a/test/SILOptimizer/sil_combine.sil
+++ b/test/SILOptimizer/sil_combine.sil
@@ -2198,134 +2198,6 @@
return %2 : $Builtin.RawPointer
}
-// CHECK-LABEL: sil @remove_trunc_utos_zext_of_and
-// CHECK: bb0([[Ref:%.*]]: $Builtin.Word):
-// CHECK: integer_literal $Builtin.Word, 4611686018427387903
-// CHECK: builtin "and_Word"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @remove_trunc_utos_zext_of_and : $@convention(thin) (Builtin.Word) -> (Builtin.Word) {
-bb0(%0 : $Builtin.Word):
- %1 = integer_literal $Builtin.Word, 4611686018427387903
- %2 = builtin "and_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
-// CHECK-LABEL: sil @dont_remove_trunc_utos_zext_of_and
-// CHECK: bb0([[Ref:%.*]]: $Builtin.Word, [[Ref:%.*]]: $Builtin.Word):
-// CHECK: builtin "and_Word"
-// CHECK: builtin "zextOrBitCast_Word_Int64"
-// CHECK: builtin "u_to_s_checked_conversion_Int64"
-// CHECK: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @dont_remove_trunc_utos_zext_of_and : $@convention(thin) (Builtin.Word, Builtin.Word) -> (Builtin.Word) {
-bb0(%0 : $Builtin.Word, %1 : $Builtin.Word):
- %2 = builtin "and_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
-// CHECK-LABEL: sil @remove_trunc_utos_zext_of_or
-// CHECK: bb0([[Ref:%.*]]: $Builtin.Word):
-// CHECK: integer_literal $Builtin.Word, 1
-// CHECK: builtin "lshr_Word"
-// CHECK: builtin "or_Word"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @remove_trunc_utos_zext_of_or : $@convention(thin) (Builtin.Word) -> (Builtin.Word) {
-bb0(%0 : $Builtin.Word):
- %1 = integer_literal $Builtin.Word, 1
- %l1 = builtin "lshr_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %2 = builtin "or_Word"(%l1 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
-// CHECK-LABEL: sil @dont_remove_trunc_utos_zext_of_or
-// CHECK: bb0([[Ref:%.*]]: $Builtin.Word):
-// CHECK: integer_literal $Builtin.Word, -2
-// CHECK: builtin "or_Word"
-// CHECK: builtin "zextOrBitCast_Word_Int64"
-// CHECK: builtin "u_to_s_checked_conversion_Int64"
-// CHECK: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @dont_remove_trunc_utos_zext_of_or : $@convention(thin) (Builtin.Word) -> (Builtin.Word) {
-bb0(%0 : $Builtin.Word):
- %1 = integer_literal $Builtin.Word, -2
- %2 = builtin "or_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
-// CHECK-LABEL: sil @remove_trunc_utos_zext_of_xor
-// CHECK: bb0:
-// CHECK: integer_literal $Builtin.Word, -1
-// CHECK: integer_literal $Builtin.Word, -1
-// CHECK: builtin "xor_Word"
-// CHECK-NOT: builtin "zextOrBitCast_Word_Int64"
-// CHECK-NOT: builtin "u_to_s_checked_conversion_Int64"
-// CHECK-NOT: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @remove_trunc_utos_zext_of_xor : $@convention(thin) () -> (Builtin.Word) {
-bb0:
- %0 = integer_literal $Builtin.Word, -1
- %1 = integer_literal $Builtin.Word, -1
- %2 = builtin "xor_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
-// CHECK-LABEL: sil @dont_remove_trunc_utos_zext_of_xor
-// CHECK: bb0([[Ref:%.*]]: $Builtin.Word):
-// CHECK: integer_literal $Builtin.Word, 1
-// CHECK: builtin "xor_Word"
-// CHECK: builtin "zextOrBitCast_Word_Int64"
-// CHECK: builtin "u_to_s_checked_conversion_Int64"
-// CHECK: builtin "truncOrBitCast_Int64_Word"
-// CHECK: return
-sil @dont_remove_trunc_utos_zext_of_xor : $@convention(thin) (Builtin.Word) -> (Builtin.Word) {
-bb0(%0 : $Builtin.Word):
- %1 = integer_literal $Builtin.Word, 1
- %2 = builtin "xor_Word"(%0 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.Word
- %3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
- %4 = builtin "u_to_s_checked_conversion_Int64"(%3 : $Builtin.Int64): $(Builtin.Int64, Builtin.Int1)
- %5 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 0
- %6 = tuple_extract %4 : $(Builtin.Int64, Builtin.Int1), 1
- cond_fail %6 : $Builtin.Int1
- %8 = builtin "truncOrBitCast_Int64_Word"(%5 : $Builtin.Int64) : $Builtin.Word
- return %8 : $Builtin.Word
-}
-
struct GenContainer<T> {
}
diff --git a/test/SILOptimizer/sil_combine_concrete_existential.sil b/test/SILOptimizer/sil_combine_concrete_existential.sil
index 9e93646..f8a96c8 100644
--- a/test/SILOptimizer/sil_combine_concrete_existential.sil
+++ b/test/SILOptimizer/sil_combine_concrete_existential.sil
@@ -437,3 +437,65 @@
%v = tuple ()
return %v : $()
}
+
+// <rdar://problem/46322928> Failure to devirtualize a protocol method
+// applied to an opened existential blocks implemention of
+// DataProtocol.
+public protocol ContiguousBytes {
+ func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
+}
+
+extension Array : ContiguousBytes {
+}
+
+// specialized thunk for @callee_guaranteed (@unowned UnsafeRawBufferPointer) -> (@error @owned Error)
+sil [transparent] [reabstraction_thunk] @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error)
+
+// Test that the witness method's opened archetype is replaced by a
+// concrete conformance.
+//
+// Note that the enum is destroyed by unchecked_take_enum_data_addr
+// before the apply (and the extracted data is destroy by the copy
+// itself), so SILCombine cannot replace the call's self
+// argument. Instead, we expect a later devirtualizer pass to just
+// insert a cast of the opened existential.
+//
+// CHECK-LABEL: sil shared [noinline] @testDevirtExistentialEnum : $@convention(thin) (@guaranteed Array<Int>) -> () {
+// CHECK: [[ALLOC_EXISTENTIAL:%.*]] = alloc_stack $ContiguousBytes
+// CHECK: [[ALLOC_ENUM:%.*]] = alloc_stack $Optional<ContiguousBytes>
+// CHECK: [[ENUM:%.*]] = init_enum_data_addr [[ALLOC_ENUM]] : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+// CHECK: [[INIT_DATA:%.*]] = init_existential_addr [[ENUM]] : $*ContiguousBytes, $Array<Int>
+// CHECK: store %0 to [[INIT_DATA]] : $*Array<Int>
+// CHECK: inject_enum_addr [[ALLOC_ENUM]] : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+// CHECK: [[TAKE_DATA:%.*]] = unchecked_take_enum_data_addr [[ALLOC_ENUM]] : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+// CHECK: copy_addr [take] [[TAKE_DATA]] to [initialization] [[ALLOC_EXISTENTIAL]] : $*ContiguousBytes
+// CHECK: [[OPENED:%.*]] = open_existential_addr immutable_access [[ALLOC_EXISTENTIAL]] : $*ContiguousBytes to $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes
+// CHECK: [[THUNK:%.*]] = function_ref @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error)
+// CHECK: [[TTF:%.*]] = thin_to_thick_function [[THUNK:%.*]] : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error) to $@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out (), @error Error)
+// CHECK: [[WM:%.*]] = witness_method $Array<Int>, #ContiguousBytes.withUnsafeBytes!1 : <Self where Self : ContiguousBytes><R> (Self) -> ((UnsafeRawBufferPointer) throws -> R) throws -> R : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
+// CHECK: apply [nothrow] [[WM]]<@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes, ()>(%{{.*}}, [[TTF]], [[OPENED]]) : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
+// CHECK: destroy_addr [[ALLOC_EXISTENTIAL]] : $*ContiguousBytes
+// CHECK-LABEL: } // end sil function 'testDevirtExistentialEnum'
+sil shared [noinline] @testDevirtExistentialEnum : $@convention(thin) (@guaranteed Array<Int>) -> () {
+bb0(%0 : $Array<Int>):
+ %3 = alloc_stack $ContiguousBytes
+ %4 = alloc_stack $Optional<ContiguousBytes>
+ %5 = init_enum_data_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+ %6 = init_existential_addr %5 : $*ContiguousBytes, $Array<Int>
+ store %0 to %6 : $*Array<Int>
+ inject_enum_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+ %9 = unchecked_take_enum_data_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt.1
+ copy_addr [take] %9 to [initialization] %3 : $*ContiguousBytes
+ dealloc_stack %4 : $*Optional<ContiguousBytes>
+ %12 = open_existential_addr immutable_access %3 : $*ContiguousBytes to $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes
+ %13 = alloc_stack $()
+ %14 = function_ref @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error)
+ %15 = thin_to_thick_function %14 : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error) to $@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out (), @error Error)
+ %16 = witness_method $@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes, #ContiguousBytes.withUnsafeBytes!1 : <Self where Self : ContiguousBytes><R> (Self) -> ((UnsafeRawBufferPointer) throws -> R) throws -> R, %12 : $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
+ %21 = apply [nothrow] %16<@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD") ContiguousBytes, ()>(%13, %15, %12) : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
+ dealloc_stack %13 : $*()
+ destroy_addr %3 : $*ContiguousBytes
+ dealloc_stack %3 : $*ContiguousBytes
+ %25 = tuple ()
+ return %25 : $()
+}