Skip to content

Commit 79afbd9

Browse files
committed
[addr-move-function] Implement the Closure Cloner.
This converts a set of closure inout_aliasable arguments to be out arguments and fixes up the initial post dominating consume set of these arguments since we are hoisting the destroy out of the cloned closure. (cherry picked from commit efd0ff8)
1 parent 36b8e39 commit 79afbd9

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed

lib/SILOptimizer/Mandatory/MoveKillsCopyableAddressesChecker.cpp

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,256 @@ bool GatherClosureUseVisitor::visitUse(Operand *op, AccessUseType useTy) {
948948
return true;
949949
}
950950

951+
//===----------------------------------------------------------------------===//
952+
// Closure Argument Cloner
953+
//===----------------------------------------------------------------------===//
954+
955+
namespace {
956+
957+
struct ClosureArgumentInOutToOutCloner
958+
: SILClonerWithScopes<ClosureArgumentInOutToOutCloner> {
959+
friend class SILInstructionVisitor<ClosureArgumentInOutToOutCloner>;
960+
friend class SILCloner<ClosureArgumentInOutToOutCloner>;
961+
962+
ConsumingClosureArgDataflowState &argDataflowState;
963+
SILFunction *orig;
964+
SmallBitVector &argsToConvertIndices;
965+
SmallVector<SILValue, 4> newConvertedArgs;
966+
967+
// The values in the original function that are promoted to stack
968+
// references.
969+
SmallPtrSet<SILValue, 4> origFunctionValues;
970+
971+
public:
972+
ClosureArgumentInOutToOutCloner(
973+
SILOptFunctionBuilder &funcBuilder, SILFunction *orig,
974+
IsSerialized_t isSerialized,
975+
ConsumingClosureArgDataflowState &argDataflowState,
976+
SmallBitVector &argsToConvertIndices);
977+
978+
void populateCloned();
979+
980+
SILFunction *getCloned() { return &getBuilder().getFunction(); }
981+
982+
void visitDestroyValueInst(DestroyValueInst *inst) {
983+
if (!argDataflowState.postDominatingConsumingUsers.erase(inst)) {
984+
SILCloner<ClosureArgumentInOutToOutCloner>::visitDestroyValueInst(inst);
985+
}
986+
987+
// Don't do anything if we have a destroy.
988+
}
989+
990+
void visitCopyAddrInst(CopyAddrInst *inst) {
991+
if (!argDataflowState.postDominatingConsumingUsers.erase(inst)) {
992+
return SILCloner<ClosureArgumentInOutToOutCloner>::visitCopyAddrInst(
993+
inst);
994+
}
995+
996+
// If this copy_addr is one of the copies that we need to fixup, convert it
997+
// to an init from a reinit.
998+
assert(!inst->isInitializationOfDest() && "Should be a reinit");
999+
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
1000+
recordClonedInstruction(
1001+
inst, getBuilder().createCopyAddr(
1002+
getOpLocation(inst->getLoc()), getOpValue(inst->getSrc()),
1003+
getOpValue(inst->getDest()), inst->isTakeOfSrc(),
1004+
IsInitialization_t::IsInitialization));
1005+
}
1006+
1007+
void visitStoreInst(StoreInst *inst) {
1008+
if (!argDataflowState.postDominatingConsumingUsers.erase(inst)) {
1009+
return SILCloner<ClosureArgumentInOutToOutCloner>::visitStoreInst(inst);
1010+
}
1011+
1012+
// If this store is one of the copies that we need to fixup, convert it
1013+
// to an init from being an assign.
1014+
assert(inst->getOwnershipQualifier() == StoreOwnershipQualifier::Assign);
1015+
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
1016+
recordClonedInstruction(
1017+
inst, getBuilder().createStore(
1018+
getOpLocation(inst->getLoc()), getOpValue(inst->getSrc()),
1019+
getOpValue(inst->getDest()), StoreOwnershipQualifier::Init));
1020+
}
1021+
1022+
private:
1023+
static SILFunction *
1024+
initCloned(SILOptFunctionBuilder &funcBuilder, SILFunction *orig,
1025+
IsSerialized_t isSerialized,
1026+
ConsumingClosureArgDataflowState &argDataflowState,
1027+
SmallBitVector &argsToConvertIndices, StringRef cloneName);
1028+
};
1029+
1030+
} // namespace
1031+
1032+
static std::string getClonedName(SILFunction *func, IsSerialized_t serialized,
1033+
SmallBitVector &argsToConvertIndices) {
1034+
auto kind = Demangle::SpecializationPass::MoveDiagnosticInOutToOut;
1035+
Mangle::FunctionSignatureSpecializationMangler Mangler(kind, serialized,
1036+
func);
1037+
for (int i = argsToConvertIndices.find_first(); i != -1;
1038+
i = argsToConvertIndices.find_next(i)) {
1039+
Mangler.setArgumentInOutToOut(i);
1040+
}
1041+
return Mangler.mangle();
1042+
}
1043+
1044+
ClosureArgumentInOutToOutCloner::ClosureArgumentInOutToOutCloner(
1045+
SILOptFunctionBuilder &funcBuilder, SILFunction *orig,
1046+
IsSerialized_t isSerialized,
1047+
ConsumingClosureArgDataflowState &argDataflowState,
1048+
SmallBitVector &argsToConvertIndices)
1049+
: SILClonerWithScopes<ClosureArgumentInOutToOutCloner>(
1050+
*initCloned(funcBuilder, orig, isSerialized, argDataflowState,
1051+
argsToConvertIndices,
1052+
getClonedName(orig, isSerialized, argsToConvertIndices))),
1053+
argDataflowState(argDataflowState), orig(orig),
1054+
argsToConvertIndices(argsToConvertIndices) {
1055+
newConvertedArgs.reserve(argsToConvertIndices.size());
1056+
assert(orig->getDebugScope()->getParentFunction() !=
1057+
getCloned()->getDebugScope()->getParentFunction());
1058+
}
1059+
1060+
/// Create the function corresponding to the clone of the
1061+
/// original closure with the signature modified to reflect promoted
1062+
/// parameters (which are specified by PromotedArgIndices).
1063+
SILFunction *ClosureArgumentInOutToOutCloner::initCloned(
1064+
SILOptFunctionBuilder &funcBuilder, SILFunction *orig,
1065+
IsSerialized_t serialized,
1066+
ConsumingClosureArgDataflowState &argDataflowState,
1067+
SmallBitVector &argsToConvertIndices, StringRef clonedName) {
1068+
SILModule &mod = orig->getModule();
1069+
SmallVector<SILParameterInfo, 4> clonedInterfaceArgTys;
1070+
SmallVector<SILResultInfo, 4> clonedResultInfos;
1071+
SILFunctionType *origFTI = orig->getLoweredFunctionType();
1072+
1073+
// First initialized cloned result infos with the old results.
1074+
for (auto result : origFTI->getResults())
1075+
clonedResultInfos.push_back(result);
1076+
1077+
// Generate a new parameter list with deleted parameters removed...
1078+
unsigned initArgIndex = orig->getConventions().getSILArgIndexOfFirstParam();
1079+
for (auto state :
1080+
llvm::enumerate(origFTI->getParameters().drop_front(initArgIndex))) {
1081+
unsigned index = state.index();
1082+
auto paramInfo = state.value();
1083+
1084+
// If we are supposed to convert this, add the parameter to the result list.
1085+
if (argsToConvertIndices.test(index)) {
1086+
clonedResultInfos.emplace_back(paramInfo.getInterfaceType(),
1087+
ResultConvention::Indirect);
1088+
continue;
1089+
}
1090+
1091+
// Otherwise, just let it through.
1092+
clonedInterfaceArgTys.push_back(paramInfo);
1093+
++index;
1094+
}
1095+
1096+
// Create the new function type for the cloned function with some of
1097+
// the parameters moved to be results.
1098+
auto clonedTy = SILFunctionType::get(
1099+
origFTI->getInvocationGenericSignature(), origFTI->getExtInfo(),
1100+
origFTI->getCoroutineKind(), origFTI->getCalleeConvention(),
1101+
clonedInterfaceArgTys, origFTI->getYields(), clonedResultInfos,
1102+
origFTI->getOptionalErrorResult(), origFTI->getPatternSubstitutions(),
1103+
origFTI->getInvocationSubstitutions(), mod.getASTContext(),
1104+
origFTI->getWitnessMethodConformanceOrInvalid());
1105+
1106+
assert((orig->isTransparent() || orig->isBare() || orig->getLocation()) &&
1107+
"SILFunction missing location");
1108+
assert((orig->isTransparent() || orig->isBare() || orig->getDebugScope()) &&
1109+
"SILFunction missing DebugScope");
1110+
assert(!orig->isGlobalInit() && "Global initializer cannot be cloned");
1111+
auto *Fn = funcBuilder.createFunction(
1112+
swift::getSpecializedLinkage(orig, orig->getLinkage()), clonedName,
1113+
clonedTy, orig->getGenericEnvironment(), orig->getLocation(),
1114+
orig->isBare(), orig->isTransparent(), serialized, IsNotDynamic,
1115+
IsNotDistributed, orig->getEntryCount(), orig->isThunk(),
1116+
orig->getClassSubclassScope(), orig->getInlineStrategy(),
1117+
orig->getEffectsKind(), orig, orig->getDebugScope());
1118+
for (auto &Attr : orig->getSemanticsAttrs()) {
1119+
Fn->addSemanticsAttr(Attr);
1120+
}
1121+
if (!orig->hasOwnership()) {
1122+
Fn->setOwnershipEliminated();
1123+
}
1124+
return Fn;
1125+
}
1126+
1127+
/// Populate the body of the cloned closure, modifying instructions as
1128+
/// necessary to take into consideration the removed parameters.
1129+
void ClosureArgumentInOutToOutCloner::populateCloned() {
1130+
SILFunction *cloned = getCloned();
1131+
1132+
// Create arguments for the entry block
1133+
SILBasicBlock *origEntryBlock = &*orig->begin();
1134+
SILBasicBlock *clonedEntryBlock = cloned->createBasicBlock();
1135+
1136+
SmallVector<SILValue, 4> entryArgs;
1137+
entryArgs.reserve(origEntryBlock->getArguments().size());
1138+
1139+
// Initialize all new arg slots to an invalid value.
1140+
newConvertedArgs.resize(origEntryBlock->getArguments().size());
1141+
1142+
// First process all of the indirect results and add our new results after
1143+
// them.
1144+
auto oldArgs = origEntryBlock->getArguments();
1145+
auto origConventions = orig->getConventions();
1146+
for (unsigned i : range(origConventions.getSILArgIndexOfFirstIndirectResult(),
1147+
origConventions.getSILArgIndexOfFirstParam())) {
1148+
auto *a = oldArgs[i];
1149+
// Create a new argument which copies the original argument.
1150+
entryArgs.push_back(
1151+
clonedEntryBlock->createFunctionArgument(a->getType(), a->getDecl()));
1152+
}
1153+
1154+
// To avoid needing to mess with types, just go through our original arguments
1155+
// in the entry block to get the right types.
1156+
llvm::SmallMapVector<SILValue, SILValue, 4> movedArgs;
1157+
SmallBitVector newResults(origEntryBlock->getNumArguments());
1158+
for (auto state : llvm::enumerate(origEntryBlock->getArguments())) {
1159+
unsigned argNo = state.index();
1160+
if (!argsToConvertIndices.test(argNo))
1161+
continue;
1162+
1163+
auto *arg = state.value();
1164+
auto *newArg = clonedEntryBlock->createFunctionArgument(arg->getType(),
1165+
arg->getDecl());
1166+
movedArgs[arg] = newArg;
1167+
entryArgs.push_back(newArg);
1168+
}
1169+
1170+
// Finally, recreate the rest of the arguments which we did not specialize.
1171+
for (auto state : llvm::enumerate(origEntryBlock->getArguments())) {
1172+
unsigned argNo = state.index();
1173+
if (argsToConvertIndices.test(argNo))
1174+
continue;
1175+
1176+
auto *arg = state.value();
1177+
entryArgs.push_back(clonedEntryBlock->createFunctionArgument(
1178+
arg->getType(), arg->getDecl()));
1179+
}
1180+
1181+
// Visit original BBs in depth-first preorder, starting with the
1182+
// entry block, cloning all instructions and terminators.
1183+
cloneFunctionBody(orig, clonedEntryBlock, entryArgs,
1184+
[&](SILValue clonedArg) -> SILValue {
1185+
auto iter = movedArgs.find(clonedArg);
1186+
if (iter == movedArgs.end())
1187+
return clonedArg;
1188+
return iter->second;
1189+
});
1190+
1191+
// As we clone instructions, any that we handled specially will have been
1192+
// erased from postDominatingConsumingUsers. If we didn't erase all of them,
1193+
// then there is a bug in the implementation.
1194+
assert(llvm::all_of(argDataflowState.postDominatingConsumingUsers,
1195+
[&](Optional<SILInstruction *> user) {
1196+
return user.hasValue();
1197+
}) &&
1198+
"Did not handle a post dominating consuming user?!");
1199+
}
1200+
9511201
//===----------------------------------------------------------------------===//
9521202
// Global Dataflow
9531203
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)