@@ -56,6 +56,8 @@ enum class WellKnownFunction {
56
56
StringEquals,
57
57
// String.percentEscapedString.getter
58
58
StringEscapePercent,
59
+ // BinaryInteger.description.getter
60
+ BinaryIntegerDescription,
59
61
// _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...)
60
62
AssertionFailure,
61
63
// A function taking one argument that prints the symbolic value of the
@@ -83,6 +85,8 @@ static llvm::Optional<WellKnownFunction> classifyFunction(SILFunction *fn) {
83
85
return WellKnownFunction::StringEquals;
84
86
if (fn->hasSemanticsAttr (semantics::STRING_ESCAPE_PERCENT_GET))
85
87
return WellKnownFunction::StringEscapePercent;
88
+ if (fn->hasSemanticsAttr (semantics::BINARY_INTEGER_DESCRIPTION))
89
+ return WellKnownFunction::BinaryIntegerDescription;
86
90
if (fn->hasSemanticsAttrThatStartsWith (" programtermination_point" ))
87
91
return WellKnownFunction::AssertionFailure;
88
92
// A call to a function with the following semantics annotation will be
@@ -780,6 +784,13 @@ extractStaticStringValue(SymbolicValue staticString) {
780
784
return staticStringProps[0 ].getStringValue ();
781
785
}
782
786
787
+ static Optional<StringRef>
788
+ extractStringOrStaticStringValue (SymbolicValue stringValue) {
789
+ if (stringValue.getKind () == SymbolicValue::String)
790
+ return stringValue.getStringValue ();
791
+ return extractStaticStringValue (stringValue);
792
+ }
793
+
783
794
// / If the specified type is a Swift.Array of some element type, then return the
784
795
// / element type. Otherwise, return a null Type.
785
796
static Type getArrayElementType (Type ty) {
@@ -789,6 +800,28 @@ static Type getArrayElementType(Type ty) {
789
800
return Type ();
790
801
}
791
802
803
+ // / Check if the given type \p ty is a stdlib integer type and if so return
804
+ // / whether the type is signed. Returns \c None if \p ty is not a stdlib integer
805
+ // / type, \c true if it is a signed integer type and \c false if it is an
806
+ // / unsigned integer type.
807
+ static Optional<bool > getSignIfStdlibIntegerType (Type ty) {
808
+ StructDecl *decl = ty->getStructOrBoundGenericStruct ();
809
+ if (!decl)
810
+ return None;
811
+ ASTContext &astCtx = ty->getASTContext ();
812
+ if (decl == astCtx.getIntDecl () || decl == astCtx.getInt8Decl () ||
813
+ decl == astCtx.getInt16Decl () || decl == astCtx.getInt32Decl () ||
814
+ decl == astCtx.getInt64Decl ()) {
815
+ return true ;
816
+ }
817
+ if (decl == astCtx.getUIntDecl () || decl == astCtx.getUInt8Decl () ||
818
+ decl == astCtx.getUInt16Decl () || decl == astCtx.getUInt32Decl () ||
819
+ decl == astCtx.getUInt64Decl ()) {
820
+ return false ;
821
+ }
822
+ return None;
823
+ }
824
+
792
825
// / Given a call to a well known function, collect its arguments as constants,
793
826
// / fold it, and return None. If any of the arguments are not constants, marks
794
827
// / the call's results as Unknown, and return an Unknown with information about
@@ -803,8 +836,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
803
836
for (unsigned i = 0 ; i < apply->getNumArguments (); i++) {
804
837
SILValue argument = apply->getArgument (i);
805
838
SymbolicValue argValue = getConstantValue (argument);
806
- Optional<StringRef> stringOpt = extractStaticStringValue (argValue);
807
-
839
+ Optional<StringRef> stringOpt =
840
+ extractStringOrStaticStringValue (argValue);
808
841
// The first argument is a prefix that specifies the kind of failure
809
842
// this is.
810
843
if (i == 0 ) {
@@ -816,7 +849,6 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
816
849
}
817
850
continue ;
818
851
}
819
-
820
852
if (stringOpt) {
821
853
message += " : " ;
822
854
message += stringOpt.getValue ();
@@ -1064,6 +1096,42 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
1064
1096
setValue (apply, resultVal);
1065
1097
return None;
1066
1098
}
1099
+ case WellKnownFunction::BinaryIntegerDescription: {
1100
+ // BinaryInteger.description.getter
1101
+ assert (conventions.getNumDirectSILResults () == 1 &&
1102
+ conventions.getNumIndirectSILResults () == 0 &&
1103
+ conventions.getNumParameters () == 1 && apply->hasSubstitutions () &&
1104
+ " unexpected BinaryInteger.description.getter signature" );
1105
+ // Get the type of the argument and check if it is a signed or
1106
+ // unsigned integer.
1107
+ SILValue integerArgument = apply->getOperand (1 );
1108
+ CanType argumentType = substituteGenericParamsAndSimpify (
1109
+ integerArgument->getType ().getASTType ());
1110
+ Optional<bool > isSignedIntegerType =
1111
+ getSignIfStdlibIntegerType (argumentType);
1112
+ if (!isSignedIntegerType.hasValue ()) {
1113
+ return getUnknown (evaluator, (SILInstruction *)apply,
1114
+ UnknownReason::InvalidOperandValue);
1115
+ }
1116
+ // Load the stdlib integer's value and convert it to a string.
1117
+ SymbolicValue stdlibIntegerValue =
1118
+ getConstAddrAndLoadResult (integerArgument);
1119
+ if (!stdlibIntegerValue.isConstant ()) {
1120
+ return stdlibIntegerValue;
1121
+ }
1122
+ SymbolicValue builtinIntegerValue =
1123
+ stdlibIntegerValue.lookThroughSingleElementAggregates ();
1124
+ assert (builtinIntegerValue.getKind () == SymbolicValue::Integer &&
1125
+ " stdlib integer type must store only a builtin integer" );
1126
+ APInt integer = builtinIntegerValue.getIntegerValue ();
1127
+ SmallString<8 > integerString;
1128
+ isSignedIntegerType.getValue () ? integer.toStringSigned (integerString)
1129
+ : integer.toStringUnsigned (integerString);
1130
+ SymbolicValue resultVal =
1131
+ SymbolicValue::getString (integerString.str (), evaluator.getAllocator ());
1132
+ setValue (apply, resultVal);
1133
+ return None;
1134
+ }
1067
1135
case WellKnownFunction::DebugPrint: {
1068
1136
assert (apply->getNumArguments () == 1 &&
1069
1137
" debug_print function must take exactly one argument" );
0 commit comments