Skip to content

Commit a5c38d0

Browse files
Revert "Remove apparently obsolete builtin functions (#20947)" (#20975)
This reverts commit b914464, which passed the public CI bots, but broke some tests on watchOS.
1 parent 4038e77 commit a5c38d0

File tree

13 files changed

+535
-39
lines changed

13 files changed

+535
-39
lines changed

include/swift/AST/Builtins.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,14 @@ BUILTIN_MISC_OPERATION(SToSCheckedTrunc, "s_to_s_checked_trunc", "n", Special)
478478
BUILTIN_MISC_OPERATION(SToUCheckedTrunc, "s_to_u_checked_trunc", "n", Special)
479479
BUILTIN_MISC_OPERATION(UToUCheckedTrunc, "u_to_u_checked_trunc", "n", Special)
480480

481+
/// Checked conversions for signed <-> unsigned integers of the same size.
482+
/// Returns a tuple containing the conversion result as well as
483+
/// the sign error / overflow bit.
484+
BUILTIN_MISC_OPERATION(SUCheckedConversion,
485+
"s_to_u_checked_conversion", "n", Special)
486+
BUILTIN_MISC_OPERATION(USCheckedConversion,
487+
"u_to_s_checked_conversion", "n", Special)
488+
481489
/// IntToFPWithOverflow has type (Integer) -> Float
482490
BUILTIN_MISC_OPERATION(IntToFPWithOverflow, "itofp_with_overflow", "n", Special)
483491

include/swift/SIL/PatternMatch.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,13 @@ using BuiltinApplyTy = typename Apply_match<BuiltinValueKind, Tys...>::Ty;
715715
// if any of the sub-matchers succeed.
716716
//
717717

718+
/// Matcher for any of the builtin checked conversions.
719+
template <typename T0>
720+
inline typename OneOf_match<BuiltinApplyTy<T0>, BuiltinApplyTy<T0>>::Ty
721+
m_CheckedConversion(const T0 &Op0) {
722+
return m_USCheckedConversion(Op0) || m_SUCheckedConversion(Op0);
723+
}
724+
718725
/// Matcher for any of the builtin ExtOrBitCast instructions.
719726
template <typename T0>
720727
inline typename OneOf_match<BuiltinApplyTy<T0>, BuiltinApplyTy<T0>>::Ty

lib/AST/Builtins.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,19 @@ static ValueDecl *getCheckedTruncOperation(ASTContext &Context, Identifier Id,
11061106
return getBuiltinFunction(Id, { InTy }, ResultTy);
11071107
}
11081108

1109+
static ValueDecl *getCheckedConversionOperation(ASTContext &Context,
1110+
Identifier Id,
1111+
Type Ty) {
1112+
Type BuiltinTy = Ty->getAs<BuiltinIntegerType>();
1113+
if (!BuiltinTy)
1114+
return nullptr;
1115+
1116+
Type SignErrorBitTy = BuiltinIntegerType::get(1, Context);
1117+
TupleTypeElt ResultElts[] = { BuiltinTy, SignErrorBitTy };
1118+
Type ResultTy = TupleType::get(ResultElts, Context);
1119+
return getBuiltinFunction(Id, { BuiltinTy }, ResultTy);
1120+
}
1121+
11091122
static ValueDecl *getIntToFPWithOverflowOperation(ASTContext &Context,
11101123
Identifier Id, Type InputTy,
11111124
Type OutputTy) {
@@ -1840,6 +1853,11 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
18401853
if (Types.size() != 2) return nullptr;
18411854
return getCheckedTruncOperation(Context, Id, Types[0], Types[1], false);
18421855

1856+
case BuiltinValueKind::SUCheckedConversion:
1857+
case BuiltinValueKind::USCheckedConversion:
1858+
if (Types.size() != 1) return nullptr;
1859+
return getCheckedConversionOperation(Context, Id, Types[0]);
1860+
18431861
case BuiltinValueKind::ClassifyBridgeObject:
18441862
if (!Types.empty()) return nullptr;
18451863
return getClassifyBridgeObject(Context, Id);

lib/IRGen/GenBuiltin.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,22 @@ if (Builtin.ID == BuiltinValueKind::id) { \
758758
return out.add(OverflowFlag);
759759
}
760760

761+
if (Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
762+
Builtin.ID == BuiltinValueKind::USCheckedConversion) {
763+
auto Ty =
764+
IGF.IGM.getStorageTypeForLowered(Builtin.Types[0]->getCanonicalType());
765+
766+
// Report a sign error if the input parameter is a negative number, when
767+
// interpreted as signed.
768+
llvm::Value *Arg = args.claimNext();
769+
llvm::Value *Zero = llvm::ConstantInt::get(Ty, 0);
770+
llvm::Value *OverflowFlag = IGF.Builder.CreateICmpSLT(Arg, Zero);
771+
772+
// Return the tuple: (the result (same as input), the overflow flag).
773+
out.add(Arg);
774+
return out.add(OverflowFlag);
775+
}
776+
761777
// We are currently emitting code for '_convertFromBuiltinIntegerLiteral',
762778
// which will call the builtin and pass it a non-compile-time-const parameter.
763779
if (Builtin.ID == BuiltinValueKind::IntToFPWithOverflow) {

lib/SIL/OperandOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SRem)
11221122
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SSubOver)
11231123
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SToSCheckedTrunc)
11241124
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SToUCheckedTrunc)
1125+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, SUCheckedConversion)
11251126
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, Shl)
11261127
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, Sizeof)
11271128
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, StaticReport)
@@ -1139,6 +1140,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UDiv)
11391140
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UIToFP)
11401141
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UMulOver)
11411142
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, URem)
1143+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, USCheckedConversion)
11421144
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, USubOver)
11431145
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UToSCheckedTrunc)
11441146
CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, UToUCheckedTrunc)

lib/SIL/ValueOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToSCheckedTrunc)
479479
CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToSCheckedTrunc)
480480
CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToUCheckedTrunc)
481481
CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToUCheckedTrunc)
482+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, SUCheckedConversion)
483+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, USCheckedConversion)
482484
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToFPWithOverflow)
483485

484486
// This is surprising, Builtin.unreachable returns a "Never" value which is

lib/SILOptimizer/Analysis/SimplifyInstruction.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,18 @@ static SILValue simplifyBuiltin(BuiltinInst *BI) {
492492
return Result;
493493
}
494494

495+
// trunc(tuple_extract(conversion(extOrBitCast(x))))) -> x
496+
if (match(Op, m_TupleExtractInst(
497+
m_CheckedConversion(
498+
m_ExtOrBitCast(m_SILValue(Result))), 0))) {
499+
// If the top bit of Result is known to be 0, then
500+
// it is safe to replace the whole pattern by original bits of x
501+
if (Result->getType() == BI->getType()) {
502+
if (auto signBit = computeSignBit(Result))
503+
if (!signBit.getValue())
504+
return Result;
505+
}
506+
}
495507
return SILValue();
496508
}
497509

@@ -627,6 +639,23 @@ SILValue InstSimplifier::simplifyOverflowBuiltin(BuiltinInst *BI) {
627639
switch (Builtin.ID) {
628640
default: break;
629641

642+
case BuiltinValueKind::SUCheckedConversion:
643+
case BuiltinValueKind::USCheckedConversion: {
644+
OperandValueArrayRef Args = BI->getArguments();
645+
const SILValue &Op = Args[0];
646+
if (auto signBit = computeSignBit(Op))
647+
if (!signBit.getValue())
648+
return Op;
649+
SILValue Result;
650+
// CheckedConversion(ExtOrBitCast(x)) -> x
651+
if (match(BI, m_CheckedConversion(m_ExtOrBitCast(m_SILValue(Result)))))
652+
if (Result->getType() == BI->getType().getTupleElementType(0)) {
653+
assert (!computeSignBit(Result).getValue() && "Sign bit should be 0");
654+
return Result;
655+
}
656+
}
657+
break;
658+
630659
case BuiltinValueKind::UToSCheckedTrunc:
631660
case BuiltinValueKind::UToUCheckedTrunc:
632661
case BuiltinValueKind::SToUCheckedTrunc:

lib/SILOptimizer/Analysis/ValueTracking.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,25 @@ Optional<bool> swift::computeSignBit(SILValue V) {
296296
continue;
297297
}
298298

299+
// Source and target type sizes are the same.
300+
// S->U conversion can only succeed if
301+
// the sign bit of its operand is 0, i.e. it is >= 0.
302+
// The sign bit of a result is 0 only if the sign
303+
// bit of a source operand is 0.
304+
case BuiltinValueKind::SUCheckedConversion:
305+
Value = BI->getArguments()[0];
306+
continue;
307+
308+
// Source and target type sizes are the same.
309+
// U->S conversion can only succeed if
310+
// the top bit of its operand is 0, i.e.
311+
// it is representable as a signed integer >=0.
312+
// The sign bit of a result is 0 only if the sign
313+
// bit of a source operand is 0.
314+
case BuiltinValueKind::USCheckedConversion:
315+
Value = BI->getArguments()[0];
316+
continue;
317+
299318
// Sign bit of the operand is promoted.
300319
case BuiltinValueKind::SExt:
301320
Value = BI->getArguments()[0];

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ static bool isBarrier(SILInstruction *inst) {
122122
case BuiltinValueKind::SToUCheckedTrunc:
123123
case BuiltinValueKind::SToSCheckedTrunc:
124124
case BuiltinValueKind::UToUCheckedTrunc:
125+
case BuiltinValueKind::SUCheckedConversion:
126+
case BuiltinValueKind::USCheckedConversion:
125127
case BuiltinValueKind::IntToFPWithOverflow:
126128
case BuiltinValueKind::ZeroInitializer:
127129
case BuiltinValueKind::Once:

lib/SILOptimizer/Utils/ConstExpr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
210210
if (!operand.isConstant())
211211
return operand;
212212

213+
// TODO: SUCheckedConversion/USCheckedConversion
214+
213215
// Implement support for s_to_s_checked_trunc_Int2048_Int64 and other
214216
// checking integer truncates. These produce a tuple of the result value
215217
// and an overflow bit.

lib/SILOptimizer/Utils/ConstantFolding.cpp

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,9 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI,
674674
assert(Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
675675
Builtin.ID == BuiltinValueKind::UToUCheckedTrunc ||
676676
Builtin.ID == BuiltinValueKind::SToUCheckedTrunc ||
677-
Builtin.ID == BuiltinValueKind::UToSCheckedTrunc);
677+
Builtin.ID == BuiltinValueKind::UToSCheckedTrunc ||
678+
Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
679+
Builtin.ID == BuiltinValueKind::USCheckedConversion);
678680

679681
// Check if we are converting a constant integer.
680682
OperandValueArrayRef Args = BI->getArguments();
@@ -686,9 +688,11 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI,
686688
auto SrcBitWidth = SrcVal.getBitWidth();
687689

688690
bool DstTySigned = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
689-
Builtin.ID == BuiltinValueKind::UToSCheckedTrunc);
691+
Builtin.ID == BuiltinValueKind::UToSCheckedTrunc ||
692+
Builtin.ID == BuiltinValueKind::USCheckedConversion);
690693
bool SrcTySigned = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc ||
691-
Builtin.ID == BuiltinValueKind::SToUCheckedTrunc);
694+
Builtin.ID == BuiltinValueKind::SToUCheckedTrunc ||
695+
Builtin.ID == BuiltinValueKind::SUCheckedConversion);
692696

693697
// Get source type and bit width.
694698
auto SrcTy = Builtin.Types[0]->castTo<AnyBuiltinIntegerType>();
@@ -701,33 +705,44 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI,
701705
bool OverflowError;
702706
Type DstTy;
703707

704-
assert(Builtin.Types.size() == 2);
705-
DstTy = Builtin.Types[1];
706-
uint32_t DstBitWidth =
707-
DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth();
708-
709-
assert((DstBitWidth < SrcBitWidth || !SrcTy->getWidth().isFixedWidth()) &&
710-
"preconditions on builtin trunc operations should prevent"
711-
"fixed-width truncations that actually extend");
712-
713-
// The only way a true extension can overflow is if the value is
714-
// negative and the result is unsigned.
715-
if (DstBitWidth > SrcBitWidth) {
716-
OverflowError = (SrcTySigned && !DstTySigned && SrcVal.isNegative());
717-
Result = (SrcTySigned ? SrcVal.sext(DstBitWidth)
718-
: SrcVal.zext(DstBitWidth));
719-
720-
// A same-width change can overflow if the top bit disagrees.
721-
} else if (DstBitWidth == SrcBitWidth) {
722-
OverflowError = (SrcTySigned != DstTySigned && SrcVal.isNegative());
708+
// Process conversions signed <-> unsigned for same size integers.
709+
if (Builtin.ID == BuiltinValueKind::SUCheckedConversion ||
710+
Builtin.ID == BuiltinValueKind::USCheckedConversion) {
711+
DstTy = SrcTy;
723712
Result = SrcVal;
713+
// Report an error if the sign bit is set.
714+
OverflowError = SrcVal.isNegative();
724715

725-
// A truncation can overflow if the value changes.
716+
// Process the checked truncations.
726717
} else {
727-
Result = SrcVal.trunc(DstBitWidth);
728-
APInt Ext = (DstTySigned ? Result.sext(SrcBitWidth)
729-
: Result.zext(SrcBitWidth));
730-
OverflowError = (SrcVal != Ext);
718+
assert(Builtin.Types.size() == 2);
719+
DstTy = Builtin.Types[1];
720+
uint32_t DstBitWidth =
721+
DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth();
722+
723+
assert((DstBitWidth < SrcBitWidth || !SrcTy->getWidth().isFixedWidth()) &&
724+
"preconditions on builtin trunc operations should prevent"
725+
"fixed-width truncations that actually extend");
726+
727+
// The only way a true extension can overflow is if the value is
728+
// negative and the result is unsigned.
729+
if (DstBitWidth > SrcBitWidth) {
730+
OverflowError = (SrcTySigned && !DstTySigned && SrcVal.isNegative());
731+
Result = (SrcTySigned ? SrcVal.sext(DstBitWidth)
732+
: SrcVal.zext(DstBitWidth));
733+
734+
// A same-width change can overflow if the top bit disagrees.
735+
} else if (DstBitWidth == SrcBitWidth) {
736+
OverflowError = (SrcTySigned != DstTySigned && SrcVal.isNegative());
737+
Result = SrcVal;
738+
739+
// A truncation can overflow if the value changes.
740+
} else {
741+
Result = SrcVal.trunc(DstBitWidth);
742+
APInt Ext = (DstTySigned ? Result.sext(SrcBitWidth)
743+
: Result.zext(SrcBitWidth));
744+
OverflowError = (SrcVal != Ext);
745+
}
731746
}
732747

733748
// Check for overflow.
@@ -804,19 +819,25 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI,
804819
DstTySigned, DstTy, SrcAsString);
805820
}
806821
} else {
807-
// Try to print user-visible types if they are available.
808-
if (!UserSrcTy.isNull()) {
822+
if (Builtin.ID == BuiltinValueKind::SUCheckedConversion) {
809823
diagnose(M.getASTContext(), Loc.getSourceLoc(),
810-
diag::integer_conversion_overflow,
811-
UserSrcTy, UserDstTy);
812-
813-
// Otherwise, print the Builtin Types.
824+
diag::integer_conversion_sign_error,
825+
UserDstTy.isNull() ? DstTy : UserDstTy);
814826
} else {
815-
// Since builtin types are sign-agnostic, print the signedness
816-
// separately.
817-
diagnose(M.getASTContext(), Loc.getSourceLoc(),
818-
diag::integer_conversion_overflow_builtin_types,
819-
SrcTySigned, SrcTy, DstTySigned, DstTy);
827+
// Try to print user-visible types if they are available.
828+
if (!UserSrcTy.isNull()) {
829+
diagnose(M.getASTContext(), Loc.getSourceLoc(),
830+
diag::integer_conversion_overflow,
831+
UserSrcTy, UserDstTy);
832+
833+
// Otherwise, print the Builtin Types.
834+
} else {
835+
// Since builtin types are sign-agnostic, print the signedness
836+
// separately.
837+
diagnose(M.getASTContext(), Loc.getSourceLoc(),
838+
diag::integer_conversion_overflow_builtin_types,
839+
SrcTySigned, SrcTy, DstTySigned, DstTy);
840+
}
820841
}
821842
}
822843

@@ -1199,7 +1220,9 @@ case BuiltinValueKind::id:
11991220
case BuiltinValueKind::SToSCheckedTrunc:
12001221
case BuiltinValueKind::UToUCheckedTrunc:
12011222
case BuiltinValueKind::SToUCheckedTrunc:
1202-
case BuiltinValueKind::UToSCheckedTrunc: {
1223+
case BuiltinValueKind::UToSCheckedTrunc:
1224+
case BuiltinValueKind::SUCheckedConversion:
1225+
case BuiltinValueKind::USCheckedConversion: {
12031226
return constantFoldAndCheckIntegerConversions(BI, Builtin, ResultsInError);
12041227
}
12051228

0 commit comments

Comments
 (0)