@@ -55,7 +55,10 @@ enum class WellKnownFunction {
55
55
// String.percentEscapedString.getter
56
56
StringEscapePercent,
57
57
// _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...)
58
- AssertionFailure
58
+ AssertionFailure,
59
+ // A function taking one argument that prints the symbolic value of the
60
+ // argument during constant evaluation. This must only be used for debugging.
61
+ DebugPrint
59
62
};
60
63
61
64
static llvm::Optional<WellKnownFunction> classifyFunction (SILFunction *fn) {
@@ -80,6 +83,12 @@ static llvm::Optional<WellKnownFunction> classifyFunction(SILFunction *fn) {
80
83
return WellKnownFunction::StringEscapePercent;
81
84
if (fn->hasSemanticsAttrThatStartsWith (" programtermination_point" ))
82
85
return WellKnownFunction::AssertionFailure;
86
+ // A call to a function with the following semantics annotation will be
87
+ // considered as a DebugPrint operation. The evaluator will print the value
88
+ // of the single argument passed to this function call to the standard error.
89
+ // This functionality must be used only for debugging the evaluator.
90
+ if (fn->hasSemanticsAttrThatStartsWith (" constant_evaluator_debug_print" ))
91
+ return WellKnownFunction::DebugPrint;
83
92
return None;
84
93
}
85
94
@@ -222,6 +231,13 @@ class ConstExprFunctionState {
222
231
llvm::Optional<SymbolicValue>
223
232
computeWellKnownCallResult (ApplyInst *apply, WellKnownFunction callee);
224
233
234
+ // / Evaluate a closure creation instruction which is either a partial_apply
235
+ // / instruction or a thin_to_think_function instruction. On success, this
236
+ // / function will bind the \c closureInst parameter to its symbolic value.
237
+ // / On failure, it returns the unknown symbolic value that captures the error.
238
+ llvm::Optional<SymbolicValue>
239
+ evaluateClosureCreation (SingleValueInstruction *closureInst);
240
+
225
241
SymbolicValue getSingleWriterAddressValue (SILValue addr);
226
242
SymbolicValue getConstAddrAndLoadResult (SILValue addr);
227
243
SymbolicValue loadAddrValue (SILValue addr, SymbolicValue addrVal);
@@ -883,36 +899,19 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
883
899
conventions.getNumIndirectSILResults () == 0 &&
884
900
" unexpected Array.append(_:) signature" );
885
901
// Get the element to be appended which is passed indirectly (@in).
886
- SymbolicValue elementAddress = getConstantValue (apply->getOperand (1 ));
887
- if (!elementAddress.isConstant ())
888
- return elementAddress;
889
-
890
- auto invalidOperand = [&]() {
902
+ SymbolicValue element = getConstAddrAndLoadResult (apply->getOperand (1 ));
903
+ if (!element.isConstant ())
904
+ return element;
905
+
906
+ // Get the array value. The array is passed @inout and could be a property
907
+ // of a struct.
908
+ SILValue arrayAddress = apply->getOperand (2 );
909
+ SymbolicValue arrayValue = getConstAddrAndLoadResult (arrayAddress);
910
+ if (!arrayValue.isConstant ())
911
+ return arrayValue;
912
+ if (arrayValue.getKind () != SymbolicValue::Array) {
891
913
return getUnknown (evaluator, (SILInstruction *)apply,
892
914
UnknownReason::InvalidOperandValue);
893
- };
894
- if (elementAddress.getKind () != SymbolicValue::Address) {
895
- // TODO: store the operand number in the error message here.
896
- return invalidOperand ();
897
- }
898
-
899
- SmallVector<unsigned , 4 > elementAP;
900
- SymbolicValue element =
901
- elementAddress.getAddressValue (elementAP)->getValue ();
902
-
903
- // Get the array value. The array is passed @inout.
904
- SymbolicValue arrayAddress = getConstantValue (apply->getOperand (2 ));
905
- if (!arrayAddress.isConstant ())
906
- return arrayAddress;
907
- if (arrayAddress.getKind () != SymbolicValue::Address)
908
- return invalidOperand ();
909
-
910
- SmallVector<unsigned , 4 > arrayAP;
911
- SymbolicValueMemoryObject *arrayMemoryObject =
912
- arrayAddress.getAddressValue (arrayAP);
913
- SymbolicValue arrayValue = arrayMemoryObject->getValue ();
914
- if (arrayValue.getKind () != SymbolicValue::Array) {
915
- return invalidOperand ();
916
915
}
917
916
918
917
// Create a new array storage by appending the \c element to the existing
@@ -930,7 +929,7 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
930
929
newElements, elementType, allocator);
931
930
SymbolicValue newArray = SymbolicValue::getArray (arrayValue.getArrayType (),
932
931
newStorage, allocator);
933
- arrayMemoryObject-> setIndexedElement (arrayAP, newArray, allocator );
932
+ computeFSStore ( newArray, arrayAddress );
934
933
return None;
935
934
}
936
935
case WellKnownFunction::StringInitEmpty: { // String.init()
@@ -1056,6 +1055,21 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply,
1056
1055
setValue (apply, resultVal);
1057
1056
return None;
1058
1057
}
1058
+ case WellKnownFunction::DebugPrint: {
1059
+ assert (apply->getNumArguments () == 1 &&
1060
+ " debug_print function must take exactly one argument" );
1061
+ SILValue argument = apply->getArgument (0 );
1062
+ SymbolicValue argValue = getConstantValue (argument);
1063
+ llvm::errs () << " Debug print output " ;
1064
+ argValue.print (llvm::errs ());
1065
+ if (argValue.getKind () != SymbolicValue::Address)
1066
+ return None;
1067
+
1068
+ llvm::errs () << " \n Addressed Memory Object: " ;
1069
+ SymbolicValueMemoryObject *memObj = argValue.getAddressValueMemoryObject ();
1070
+ memObj->getValue ().print (llvm::errs ());
1071
+ return None;
1072
+ }
1059
1073
}
1060
1074
llvm_unreachable (" unhandled WellKnownFunction" );
1061
1075
}
@@ -1092,10 +1106,11 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
1092
1106
}
1093
1107
1094
1108
// If we reached an external function that hasn't been deserialized yet, make
1095
- // sure to pull it in so we can see its body. If that fails, then we can't
1096
- // analyze the function.
1109
+ // sure to pull it in so we can see its body. If that fails, then we can't
1110
+ // analyze the function. Note: pull in everything referenced from another
1111
+ // module in case some referenced functions have non-public linkage.
1097
1112
if (callee->isExternalDeclaration ()) {
1098
- callee ->getModule ().loadFunction (callee);
1113
+ apply ->getModule ().linkFunction (callee, SILModule::LinkingMode::LinkAll );
1099
1114
if (callee->isExternalDeclaration ())
1100
1115
return computeOpaqueCallResult (apply, callee);
1101
1116
}
@@ -1547,6 +1562,43 @@ ConstExprFunctionState::computeFSStore(SymbolicValue storedCst, SILValue dest) {
1547
1562
return None;
1548
1563
}
1549
1564
1565
+ llvm::Optional<SymbolicValue> ConstExprFunctionState::evaluateClosureCreation (
1566
+ SingleValueInstruction *closureInst) {
1567
+ assert (isa<PartialApplyInst>(closureInst) ||
1568
+ isa<ThinToThickFunctionInst>(closureInst));
1569
+ SILValue calleeOperand = closureInst->getOperand (0 );
1570
+ SymbolicValue calleeValue = getConstantValue (calleeOperand);
1571
+ if (!calleeValue.isConstant ())
1572
+ return calleeValue;
1573
+ if (calleeValue.getKind () != SymbolicValue::Function) {
1574
+ return getUnknown (evaluator, (SILInstruction *)closureInst,
1575
+ UnknownReason::InvalidOperandValue);
1576
+ }
1577
+
1578
+ SILFunction *target = calleeValue.getFunctionValue ();
1579
+ assert (target != nullptr );
1580
+
1581
+ SmallVector<SymbolicClosureArgument, 4 > captures;
1582
+
1583
+ // If this is a partial-apply instruction, arguments to this partial-apply
1584
+ // instruction are the captures of the closure.
1585
+ if (PartialApplyInst *papply = dyn_cast<PartialApplyInst>(closureInst)) {
1586
+ for (SILValue capturedSILValue : papply->getArguments ()) {
1587
+ SymbolicValue capturedSymbolicValue = getConstantValue (capturedSILValue);
1588
+ if (!capturedSymbolicValue.isConstant ()) {
1589
+ captures.push_back ({capturedSILValue, None});
1590
+ continue ;
1591
+ }
1592
+ captures.push_back ({capturedSILValue, capturedSymbolicValue});
1593
+ }
1594
+ }
1595
+
1596
+ auto closureVal =
1597
+ SymbolicValue::makeClosure (target, captures, evaluator.getAllocator ());
1598
+ setValue (closureInst, closureVal);
1599
+ return None;
1600
+ }
1601
+
1550
1602
// / Evaluate the specified instruction in a flow sensitive way, for use by
1551
1603
// / the constexpr function evaluator. This does not handle control flow
1552
1604
// / statements. This returns None on success, and an Unknown SymbolicValue with
@@ -1630,34 +1682,8 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
1630
1682
injectEnumInst->getOperand ());
1631
1683
}
1632
1684
1633
- if (auto *papply = dyn_cast<PartialApplyInst>(inst)) {
1634
- SILValue calleeOperand = papply->getOperand (0 );
1635
- SymbolicValue calleeValue = getConstantValue (calleeOperand);
1636
- if (!calleeValue.isConstant ())
1637
- return calleeValue;
1638
- if (calleeValue.getKind () != SymbolicValue::Function) {
1639
- return getUnknown (evaluator, (SILInstruction *)papply,
1640
- UnknownReason::InvalidOperandValue);
1641
- }
1642
-
1643
- SILFunction *target = calleeValue.getFunctionValue ();
1644
- assert (target != nullptr );
1645
-
1646
- // Arguments to this partial-apply instruction are the captures of the
1647
- // closure.
1648
- SmallVector<SymbolicClosureArgument, 4 > captures;
1649
- for (SILValue argument : papply->getArguments ()) {
1650
- SymbolicValue argumentValue = getConstantValue (argument);
1651
- if (!argumentValue.isConstant ()) {
1652
- captures.push_back ({ argument, None });
1653
- continue ;
1654
- }
1655
- captures.push_back ({ argument, argumentValue });
1656
- }
1657
- auto closureVal = SymbolicValue::makeClosure (target, captures,
1658
- evaluator.getAllocator ());
1659
- setValue (papply, closureVal);
1660
- return None;
1685
+ if (isa<PartialApplyInst>(inst) || isa<ThinToThickFunctionInst>(inst)) {
1686
+ return evaluateClosureCreation (cast<SingleValueInstruction>(inst));
1661
1687
}
1662
1688
1663
1689
// If the instruction produces a result, try computing it, and fail if the
@@ -2073,6 +2099,8 @@ ConstExprStepEvaluator::lookupConstValue(SILValue value) {
2073
2099
return res;
2074
2100
}
2075
2101
2102
+ void ConstExprStepEvaluator::dumpState () { internalState->dump (); }
2103
+
2076
2104
bool swift::isKnownConstantEvaluableFunction (SILFunction *fun) {
2077
2105
return classifyFunction (fun).hasValue ();
2078
2106
}
0 commit comments