@@ -43,8 +43,30 @@ evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap,
4343// ConstantFolding.h/cpp files should be subsumed by this, as this is a more
4444// general framework.
4545
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+
4668// ===----------------------------------------------------------------------===//
47- // MemoryValue implementation.
69+ // AddressValue implementation.
4870// ===----------------------------------------------------------------------===//
4971
5072namespace {
@@ -253,6 +275,10 @@ namespace {
253275
254276 AddressValue computeSingleStoreAddressValue (SILValue addr);
255277 llvm::Optional<SymbolicValue> computeCallResult (ApplyInst *apply);
278+
279+ llvm::Optional<SymbolicValue>
280+ computeOpaqueCallResult (ApplyInst *apply, SILFunction *callee);
281+
256282 SymbolicValue computeLoadResult (SILValue addr);
257283 llvm::Optional<SymbolicValue> computeFSStore (SymbolicValue storedCst,
258284 SILValue dest);
@@ -268,20 +294,9 @@ Type ConstExprFunctionState::simplifyType(Type ty) {
268294 return substitutionMap.empty () ? ty : ty.subst (substitutionMap);
269295}
270296
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-
281297// TODO: refactor this out somewhere sharable between autodiff and this code.
282298static void lookupOrLinkWitnessTable (ProtocolConformanceRef confRef,
283- SILModule &module ,
284- std::unique_ptr<SerializedSILLoader> &silLoader) {
299+ SILModule &module ) {
285300 // Cannot resolve abstract conformances.
286301 if (!confRef.isConcrete ())
287302 return ;
@@ -295,7 +310,8 @@ static void lookupOrLinkWitnessTable(ProtocolConformanceRef confRef,
295310 conf->getDeclContext ()->getAsNominalTypeOrNominalTypeExtensionContext ();
296311 auto linkage = getSILLinkage (getDeclLinkage (decl), NotForDefinition);
297312 auto *newTable = module .createWitnessTableDeclaration (conf, linkage);
298- newTable = initLoader (silLoader, module ).lookupWitnessTable (newTable);
313+ newTable = module .getSILLoader ()->lookupWitnessTable (newTable);
314+
299315 // Update linkage for witness methods.
300316 // FIXME: Figure out why witnesses have shared linkage by default.
301317 for (auto &entry : newTable->getEntries ())
@@ -374,8 +390,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) {
374390 module .lookUpFunctionInWitnessTable (conf, wmi->getMember ()).first ;
375391 if (!fn) {
376392 // If that failed, try force loading it, and try again.
377- lookupOrLinkWitnessTable (conf, wmi->getModule (),
378- evaluator.getSILLoader ());
393+ lookupOrLinkWitnessTable (conf, wmi->getModule ());
379394 fn = module .lookUpFunctionInWitnessTable (conf, wmi->getMember ()).first ;
380395 }
381396
@@ -416,7 +431,27 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
416431 return SymbolicValue::getUnknown (SILValue (inst), UnknownReason::Default);
417432 };
418433
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.
420455 if (inst->getNumOperands () == 1 ) {
421456 auto operand = getConstantValue (inst->getOperand (0 ));
422457 // TODO: Could add a "value used here" sort of diagnostic.
@@ -451,6 +486,10 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
451486 if (builtin.ID == BuiltinValueKind::UToSCheckedTrunc)
452487 overflowed |= result.isSignBitSet ();
453488
489+ if (overflowed)
490+ return SymbolicValue::getUnknown (SILValue (inst),
491+ UnknownReason::Overflow);
492+
454493 auto &allocator = evaluator.getAllocator ();
455494 // Build the Symbolic value result for our truncated value.
456495 return SymbolicValue::getAggregate ({
@@ -663,14 +702,20 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
663702 [&](const std::function<APInt (const APInt &, const APInt &, bool &)> &fn)
664703 -> SymbolicValue {
665704 if (operand0.getKind () != SymbolicValue::Integer ||
666- operand1.getKind () != SymbolicValue::Integer)
705+ operand1.getKind () != SymbolicValue::Integer ||
706+ operand2.getKind () != SymbolicValue::Integer)
667707 return unknownResult ();
668708
669- // TODO: We can/should diagnose statically detectable integer overflow
670- // errors and subsume the ConstantFolding.cpp mandatory SIL pass.
671709 auto l = operand0.getIntegerValue (), r = operand1.getIntegerValue ();
672710 bool overflowed = false ;
673711 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+
674719 auto &allocator = evaluator.getAllocator ();
675720 // Build the Symbolic value result for our normal and overflow bit.
676721 return SymbolicValue::getAggregate ({
@@ -714,6 +759,34 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
714759 return unknownResult ();
715760}
716761
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.
717790SubstitutionMap
718791getWitnessMethodSubstitutions (SILModule &Module, ApplySite AI, SILFunction *F,
719792 ProtocolConformanceRef CRef);
@@ -726,48 +799,45 @@ llvm::Optional<SymbolicValue>
726799ConstExprFunctionState::computeCallResult (ApplyInst *apply) {
727800 auto conventions = apply->getSubstCalleeConv ();
728801
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-
746802 // 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);
750807
751808 SILFunction *callee;
752809 Optional<ProtocolConformanceRef> conformance;
753- std::tie (callee, conformance) = calleeLV .getFunctionValue ();
810+ std::tie (callee, conformance) = calleeFn .getFunctionValue ();
754811
755812
756813 // If we reached an external function that hasn't been deserialized yet, make
757814 // sure to pull it in so we can see its body. If that fails, then we can't
758815 // analyze the function.
759816 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);
767820 }
768821
769822 // TODO: Verify that the callee was defined as a @constexpr function.
770823
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+
771841 // Verify that we can fold all of the arguments to the call.
772842 SmallVector<SymbolicValue, 4 > paramConstants;
773843 unsigned applyParamBaseIndex = 1 +conventions.getNumIndirectSILResults ();
@@ -834,7 +904,7 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) {
834904 if (unsigned numNormalResults = conventions.getNumDirectSILResults ()) {
835905 // TODO: unclear when this happens, is this for tuple result values?
836906 assert (numNormalResults == 1 && " Multiple results aren't supported?" );
837- calculatedValues[ apply->getResults ()[0 ]] = results[nextResult];
907+ setValue ( apply->getResults ()[0 ], results[nextResult]) ;
838908 ++nextResult;
839909 }
840910
@@ -863,6 +933,13 @@ SymbolicValue ConstExprFunctionState::getConstantValue(SILValue value) {
863933
864934 // Compute the value of a normal instruction based on its operands.
865935 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+
866943 return calculatedValues[value] = result;
867944}
868945
@@ -1185,11 +1262,12 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) {
11851262
11861263 if (isa<CondFailInst>(inst)) {
11871264 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+ }
11931271 }
11941272
11951273 // If this is a call, evaluate it.
0 commit comments