@@ -108,6 +108,154 @@ class ConstExprEvaluator {
108108 }
109109};
110110
111+ enum class WellKnownFunction {
112+ // Array.init()
113+ ArrayInitEmpty,
114+ // Array._allocateUninitializedArray
115+ AllocateUninitializedArray,
116+ // Array._endMutation
117+ EndArrayMutation,
118+ // _finalizeUninitializedArray
119+ FinalizeUninitializedArray,
120+ // Array.append(_:)
121+ ArrayAppendElement,
122+ // String.init()
123+ StringInitEmpty,
124+ // String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
125+ StringMakeUTF8,
126+ // static String.append (_: String, _: inout String)
127+ StringAppend,
128+ // static String.== infix(_: String)
129+ StringEquals,
130+ // String.percentEscapedString.getter
131+ StringEscapePercent,
132+ // BinaryInteger.description.getter
133+ BinaryIntegerDescription,
134+ // _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...)
135+ AssertionFailure,
136+ // A function taking one argument that prints the symbolic value of the
137+ // argument during constant evaluation. This must only be used for debugging.
138+ DebugPrint
139+ };
140+
141+ // ===----------------------------------------------------------------------===//
142+ // ConstExprFunctionState implementation.
143+ // ===----------------------------------------------------------------------===//
144+
145+ // / This type represents the state of computed values within a function
146+ // / as evaluation happens. A separate instance of this is made for each
147+ // / callee in a call chain to represent the constant values given the set of
148+ // / formal parameters that callee was invoked with.
149+ class ConstExprFunctionState {
150+ // / This is the evaluator that is computing this function state. We use it to
151+ // / allocate space for values and to query the call stack.
152+ ConstExprEvaluator &evaluator;
153+
154+ // / If we are analyzing the body of a constexpr function, this is the
155+ // / function. This is null for the top-level expression.
156+ SILFunction *fn;
157+
158+ // / If we have a function being analyzed, this is the substitutionMap for
159+ // / the call to it.
160+ // / substitutionMap specifies a mapping from all of the protocol and type
161+ // / requirements in the generic signature down to concrete conformances and
162+ // / concrete types.
163+ SubstitutionMap substitutionMap;
164+
165+ // / This keeps track of the number of instructions we've evaluated. If this
166+ // / goes beyond the execution cap, then we start returning unknown values.
167+ unsigned &numInstEvaluated;
168+
169+ // / This is a state of previously analyzed values, maintained and filled in
170+ // / by getConstantValue. This does not hold the memory referred to by SIL
171+ // / addresses.
172+ llvm::DenseMap<SILValue, SymbolicValue> calculatedValues;
173+
174+ // / If a SILValue is not bound to a SymbolicValue in the calculatedValues,
175+ // / try to compute it recursively by visiting its defining instruction.
176+ bool recursivelyComputeValueIfNotInState = false ;
177+
178+ public:
179+ ConstExprFunctionState (ConstExprEvaluator &evaluator, SILFunction *fn,
180+ SubstitutionMap substitutionMap,
181+ unsigned &numInstEvaluated,
182+ bool enableTopLevelEvaluation);
183+
184+ // / Pretty print the state to stderr.
185+ void dump () const ;
186+
187+ void setValue (SILValue value, SymbolicValue symVal);
188+
189+ // / Return the symbolic value for a SILValue if it is bound in the interpreter
190+ // / state. If not, return None.
191+ std::optional<SymbolicValue> lookupValue (SILValue value);
192+
193+ // / Invariant: Before the call, `calculatedValues` must not contain `addr`
194+ // / as a key.
195+ SymbolicValue createMemoryObject (SILValue addr, SymbolicValue initialValue);
196+
197+ // / Return the SymbolicValue for the specified SIL value. If the SIL value is
198+ // / not in \c calculatedValues, try computing the SymbolicValue recursively
199+ // / if \c recursivelyComputeValueIfNotInState flag is set.
200+ SymbolicValue getConstantValue (SILValue value);
201+
202+ // / Evaluate the specified instruction in a flow sensitive way, for use by
203+ // / the constexpr function evaluator. This does not handle control flow
204+ // / statements.
205+ std::optional<SymbolicValue> evaluateFlowSensitive (SILInstruction *inst);
206+
207+ // / Evaluate a branch or non-branch instruction and if the evaluation was
208+ // / successful, return the next instruction from where the evaluation must
209+ // / continue.
210+ // / \param instI basic-block iterator pointing to the instruction to evaluate.
211+ // / \param visitedBlocks basic blocks already visited during evaluation.
212+ // / This is used to detect loops.
213+ // / \returns a pair where the first and second elements are defined as
214+ // / follows:
215+ // / If the evaluation of the instruction is successful, the first element
216+ // / is the iterator to the next instruction from the where the evaluation
217+ // / must continue. Otherwise, it is None.
218+ // /
219+ // / Second element is None, if the evaluation is successful.
220+ // / Otherwise, is an unknown symbolic value that contains the error.
221+ std::pair<std::optional<SILBasicBlock::iterator>,
222+ std::optional<SymbolicValue>>
223+ evaluateInstructionAndGetNext (
224+ SILBasicBlock::iterator instI,
225+ SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks);
226+
227+ Type substituteGenericParamsAndSimplify (Type ty);
228+ CanType substituteGenericParamsAndSimplify (CanType ty) {
229+ return substituteGenericParamsAndSimplify (Type (ty))->getCanonicalType ();
230+ }
231+ SymbolicValue computeConstantValue (SILValue value);
232+ SymbolicValue computeConstantValueBuiltin (BuiltinInst *inst);
233+
234+ std::optional<SymbolicValue> computeCallResult (ApplyInst *apply);
235+
236+ std::optional<SymbolicValue> computeOpaqueCallResult (ApplyInst *apply,
237+ SILFunction *callee);
238+
239+ std::optional<SymbolicValue>
240+ computeWellKnownCallResult (ApplyInst *apply, WellKnownFunction callee);
241+
242+ // / Evaluate a closure creation instruction which is either a partial_apply
243+ // / instruction or a thin_to_think_function instruction. On success, this
244+ // / function will bind the \c closureInst parameter to its symbolic value.
245+ // / On failure, it returns the unknown symbolic value that captures the error.
246+ std::optional<SymbolicValue>
247+ evaluateClosureCreation (SingleValueInstruction *closureInst);
248+
249+ SymbolicValue getSingleWriterAddressValue (SILValue addr);
250+ SymbolicValue getConstAddrAndLoadResult (SILValue addr);
251+ SymbolicValue loadAddrValue (SILValue addr, SymbolicValue addrVal);
252+ std::optional<SymbolicValue> computeFSStore (SymbolicValue storedCst,
253+ SILValue dest);
254+
255+ private:
256+ std::optional<SymbolicValue> initializeAddressFromSingleWriter (SILValue addr);
257+ };
258+
111259// / A constant-expression evaluator that can be used to step through a control
112260// / flow graph (SILFunction body) by evaluating one instruction at a time.
113261// / This evaluator can also "skip" instructions without evaluating them and
0 commit comments