@@ -43,8 +43,30 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap,
43
43
// ConstantFolding.h/cpp files should be subsumed by this, as this is a more
44
44
// general framework.
45
45
46
+
47
+ // We have a list of functions that we hackily special case. In order to keep
48
+ // this localized, we use this classifier function. This should be replaced
49
+ // with an attribute put on the standard library that captures this info.
50
+ enum class WellKnownFunction {
51
+ Unknown,
52
+ StringInitEmpty, // String.init()
53
+ AssertionFailure, // _assertionFailure(_:_:file:line:flags:)
54
+ };
55
+
56
+
57
+ static WellKnownFunction classifyFunction (StringRef mangledName) {
58
+ if (mangledName == " $SS2SycfC" )
59
+ return WellKnownFunction::StringInitEmpty;
60
+
61
+ if (mangledName.contains (" _assertionFailure" ))
62
+ return WellKnownFunction::AssertionFailure;
63
+ return WellKnownFunction::Unknown;
64
+ }
65
+
66
+
67
+
46
68
// ===----------------------------------------------------------------------===//
47
- // MemoryValue implementation.
69
+ // AddressValue implementation.
48
70
// ===----------------------------------------------------------------------===//
49
71
50
72
namespace {
@@ -253,6 +275,10 @@ namespace {
253
275
254
276
AddressValue computeSingleStoreAddressValue (SILValue addr);
255
277
llvm::Optional<SymbolicValue> computeCallResult (ApplyInst *apply);
278
+
279
+ llvm::Optional<SymbolicValue>
280
+ computeOpaqueCallResult (ApplyInst *apply, SILFunction *callee);
281
+
256
282
SymbolicValue computeLoadResult (SILValue addr);
257
283
llvm::Optional<SymbolicValue> computeFSStore (SymbolicValue storedCst,
258
284
SILValue dest);
@@ -268,20 +294,9 @@ Type ConstExprFunctionState::simplifyType(Type ty) {
268
294
return substitutionMap.empty () ? ty : ty.subst (substitutionMap);
269
295
}
270
296
271
- // / Lazily initialize the specified SIL Loader.
272
- static SerializedSILLoader &
273
- initLoader (std::unique_ptr<SerializedSILLoader> &silLoader, SILModule &module ) {
274
- if (!silLoader)
275
- silLoader = SerializedSILLoader::create (module .getASTContext (),
276
- &module , nullptr );
277
- return *silLoader;
278
- }
279
-
280
-
281
297
// TODO: refactor this out somewhere sharable between autodiff and this code.
282
298
static void lookupOrLinkWitnessTable (ProtocolConformanceRef confRef,
283
- SILModule &module ,
284
- std::unique_ptr<SerializedSILLoader> &silLoader) {
299
+ SILModule &module ) {
285
300
// Cannot resolve abstract conformances.
286
301
if (!confRef.isConcrete ())
287
302
return ;
@@ -295,7 +310,8 @@ static void lookupOrLinkWitnessTable(ProtocolConformanceRef confRef,
295
310
conf->getDeclContext ()->getAsNominalTypeOrNominalTypeExtensionContext ();
296
311
auto linkage = getSILLinkage (getDeclLinkage (decl), NotForDefinition);
297
312
auto *newTable = module .createWitnessTableDeclaration (conf, linkage);
298
- newTable = initLoader (silLoader, module ).lookupWitnessTable (newTable);
313
+ newTable = module .getSILLoader ()->lookupWitnessTable (newTable);
314
+
299
315
// Update linkage for witness methods.
300
316
// FIXME: Figure out why witnesses have shared linkage by default.
301
317
for (auto &entry : newTable->getEntries ())
@@ -374,8 +390,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
374
390
module .lookUpFunctionInWitnessTable (conf, wmi->getMember ()).first ;
375
391
if (!fn) {
376
392
// If that failed, try force loading it, and try again.
377
- lookupOrLinkWitnessTable (conf, wmi->getModule (),
378
- evaluator.getSILLoader ());
393
+ lookupOrLinkWitnessTable (conf, wmi->getModule ());
379
394
fn = module .lookUpFunctionInWitnessTable (conf, wmi->getMember ()).first ;
380
395
}
381
396
@@ -416,7 +431,27 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
416
431
return SymbolicValue::getUnknown (SILValue (inst), UnknownReason::Default);
417
432
};
418
433
419
- // Unary operations first.
434
+ // Nullary operations.
435
+ if (inst->getNumOperands () == 0 ) {
436
+ switch (builtin.ID ) {
437
+ default : break ;
438
+ case BuiltinValueKind::AssertConf: {
439
+ // assert_configuration builtin gets replaces with debug/release/etc
440
+ // constants.
441
+ auto config = inst->getModule ().getOptions ().AssertConfig ;
442
+ // Don't replace assert_configuration if we're not supposed to.
443
+ if (config == SILOptions::DisableReplacement)
444
+ break ;
445
+ auto resultBitWidth =
446
+ inst->getType ().castTo <BuiltinIntegerType>()->getGreatestWidth ();
447
+ auto result = APInt (resultBitWidth, config);
448
+ return SymbolicValue::getInteger (result, evaluator.getAllocator ());
449
+ }
450
+ }
451
+ }
452
+
453
+
454
+ // Unary operations.
420
455
if (inst->getNumOperands () == 1 ) {
421
456
auto operand = getConstantValue (inst->getOperand (0 ));
422
457
// TODO: Could add a "value used here" sort of diagnostic.
@@ -451,6 +486,10 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
451
486
if (builtin.ID == BuiltinValueKind::UToSCheckedTrunc)
452
487
overflowed |= result.isSignBitSet ();
453
488
489
+ if (overflowed)
490
+ return SymbolicValue::getUnknown (SILValue (inst),
491
+ UnknownReason::Overflow);
492
+
454
493
auto &allocator = evaluator.getAllocator ();
455
494
// Build the Symbolic value result for our truncated value.
456
495
return SymbolicValue::getAggregate ({
@@ -663,14 +702,20 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
663
702
[&](const std::function<APInt (const APInt &, const APInt &, bool &)> &fn)
664
703
-> SymbolicValue {
665
704
if (operand0.getKind () != SymbolicValue::Integer ||
666
- operand1.getKind () != SymbolicValue::Integer)
705
+ operand1.getKind () != SymbolicValue::Integer ||
706
+ operand2.getKind () != SymbolicValue::Integer)
667
707
return unknownResult ();
668
708
669
- // TODO: We can/should diagnose statically detectable integer overflow
670
- // errors and subsume the ConstantFolding.cpp mandatory SIL pass.
671
709
auto l = operand0.getIntegerValue (), r = operand1.getIntegerValue ();
672
710
bool overflowed = false ;
673
711
auto result = fn (l, r, overflowed);
712
+
713
+ // Return a statically diagnosed overflow if the operation is supposed to
714
+ // trap on overflow.
715
+ if (overflowed && !operand2.getIntegerValue ().isNullValue ())
716
+ return SymbolicValue::getUnknown (SILValue (inst),
717
+ UnknownReason::Overflow);
718
+
674
719
auto &allocator = evaluator.getAllocator ();
675
720
// Build the Symbolic value result for our normal and overflow bit.
676
721
return SymbolicValue::getAggregate ({
@@ -714,6 +759,34 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
714
759
return unknownResult ();
715
760
}
716
761
762
+ // Handle calls to opaque callees, either by handling them and returning None or
763
+ // by returning with a Unknown indicating a failure.
764
+ llvm::Optional<SymbolicValue>
765
+ ConstExprFunctionState::computeOpaqueCallResult (ApplyInst *apply,
766
+ SILFunction *callee) {
767
+ // This is a termination point like fatalError.
768
+ if (callee->hasSemanticsAttr (" arc.programtermination_point" )) {
769
+ // TODO: Actually get the message out of fatalError. We can literally get
770
+ // its string and file/line/col info and propagate it up!
771
+ return SymbolicValue::getUnknown ((SILInstruction*)apply,
772
+ UnknownReason::Trap);
773
+ }
774
+
775
+ if (classifyFunction (callee->getName ()) ==
776
+ WellKnownFunction::AssertionFailure) {
777
+ // TODO: Actually get the message out of fatalError. We can literally get
778
+ // its string and file/line/col info and propagate it up!
779
+ return SymbolicValue::getUnknown ((SILInstruction*)apply,
780
+ UnknownReason::Trap);
781
+ }
782
+
783
+ DEBUG (llvm::errs () << " ConstExpr Opaque Callee: " << *callee << " \n " );
784
+ return SymbolicValue::getUnknown ((SILInstruction*)apply,
785
+ UnknownReason::Default);
786
+ }
787
+
788
+
789
+ // TODO: Refactor this to someplace common, this is defined in Devirtualize.cpp.
717
790
SubstitutionMap
718
791
getWitnessMethodSubstitutions (SILModule &Module, ApplySite AI, SILFunction *F,
719
792
ProtocolConformanceRef CRef);
@@ -726,48 +799,45 @@ llvm::Optional<SymbolicValue>
726
799
ConstExprFunctionState::computeCallResult (ApplyInst *apply) {
727
800
auto conventions = apply->getSubstCalleeConv ();
728
801
729
- // The many failure paths through this function invoke this to return their
730
- // failure information.
731
- auto failure = [&](UnknownReason reason) -> SymbolicValue {
732
- auto unknown = SymbolicValue::getUnknown ((SILInstruction*)apply, reason);
733
- // Remember that this call produced unknown as well as any indirect results.
734
- calculatedValues[apply] = unknown;
735
-
736
- for (unsigned i = 0 , e = conventions.getNumIndirectSILResults ();
737
- i != e; ++i) {
738
- auto resultOperand = apply->getOperand (i+1 );
739
- assert (resultOperand->getType ().isAddress () &&
740
- " Indirect results should be by-address" );
741
- calculatedValues[resultOperand] = unknown;
742
- }
743
- return unknown;
744
- };
745
-
746
802
// Determine the callee.
747
- auto calleeLV = getConstantValue (apply->getOperand (0 ));
748
- if (!calleeLV.isConstant ())
749
- return failure (UnknownReason::Default);
803
+ auto calleeFn = getConstantValue (apply->getOperand (0 ));
804
+ if (!calleeFn.isConstant ())
805
+ return SymbolicValue::getUnknown ((SILInstruction*)apply,
806
+ UnknownReason::Default);
750
807
751
808
SILFunction *callee;
752
809
Optional<ProtocolConformanceRef> conformance;
753
- std::tie (callee, conformance) = calleeLV .getFunctionValue ();
810
+ std::tie (callee, conformance) = calleeFn .getFunctionValue ();
754
811
755
812
756
813
// If we reached an external function that hasn't been deserialized yet, make
757
814
// sure to pull it in so we can see its body. If that fails, then we can't
758
815
// analyze the function.
759
816
if (callee->isExternalDeclaration ()) {
760
- auto newCallee = initLoader (evaluator.getSILLoader (),
761
- callee->getModule ()).lookupSILFunction (callee);
762
- if (!newCallee || newCallee->isExternalDeclaration ()) {
763
- DEBUG (llvm::errs () << " ConstExpr Opaque Callee: " << *callee << " \n " );
764
- return failure (UnknownReason::Default);
765
- }
766
- callee = newCallee;
817
+ callee->getModule ().loadFunction (callee);
818
+ if (callee->isExternalDeclaration ())
819
+ return computeOpaqueCallResult (apply, callee);
767
820
}
768
821
769
822
// TODO: Verify that the callee was defined as a @constexpr function.
770
823
824
+ // If this is a well-known function, do not step into it.
825
+ //
826
+ // FIXME: This should be based on the SILFunction carrying a
827
+ // @constexprSemantics sort of attribute that indicates it is well known,
828
+ // just like the existing SemanticsAttr thing.
829
+ switch (classifyFunction (callee->getName ())) {
830
+ default : break ;
831
+ case WellKnownFunction::StringInitEmpty: { // String.init()
832
+ assert (conventions.getNumDirectSILResults () == 1 &&
833
+ conventions.getNumIndirectSILResults () == 0 &&
834
+ " unexpected String.init() signature" );
835
+ auto result = SymbolicValue::getString (" " , evaluator.getAllocator ());
836
+ setValue (apply->getResults ()[0 ], result);
837
+ return None;
838
+ }
839
+ }
840
+
771
841
// Verify that we can fold all of the arguments to the call.
772
842
SmallVector<SymbolicValue, 4 > paramConstants;
773
843
unsigned applyParamBaseIndex = 1 +conventions.getNumIndirectSILResults ();
@@ -834,7 +904,7 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
834
904
if (unsigned numNormalResults = conventions.getNumDirectSILResults ()) {
835
905
// TODO: unclear when this happens, is this for tuple result values?
836
906
assert (numNormalResults == 1 && " Multiple results aren't supported?" );
837
- calculatedValues[ apply->getResults ()[0 ]] = results[nextResult];
907
+ setValue ( apply->getResults ()[0 ], results[nextResult]) ;
838
908
++nextResult;
839
909
}
840
910
@@ -863,6 +933,13 @@ SymbolicValue ConstExprFunctionState::getConstantValue(SILValue value) {
863
933
864
934
// Compute the value of a normal instruction based on its operands.
865
935
auto result = computeConstantValue (value);
936
+
937
+ // If this is the top-level lazy interpreter, output a debug trace.
938
+ if (!fn) {
939
+ DEBUG (llvm::errs () << " ConstExpr top level: " ; value->dump ());
940
+ DEBUG (llvm::errs () << " RESULT: " ; result.dump ());
941
+ }
942
+
866
943
return calculatedValues[value] = result;
867
944
}
868
945
@@ -1185,11 +1262,12 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
1185
1262
1186
1263
if (isa<CondFailInst>(inst)) {
1187
1264
auto failed = getConstantValue (inst->getOperand (0 ));
1188
- if (failed.isConstant () && failed.getIntegerValue () == 0 )
1189
- return None;
1190
- // TODO: Emit a diagnostic if this cond_fail actually fails under constant
1191
- // folding.
1192
- DEBUG (llvm::errs () << " CONDFAIL FAILED!\n " );
1265
+ if (failed.getKind () == SymbolicValue::Integer) {
1266
+ if (failed.getIntegerValue () == 0 )
1267
+ return None;
1268
+ // Conditional fail actually failed.
1269
+ return SymbolicValue::getUnknown (inst, UnknownReason::Trap);
1270
+ }
1193
1271
}
1194
1272
1195
1273
// If this is a call, evaluate it.
0 commit comments