@@ -111,6 +111,27 @@ static llvm::Optional<WellKnownFunction> classifyFunction(SILFunction *fn) {
111111 return None;
112112}
113113
114+ static bool isReadOnlyFunction (WellKnownFunction function) {
115+ switch (function) {
116+ case WellKnownFunction::ArrayInitEmpty:
117+ case WellKnownFunction::AllocateUninitializedArray:
118+ case WellKnownFunction::StringInitEmpty:
119+ case WellKnownFunction::StringMakeUTF8:
120+ case WellKnownFunction::StringEquals:
121+ case WellKnownFunction::StringEscapePercent:
122+ case WellKnownFunction::BinaryIntegerDescription:
123+ return true ;
124+
125+ case WellKnownFunction::EndArrayMutation:
126+ case WellKnownFunction::FinalizeUninitializedArray:
127+ case WellKnownFunction::ArrayAppendElement:
128+ case WellKnownFunction::StringAppend:
129+ case WellKnownFunction::AssertionFailure:
130+ case WellKnownFunction::DebugPrint:
131+ return false ;
132+ }
133+ }
134+
114135// / Helper function for creating UnknownReason without a payload.
115136static SymbolicValue getUnknown (ConstExprEvaluator &evaluator, SILNode *node,
116137 UnknownReason::UnknownKind kind) {
@@ -2291,3 +2312,39 @@ bool swift::isConstantEvaluable(SILFunction *fun) {
22912312 return hasConstantEvaluableAnnotation (fun) ||
22922313 isKnownConstantEvaluableFunction (fun);
22932314}
2315+
2316+ // / Return true iff the \p applySite is constant-evaluable and read-only.
2317+ // /
2318+ // / Functions annotated as "constant_evaluable" are assumed to be "side-effect
2319+ // / free", unless their signature and substitution map indicates otherwise. A
2320+ // / constant_evaluable function call is read only unless it:
2321+ // / (1) has generic parameters
2322+ // / (2) has inout parameters
2323+ // / (3) has indirect results
2324+ // /
2325+ // / Read-only constant evaluable functions can do only the following and
2326+ // / nothing else:
2327+ // / (1) The call may read any memory location.
2328+ // / (2) The call may destroy owned parameters i.e., consume them.
2329+ // / (3) The call may write into memory locations newly created by the call.
2330+ // / (4) The call may use assertions, which traps at runtime on failure.
2331+ // / (5) The call may return a non-generic value.
2332+ // /
2333+ // / Essentially, these are calls whose "effect" is visible only in their return
2334+ // / value or through the parameters that are destroyed. The return value
2335+ // / is also guaranteed to have value semantics as it is non-generic and
2336+ // / reference semantics is not constant evaluable.
2337+ bool swift::isReadOnlyConstantEvaluableCall (FullApplySite applySite) {
2338+ SILFunction *callee = applySite.getCalleeFunction ();
2339+ if (!callee)
2340+ return false ;
2341+
2342+ if (auto knownFunction = classifyFunction (callee)) {
2343+ return isReadOnlyFunction (knownFunction.getValue ());
2344+ }
2345+ if (!hasConstantEvaluableAnnotation (callee))
2346+ return false ;
2347+
2348+ return !applySite.hasSubstitutions () && !getNumInOutArguments (applySite)
2349+ && !applySite.getNumIndirectSILResults ();
2350+ }
0 commit comments