@@ -123,12 +123,22 @@ class ConstExprFunctionState {
123
123
// / addresses.
124
124
llvm::DenseMap<SILValue, SymbolicValue> calculatedValues;
125
125
126
+ // / If a SILValue is not bound to a SymbolicValue in the calculatedValues,
127
+ // / try to compute it recursively by visiting its defining instruction.
128
+ bool recursivelyComputeValueIfNotInState = false ;
129
+
126
130
public:
127
131
ConstExprFunctionState (ConstExprEvaluator &evaluator, SILFunction *fn,
128
132
SubstitutionMap substitutionMap,
129
- unsigned &numInstEvaluated)
133
+ unsigned &numInstEvaluated,
134
+ bool enableTopLevelEvaluation)
130
135
: evaluator(evaluator), fn(fn), substitutionMap(substitutionMap),
131
- numInstEvaluated (numInstEvaluated) {}
136
+ numInstEvaluated (numInstEvaluated),
137
+ recursivelyComputeValueIfNotInState(enableTopLevelEvaluation) {
138
+ assert ((!fn || !enableTopLevelEvaluation) &&
139
+ " top-level evaluation must be disabled when evaluating a function"
140
+ " body step by step" );
141
+ }
132
142
133
143
// / Pretty print the state to stderr.
134
144
void dump () const {
@@ -168,8 +178,9 @@ class ConstExprFunctionState {
168
178
return result;
169
179
}
170
180
171
- // / Return the SymbolicValue for the specified SIL value, lazily computing
172
- // / it if needed.
181
+ // / Return the SymbolicValue for the specified SIL value. If the SIL value is
182
+ // / not in \c calculatedValues, try computing the SymbolicValue recursively
183
+ // / if \c recursivelyComputeValueIfNotInState flag is set.
173
184
SymbolicValue getConstantValue (SILValue value);
174
185
175
186
// / Evaluate the specified instruction in a flow sensitive way, for use by
@@ -232,14 +243,6 @@ Type ConstExprFunctionState::substituteGenericParamsAndSimpify(Type ty) {
232
243
SymbolicValue ConstExprFunctionState::computeConstantValue (SILValue value) {
233
244
assert (!calculatedValues.count (value));
234
245
235
- // If the client is asking for the value of a stack object that hasn't been
236
- // computed, and if fn is null, then we are in top level code, and the
237
- // stack object must be a single store value. Since this is a very different
238
- // computation, split it out to its own path.
239
- if (!fn && value->getType ().isAddress () && isa<AllocStackInst>(value)) {
240
- return getSingleWriterAddressValue (value);
241
- }
242
-
243
246
// If this a trivial constant instruction that we can handle, then fold it
244
247
// immediately.
245
248
if (auto *ili = dyn_cast<IntegerLiteralInst>(value))
@@ -382,17 +385,6 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
382
385
if (auto *builtin = dyn_cast<BuiltinInst>(value))
383
386
return computeConstantValueBuiltin (builtin);
384
387
385
- if (auto *apply = dyn_cast<ApplyInst>(value)) {
386
- auto callResult = computeCallResult (apply);
387
-
388
- // If this failed, return the error code.
389
- if (callResult.hasValue ())
390
- return callResult.getValue ();
391
-
392
- assert (calculatedValues.count (apply));
393
- return calculatedValues[apply];
394
- }
395
-
396
388
if (auto *enumVal = dyn_cast<EnumInst>(value)) {
397
389
if (!enumVal->hasOperand ())
398
390
return SymbolicValue::getEnum (enumVal->getElement ());
@@ -1174,15 +1166,37 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
1174
1166
return None;
1175
1167
}
1176
1168
1177
- // / Return the SymbolicValue for the specified SIL value, lazily computing
1178
- // / it if needed.
1179
1169
SymbolicValue ConstExprFunctionState::getConstantValue (SILValue value) {
1180
1170
// Check to see if we already have an answer.
1181
1171
auto it = calculatedValues.find (value);
1182
1172
if (it != calculatedValues.end ())
1183
1173
return it->second ;
1184
1174
1185
- // Compute the value of a normal instruction based on its operands.
1175
+ if (!recursivelyComputeValueIfNotInState) {
1176
+ return getUnknown (evaluator, value, UnknownReason::UntrackedSILValue);
1177
+ }
1178
+
1179
+ // If the client is asking for the value of a stack object that hasn't been
1180
+ // computed, and if we have to recursively compute it, the stack object must
1181
+ // be a single store value. Since this is a very different computation,
1182
+ // split it out to its own path.
1183
+ if (value->getType ().isAddress () && isa<AllocStackInst>(value)) {
1184
+ return getSingleWriterAddressValue (value);
1185
+ }
1186
+
1187
+ if (auto *apply = dyn_cast<ApplyInst>(value)) {
1188
+ auto callResult = computeCallResult (apply);
1189
+
1190
+ // If this failed, return the error code.
1191
+ if (callResult.hasValue ())
1192
+ return callResult.getValue ();
1193
+
1194
+ assert (calculatedValues.count (apply));
1195
+ return calculatedValues[apply];
1196
+ }
1197
+
1198
+ // Compute the value of a normal single-value instructions based on its
1199
+ // operands.
1186
1200
auto result = computeConstantValue (value);
1187
1201
1188
1202
// If this is the top-level lazy interpreter, output a debug trace.
@@ -1567,15 +1581,6 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
1567
1581
return None;
1568
1582
}
1569
1583
1570
- // Make sure that our copy_value, begin_borrow form constants. Otherwise,
1571
- // return why.
1572
- if (isa<CopyValueInst>(inst) || isa<BeginBorrowInst>(inst)) {
1573
- auto result = getConstantValue (inst->getOperand (0 ));
1574
- if (!result.isConstant ())
1575
- return result;
1576
- return None;
1577
- }
1578
-
1579
1584
// If this is a deallocation of a memory object that we are tracking, then
1580
1585
// don't do anything. The memory is allocated in a BumpPtrAllocator so there
1581
1586
// is no useful way to free it.
@@ -1596,7 +1601,10 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
1596
1601
}
1597
1602
}
1598
1603
1599
- // If this is a call, evaluate it.
1604
+ // If this is a call, evaluate it. Calls are handled separately from other
1605
+ // single-valued instructions because calls which return void will not be
1606
+ // mapped to a symbolic value. Every other single-valued instruction will be
1607
+ // mapped to a symbolic value if its evaluation is successful.
1600
1608
if (auto apply = dyn_cast<ApplyInst>(inst))
1601
1609
return computeCallResult (apply);
1602
1610
@@ -1622,13 +1630,13 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
1622
1630
injectEnumInst->getOperand ());
1623
1631
}
1624
1632
1625
- // If the instruction produces a result, try constant folding it.
1626
- // If this fails, then we fail.
1627
- if (isa<SingleValueInstruction>(inst)) {
1628
- auto oneResultVal = inst->getResults ()[0 ];
1629
- auto result = getConstantValue (oneResultVal);
1633
+ // If the instruction produces a result, try computing it, and fail if the
1634
+ // computation fails.
1635
+ if (auto *singleValueInst = dyn_cast<SingleValueInstruction>(inst)) {
1636
+ auto result = computeConstantValue (singleValueInst);
1630
1637
if (!result.isConstant ())
1631
1638
return result;
1639
+ setValue (singleValueInst, result);
1632
1640
LLVM_DEBUG (llvm::dbgs () << " RESULT: " ; result.dump ());
1633
1641
return None;
1634
1642
}
@@ -1767,7 +1775,8 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap,
1767
1775
ConstExprEvaluator &evaluator) {
1768
1776
assert (!fn.isExternalDeclaration () && " Can't analyze bodyless function" );
1769
1777
ConstExprFunctionState state (evaluator, &fn, substitutionMap,
1770
- numInstEvaluated);
1778
+ numInstEvaluated,
1779
+ /* TopLevelEvaluation*/ false );
1771
1780
1772
1781
// TODO: implement caching.
1773
1782
// TODO: reject code that is too complex.
@@ -1860,7 +1869,9 @@ SymbolicValue ConstExprEvaluator::getUnknown(SILNode *node,
1860
1869
void ConstExprEvaluator::computeConstantValues (
1861
1870
ArrayRef<SILValue> values, SmallVectorImpl<SymbolicValue> &results) {
1862
1871
unsigned numInstEvaluated = 0 ;
1863
- ConstExprFunctionState state (*this , nullptr , {}, numInstEvaluated);
1872
+ ConstExprFunctionState state (*this , /* SILFunction*/ nullptr , {},
1873
+ numInstEvaluated,
1874
+ /* enableTopLevelEvaluation*/ true );
1864
1875
for (auto v : values) {
1865
1876
auto symVal = state.getConstantValue (v);
1866
1877
results.push_back (symVal);
@@ -1881,7 +1892,8 @@ ConstExprStepEvaluator::ConstExprStepEvaluator(SymbolicValueAllocator &alloc,
1881
1892
bool trackCallees)
1882
1893
: evaluator(alloc, assertConf, trackCallees),
1883
1894
internalState (
1884
- new ConstExprFunctionState(evaluator, fun, {}, stepsEvaluated)) {
1895
+ new ConstExprFunctionState(evaluator, fun, {}, stepsEvaluated,
1896
+ /* enableTopLevelEvaluation*/ false )) {
1885
1897
assert (fun);
1886
1898
}
1887
1899
0 commit comments