@@ -56,6 +56,8 @@ enum class WellKnownFunction {
5656 StringEquals,
5757 // String.percentEscapedString.getter
5858 StringEscapePercent,
59+ // BinaryInteger.description.getter
60+ BinaryIntegerDescription,
5961 // _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...)
6062 AssertionFailure,
6163 // A function taking one argument that prints the symbolic value of the
@@ -83,6 +85,8 @@ static llvm::Optional<WellKnownFunction> classifyFunction(SILFunction *fn) {
8385 return WellKnownFunction::StringEquals;
8486 if (fn->hasSemanticsAttr (semantics::STRING_ESCAPE_PERCENT_GET))
8587 return WellKnownFunction::StringEscapePercent;
88+ if (fn->hasSemanticsAttr (semantics::BINARY_INTEGER_DESCRIPTION))
89+ return WellKnownFunction::BinaryIntegerDescription;
8690 if (fn->hasSemanticsAttrThatStartsWith (" programtermination_point" ))
8791 return WellKnownFunction::AssertionFailure;
8892 // A call to a function with the following semantics annotation will be
@@ -789,6 +793,28 @@ static Type getArrayElementType(Type ty) {
789793 return Type ();
790794}
791795
796+ // / Check if the given type \p ty is a stdlib integer type and if so return
797+ // / whether the type is signed. Returns \c None if \p ty is not a stdlib integer
798+ // / type, \c true if it is a signed integer type and \c false if it is an
799+ // / unsigned integer type.
800+ static Optional<bool > getSignIfStdlibIntegerType (Type ty) {
801+ StructDecl *decl = ty->getStructOrBoundGenericStruct ();
802+ if (!decl)
803+ return None;
804+ ASTContext &astCtx = ty->getASTContext ();
805+ if (decl == astCtx.getIntDecl () || decl == astCtx.getInt8Decl () ||
806+ decl == astCtx.getInt16Decl () || decl == astCtx.getInt32Decl () ||
807+ decl == astCtx.getInt64Decl ()) {
808+ return true ;
809+ }
810+ if (decl == astCtx.getUIntDecl () || decl == astCtx.getUInt8Decl () ||
811+ decl == astCtx.getUInt16Decl () || decl == astCtx.getUInt32Decl () ||
812+ decl == astCtx.getUInt64Decl ()) {
813+ return false ;
814+ }
815+ return None;
816+ }
817+
792818// / Given a call to a well known function, collect its arguments as constants,
793819// / fold it, and return None. If any of the arguments are not constants, marks
794820// / the call's results as Unknown, and return an Unknown with information about
@@ -1064,6 +1090,42 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
10641090 setValue (apply, resultVal);
10651091 return None;
10661092 }
1093+ case WellKnownFunction::BinaryIntegerDescription: {
1094+ // BinaryInteger.description.getter
1095+ assert (conventions.getNumDirectSILResults () == 1 &&
1096+ conventions.getNumIndirectSILResults () == 0 &&
1097+ conventions.getNumParameters () == 1 && apply->hasSubstitutions () &&
1098+ " unexpected BinaryInteger.description.getter signature" );
1099+ // Get the type of the argument and check if it is a signed or
1100+ // unsigned integer.
1101+ SILValue integerArgument = apply->getOperand (1 );
1102+ CanType argumentType = substituteGenericParamsAndSimpify (
1103+ integerArgument->getType ().getASTType ());
1104+ Optional<bool > isSignedIntegerType =
1105+ getSignIfStdlibIntegerType (argumentType);
1106+ if (!isSignedIntegerType.hasValue ()) {
1107+ return getUnknown (evaluator, (SILInstruction *)apply,
1108+ UnknownReason::InvalidOperandValue);
1109+ }
1110+ // Load the stdlib integer's value and convert it to a string.
1111+ SymbolicValue stdlibIntegerValue =
1112+ getConstAddrAndLoadResult (integerArgument);
1113+ if (!stdlibIntegerValue.isConstant ()) {
1114+ return stdlibIntegerValue;
1115+ }
1116+ SymbolicValue builtinIntegerValue =
1117+ stdlibIntegerValue.lookThroughSingleElementAggregates ();
1118+ assert (builtinIntegerValue.getKind () == SymbolicValue::Integer &&
1119+ " stdlib integer type must store only a builtin integer" );
1120+ APInt integer = builtinIntegerValue.getIntegerValue ();
1121+ SmallString<8 > integerString;
1122+ isSignedIntegerType.getValue () ? integer.toStringSigned (integerString)
1123+ : integer.toStringUnsigned (integerString);
1124+ SymbolicValue resultVal =
1125+ SymbolicValue::getString (integerString.str (), evaluator.getAllocator ());
1126+ setValue (apply, resultVal);
1127+ return None;
1128+ }
10671129 case WellKnownFunction::DebugPrint: {
10681130 assert (apply->getNumArguments () == 1 &&
10691131 " debug_print function must take exactly one argument" );
0 commit comments