Skip to content

Commit efd0ff8

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.
1 parent 2998747 commit efd0ff8

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)