@@ -282,42 +282,52 @@ evaluateOrSkip(ConstExprStepEvaluator &stepEval,
282
282
283
283
// / Return true iff the given value is a stdlib Int or Bool and it not a direct
284
284
// / construction of Int or Bool.
285
- static bool isFoldableIntOrBool (SILValue value, SILInstruction *definingInst,
286
- ASTContext &astContext) {
287
- assert (definingInst);
288
- return !isa<StructInst>(definingInst) &&
289
- isIntegerOrBoolType (value->getType (), astContext);
285
+ static bool isFoldableIntOrBool (SILValue value, ASTContext &astContext) {
286
+ return isIntegerOrBoolType (value->getType (), astContext) &&
287
+ !isa<StructInst>(value);
290
288
}
291
289
292
290
// / Return true iff the given value is a string and is not an initialization
293
291
// / of an string from a string literal.
294
- static bool isFoldableString (SILValue value, SILInstruction *definingInst,
295
- ASTContext &astContext) {
296
- assert (definingInst);
292
+ static bool isFoldableString (SILValue value, ASTContext &astContext) {
297
293
return isStringType (value->getType (), astContext) &&
298
- !getStringMakeUTF8Init (definingInst);
294
+ (!isa<ApplyInst>(value) ||
295
+ !getStringMakeUTF8Init (cast<ApplyInst>(value)));
299
296
}
300
297
301
298
// / Return true iff the given value is an array and is not an initialization
302
299
// / of an array from an array literal.
303
- static bool isFoldableArray (SILValue value, SILInstruction *definingInst,
304
- ASTContext &astContext) {
305
- assert (definingInst);
300
+ static bool isFoldableArray (SILValue value, ASTContext &astContext) {
306
301
if (!isArrayType (value->getType (), astContext))
307
302
return false ;
308
-
309
- // Check if this is not an initialization of an array from a literal.
303
+ // If value is an initialization of an array from a literal or an empty array
304
+ // initializer, it need not be folded. Arrays constructed from literals use a
305
+ // function with semantics: "array.uninitialized_intrinsic" that returns
306
+ // a pair, where the first element of the pair is the array.
307
+ SILInstruction *definingInst = value->getDefiningInstruction ();
308
+ if (!definingInst)
309
+ return true ;
310
310
SILInstruction *constructorInst = definingInst;
311
311
if (isa<DestructureTupleInst>(definingInst) ||
312
312
isa<TupleExtractInst>(definingInst)) {
313
313
constructorInst = definingInst->getOperand (0 )->getDefiningInstruction ();
314
314
}
315
- ApplyInst *apply = dyn_cast<ApplyInst>(definingInst);
316
- if (!apply)
315
+ if (!constructorInst || !isa<ApplyInst>(constructorInst))
317
316
return true ;
318
- SILFunction *callee = apply->getCalleeFunction ();
319
- return !callee || !callee->hasSemanticsAttr (" array.init.empty" ) ||
320
- !callee->hasSemanticsAttr (" array.uninitialized_intrinsic" );
317
+ SILFunction *callee = cast<ApplyInst>(constructorInst)->getCalleeFunction ();
318
+ return !callee ||
319
+ (!callee->hasSemanticsAttr (" array.init.empty" ) &&
320
+ !callee->hasSemanticsAttr (" array.uninitialized_intrinsic" ));
321
+ }
322
+
323
+ // / Return true iff the given value is a closure but is not a creation of a
324
+ // / closure e.g., through partial_apply or thin_to_thick_function or
325
+ // / convert_function.
326
+ static bool isFoldableClosure (SILValue value) {
327
+ return value->getType ().is <SILFunctionType>() &&
328
+ (!isa<FunctionRefInst>(value) && !isa<PartialApplyInst>(value) &&
329
+ !isa<ThinToThickFunctionInst>(value) &&
330
+ !isa<ConvertFunctionInst>(value));
321
331
}
322
332
323
333
// / Check whether a SILValue is foldable. String, integer, array and
@@ -337,9 +347,9 @@ static bool isSILValueFoldable(SILValue value) {
337
347
!isa<LoadBorrowInst>(definingInst) &&
338
348
!isa<BeginBorrowInst>(definingInst) &&
339
349
!isa<CopyValueInst>(definingInst) &&
340
- (isFoldableIntOrBool (value, definingInst, astContext) ||
341
- isFoldableString (value, definingInst, astContext) ||
342
- isFoldableArray (value, definingInst, astContext)));
350
+ (isFoldableIntOrBool (value, astContext) ||
351
+ isFoldableString (value, astContext) ||
352
+ isFoldableArray (value, astContext) || isFoldableClosure (value )));
343
353
}
344
354
345
355
// / Diagnose failure during evaluation of a call to a constant-evaluable
@@ -585,6 +595,39 @@ static SILValue emitCodeForConstantArray(ArrayRef<SILValue> elements,
585
595
return arraySIL;
586
596
}
587
597
598
+ // / Given a SILValue \p value, return the instruction immediately following the
599
+ // / definition of the value. That is, if the value is defined by an
600
+ // / instruction, return the instruction following the definition. Otherwise, if
601
+ // / the value is a basic block parameter, return the first instruction of the
602
+ // / basic block.
603
+ SILInstruction *getInstructionFollowingValueDefinition (SILValue value) {
604
+ SILInstruction *definingInst = value->getDefiningInstruction ();
605
+ if (definingInst) {
606
+ return &*std::next (definingInst->getIterator ());
607
+ }
608
+ // Here value must be a basic block argument.
609
+ SILBasicBlock *bb = value->getParentBlock ();
610
+ return &*bb->begin ();
611
+ }
612
+
613
+ // / Given a SILValue \p value, create a copy of the value using copy_value in
614
+ // / OSSA or retain in non-OSSA, if \p value is a non-trivial type. Otherwise, if
615
+ // / \p value is a trivial type, return the value itself.
616
+ SILValue makeOwnedCopyOfSILValue (SILValue value, SILFunction &fun) {
617
+ SILType type = value->getType ();
618
+ if (type.isTrivial (fun))
619
+ return value;
620
+ assert (!type.isAddress () && " cannot make owned copy of addresses" );
621
+
622
+ SILInstruction *instAfterValueDefinition =
623
+ getInstructionFollowingValueDefinition (value);
624
+ SILLocation copyLoc = instAfterValueDefinition->getLoc ();
625
+ SILBuilderWithScope builder (instAfterValueDefinition);
626
+ const TypeLowering &typeLowering = builder.getTypeLowering (type);
627
+ SILValue copy = typeLowering.emitCopyValue (builder, copyLoc, value);
628
+ return copy;
629
+ }
630
+
588
631
// / Generate SIL code that computes the constant given by the symbolic value
589
632
// / `symVal`. Note that strings and struct-typed constant values will require
590
633
// / multiple instructions to be emitted.
@@ -684,6 +727,61 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal,
684
727
elementSILValues, expectedType->getCanonicalType (), builder, loc);
685
728
return arraySIL;
686
729
}
730
+ case SymbolicValue::Closure: {
731
+ assert (expectedType->is <AnyFunctionType>() ||
732
+ expectedType->is <SILFunctionType>());
733
+
734
+ SymbolicClosure *closure = symVal.getClosure ();
735
+ SubstitutionMap callSubstMap = closure->getCallSubstitutionMap ();
736
+ SILModule &module = builder.getModule ();
737
+ ArrayRef<SymbolicClosureArgument> captures = closure->getCaptures ();
738
+
739
+ // Recursively emit code for all captured values that are mapped to a
740
+ // symbolic value. If there is a captured value that is not mapped
741
+ // to a symbolic value, use the captured value as such (after possibly
742
+ // copying non-trivial captures).
743
+ SmallVector<SILValue, 4 > capturedSILVals;
744
+ for (SymbolicClosureArgument capture : captures) {
745
+ SILValue captureOperand = capture.first ;
746
+ Optional<SymbolicValue> captureSymVal = capture.second ;
747
+ if (!captureSymVal) {
748
+ SILFunction &fun = builder.getFunction ();
749
+ assert (captureOperand->getFunction () == &fun &&
750
+ " non-constant captured arugment not defined in this function" );
751
+ // If the captureOperand is a non-trivial value, it should be copied
752
+ // as it now used in a new folded closure.
753
+ SILValue captureCopy = makeOwnedCopyOfSILValue (captureOperand, fun);
754
+ capturedSILVals.push_back (captureCopy);
755
+ continue ;
756
+ }
757
+ // Here, we have a symbolic value for the capture. Therefore, use it to
758
+ // create a new constant at this point. Note that the captured operand
759
+ // type may have generic parameters which has to be substituted with the
760
+ // substitution map that was inferred by the constant evaluator at the
761
+ // partial-apply site.
762
+ SILType operandType = captureOperand->getType ();
763
+ SILType captureType = operandType.subst (module , callSubstMap);
764
+ SILValue captureSILVal = emitCodeForSymbolicValue (
765
+ captureSymVal.getValue (), captureType.getASTType (), builder, loc,
766
+ stringInfo);
767
+ capturedSILVals.push_back (captureSILVal);
768
+ }
769
+
770
+ FunctionRefInst *functionRef =
771
+ builder.createFunctionRef (loc, closure->getTarget ());
772
+ SILType closureType = closure->getClosureType ();
773
+ ParameterConvention convention =
774
+ closureType.getAs <SILFunctionType>()->getCalleeConvention ();
775
+ PartialApplyInst *papply = builder.createPartialApply (
776
+ loc, functionRef, callSubstMap, capturedSILVals, convention);
777
+ // The type of the created closure must be a lowering of the expected type.
778
+ SILType resultType = papply->getType ();
779
+ CanType expectedCanType = expectedType->getCanonicalType ();
780
+ assert (expectedType->is <SILFunctionType>()
781
+ ? resultType.getASTType () == expectedCanType
782
+ : resultType.is <SILFunctionType>());
783
+ return papply;
784
+ }
687
785
default : {
688
786
llvm_unreachable (" Symbolic value kind is not supported" );
689
787
}
@@ -997,8 +1095,9 @@ static void constantFold(SILInstruction *start,
997
1095
// / marks the begining of the string interpolation that is used to create an
998
1096
// / OSLogMessage instance. This function traverses the backward data-dependence
999
1097
// / chain of the given OSLogMessage initializer: \p oslogInit. As a special case
1000
- // / it avoid chasing the data-dependenceies through a partial-apply as they are
1001
- // / considered as constants.
1098
+ // / it avoids chasing the data-dependencies from the captured values of
1099
+ // / partial-apply instructions, as a partial apply instruction is considered as
1100
+ // / a constant regardless of the constantness of its captures.
1002
1101
static SILInstruction *beginOfInterpolation (ApplyInst *oslogInit) {
1003
1102
auto oslogInitCallSite = FullApplySite (oslogInit);
1004
1103
SILFunction *callee = oslogInitCallSite.getCalleeFunction ();
@@ -1023,7 +1122,14 @@ static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) {
1023
1122
// Partial applies are used to capture the dynamic arguments passed to
1024
1123
// the string interpolation. Their arguments are not required to be
1025
1124
// known at compile time and they need not be constant evaluated.
1026
- // Therefore, do not follow this dependency chain.
1125
+ // Therefore, follow only the dependency chain along function ref operand.
1126
+ SILInstruction *definingInstruction =
1127
+ inst->getOperand (0 )->getDefiningInstruction ();
1128
+ assert (definingInstruction && " no function-ref operand in partial-apply" );
1129
+ if (seenInstructions.insert (definingInstruction).second ) {
1130
+ worklist.push_back (definingInstruction);
1131
+ candidateStartInstructions.insert (definingInstruction);
1132
+ }
1027
1133
continue ;
1028
1134
}
1029
1135
0 commit comments