void FunctionSignatureSpecializationMangler::mangleArgument( ArgumentModifierIntBase ArgMod, NullablePtr<SILInstruction> Inst) { if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ConstantProp)) { mangleConstantProp(cast<LiteralInst>(Inst.get())); return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ClosureProp)) { mangleClosureProp(Inst.get()); return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::Unmodified)) { ArgOpBuffer << 'n'; return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToValue)) { ArgOpBuffer << 'i'; return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToStack)) { ArgOpBuffer << 's'; return; } bool hasSomeMod = false; if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::ExistentialToGeneric)) { ArgOpBuffer << 'e'; hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::Dead)) { ArgOpBuffer << 'd'; hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::OwnedToGuaranteed)) { ArgOpBuffer << (hasSomeMod ? 'G' : 'g'); hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::GuaranteedToOwned)) { ArgOpBuffer << (hasSomeMod ? 'O' : 'o'); hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::SROA)) { ArgOpBuffer << (hasSomeMod ? 'X' : 'x'); hasSomeMod = true; } assert(hasSomeMod && "Unknown modifier"); }
void FunctionSignatureSpecializationMangler::mangleArgument( ArgumentModifierIntBase ArgMod, NullablePtr<SILInstruction> Inst) { if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ConstantProp)) { mangleConstantProp(cast<LiteralInst>(Inst.get())); return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ClosureProp)) { if (auto *PAI = dyn_cast<PartialApplyInst>(Inst.get())) { mangleClosureProp(PAI); return; } auto *TTTFI = cast<ThinToThickFunctionInst>(Inst.get()); mangleClosureProp(TTTFI); return; } llvm::raw_ostream &os = getBuffer(); if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::Unmodified)) { os << "n"; return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToValue)) { os << "i"; return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToStack)) { os << "k"; return; } bool hasSomeMod = false; if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::Dead)) { os << "d"; hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::OwnedToGuaranteed)) { os << "g"; hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::SROA)) { os << "s"; hasSomeMod = true; } assert(hasSomeMod && "Unknown modifier"); }
/// This is separate from the main verification routine, so I can minimize the /// amount of places that need to use SILGenFunction &SGF. static void verifyHelper(ArrayRef<ManagedValue> values, NullablePtr<SILGenFunction> SGF = nullptr) { // This is a no-op in non-assert builds. #ifndef NDEBUG auto result = Optional<ValueOwnershipKind>(ValueOwnershipKind::Any); Optional<bool> sameHaveCleanups; for (ManagedValue v : values) { assert((!SGF || !v.getType().isLoadable(SGF.get()->getModule()) || v.getType().isObject()) && "All loadable values in an RValue must be an object"); ValueOwnershipKind kind = v.getOwnershipKind(); if (kind == ValueOwnershipKind::Trivial) continue; // Merge together whether or not the RValue has cleanups. if (!sameHaveCleanups.hasValue()) { sameHaveCleanups = v.hasCleanup(); } else { assert(*sameHaveCleanups == v.hasCleanup()); } // This variable is here so that if the assert below fires, the current // reduction value is still available. auto newResult = result.getValue().merge(kind); assert(newResult.hasValue()); result = newResult; } #endif }
SILInstruction *SILCombiner::visitSelectEnumInst(SelectEnumInst *SEI) { // Canonicalize a select_enum: if the default refers to exactly one case, then // replace the default with that case. if (SEI->hasDefault()) { NullablePtr<EnumElementDecl> elementDecl = SEI->getUniqueCaseForDefault(); if (elementDecl.isNonNull()) { // Construct a new instruction by copying all the case entries. SmallVector<std::pair<EnumElementDecl *, SILValue>, 4> CaseValues; for (int idx = 0, numIdcs = SEI->getNumCases(); idx < numIdcs; idx++) { CaseValues.push_back(SEI->getCase(idx)); } // Add the default-entry of the original instruction as case-entry. CaseValues.push_back( std::make_pair(elementDecl.get(), SEI->getDefaultResult())); return Builder.createSelectEnum(SEI->getLoc(), SEI->getEnumOperand(), SEI->getType(), SILValue(), CaseValues); } } // TODO: We should be able to flat-out replace the select_enum instruction // with the selected value in another pass. For parity with the enum_is_tag // combiner pass, handle integer literals for now. auto *EI = dyn_cast<EnumInst>(SEI->getEnumOperand()); if (!EI) return nullptr; SILValue selected; for (unsigned i = 0, e = SEI->getNumCases(); i < e; ++i) { auto casePair = SEI->getCase(i); if (casePair.first == EI->getElement()) { selected = casePair.second; break; } } if (!selected) selected = SEI->getDefaultResult(); if (auto *ILI = dyn_cast<IntegerLiteralInst>(selected)) { return Builder.createIntegerLiteral(ILI->getLoc(), ILI->getType(), ILI->getValue()); } return nullptr; }
SILInstruction *SILCombiner::visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) { // Canonicalize a select_enum_addr: if the default refers to exactly one case, // then replace the default with that case. Builder.setCurrentDebugScope(SEAI->getDebugScope()); if (SEAI->hasDefault()) { NullablePtr<EnumElementDecl> elementDecl = SEAI->getUniqueCaseForDefault(); if (elementDecl.isNonNull()) { // Construct a new instruction by copying all the case entries. SmallVector<std::pair<EnumElementDecl *, SILValue>, 4> CaseValues; for (int idx = 0, numIdcs = SEAI->getNumCases(); idx < numIdcs; idx++) { CaseValues.push_back(SEAI->getCase(idx)); } // Add the default-entry of the original instruction as case-entry. CaseValues.push_back( std::make_pair(elementDecl.get(), SEAI->getDefaultResult())); return Builder.createSelectEnumAddr(SEAI->getLoc(), SEAI->getEnumOperand(), SEAI->getType(), SILValue(), CaseValues); } } // Promote select_enum_addr to select_enum if the enum is loadable. // = select_enum_addr %ptr : $*Optional<SomeClass>, case ... // -> // %value = load %ptr // = select_enum %value SILType Ty = SEAI->getEnumOperand().getType(); if (!Ty.isLoadable(SEAI->getModule())) return nullptr; SmallVector<std::pair<EnumElementDecl*, SILValue>, 8> Cases; for (int i = 0, e = SEAI->getNumCases(); i < e; ++i) Cases.push_back(SEAI->getCase(i)); SILValue Default = SEAI->hasDefault() ? SEAI->getDefaultResult() : SILValue(); LoadInst *EnumVal = Builder.createLoad(SEAI->getLoc(), SEAI->getEnumOperand()); auto *I = Builder.createSelectEnum(SEAI->getLoc(), EnumVal, SEAI->getType(), Default, Cases); return I; }
/// Returns true if we proved that RCIdentity has a non-payloaded enum case, /// false if RCIdentity has a payloaded enum case, and None if we failed to find /// anything. static llvm::Optional<bool> proveNonPayloadedEnumCase(SILBasicBlock *BB, SILValue RCIdentity) { // Then see if BB has one predecessor... if it does not, return None so we // keep searching up the domtree. SILBasicBlock *SinglePred = BB->getSinglePredecessorBlock(); if (!SinglePred) return None; // Check if SinglePred has a switch_enum terminator switching on // RCIdentity... If it does not, return None so we keep searching up the // domtree. auto *SEI = dyn_cast<SwitchEnumInst>(SinglePred->getTerminator()); if (!SEI || SEI->getOperand() != RCIdentity) return None; // Then return true if along the edge from the SEI to BB, RCIdentity has a // non-payloaded enum value. NullablePtr<EnumElementDecl> Decl = SEI->getUniqueCaseForDestination(BB); if (Decl.isNull()) return None; return !Decl.get()->hasArgumentType(); }
SILValue LSValue::reduce(LSLocation &Base, SILModule *M, LSLocationValueMap &Values, SILInstruction *InsertPt, TypeExpansionAnalysis *TE) { // Walk bottom up the projection tree, try to reason about how to construct // a single SILValue out of all the available values for all the memory // locations. // // First, get a list of all the leaf nodes and intermediate nodes for the // Base memory location. LSLocationList ALocs; ProjectionPath &BasePath = Base.getPath().getValue(); for (const auto &P : TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) { ALocs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath)); } // Second, go from leaf nodes to their parents. This guarantees that at the // point the parent is processed, its children have been processed already. for (auto I = ALocs.rbegin(), E = ALocs.rend(); I != E; ++I) { // This is a leaf node, we have a value for it. // // Reached the end of the projection tree, this is a leaf node. LSLocationList FirstLevel; I->getFirstLevelLSLocations(FirstLevel, M); if (FirstLevel.empty()) continue; // If this is a class reference type, we have reached end of the type tree. if (I->getType().getClassOrBoundGenericClass()) continue; // This is NOT a leaf node, we need to construct a value for it. // There is only 1 children node and its value's projection path is not // empty, keep stripping it. auto Iter = FirstLevel.begin(); LSValue &FirstVal = Values[*Iter]; if (FirstLevel.size() == 1 && !FirstVal.hasEmptyProjectionPath()) { Values[*I] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeLSLocations(Values, FirstLevel); continue; } // If there are more than 1 children and all the children nodes have // LSValues with the same base and non-empty projection path. we can get // away by not extracting value for every single field. // // Simply create a new node with all the aggregated base value, i.e. // stripping off the last level projection. bool HasIdenticalValueBase = true; SILValue FirstBase = FirstVal.getBase(); Iter = std::next(Iter); for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) { LSValue &V = Values[*Iter]; HasIdenticalValueBase &= (FirstBase == V.getBase()); } if (FirstLevel.size() > 1 && HasIdenticalValueBase && !FirstVal.hasEmptyProjectionPath()) { Values[*I] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeLSLocations(Values, FirstLevel); continue; } // In 3 cases do we need aggregation. // // 1. If there is only 1 child and we cannot strip off any projections, // that means we need to create an aggregation. // // 2. There are multiple children and they have the same base, but empty // projection paths. // // 3. Children have values from different bases, We need to create // extractions and aggregation in this case. // llvm::SmallVector<SILValue, 8> Vals; for (auto &X : FirstLevel) { Vals.push_back(Values[X].materialize(InsertPt)); } SILBuilder Builder(InsertPt); // We use an auto-generated SILLocation for now. // TODO: make the sil location more precise. NullablePtr<swift::SILInstruction> AI = Projection::createAggFromFirstLevelProjections( Builder, RegularLocation::getAutoGeneratedLocation(), I->getType(), Vals); // This is the Value for the current node. ProjectionPath P; Values[*I] = LSValue(SILValue(AI.get()), P); removeLSLocations(Values, FirstLevel); // Keep iterating until we have reach the top-most level of the projection // tree. // i.e. the memory location represented by the Base. } assert(Values.size() == 1 && "Should have a single location this point"); // Finally materialize and return the forwarding SILValue. return Values.begin()->second.materialize(InsertPt); }
void LSValue::reduceInner(LSLocation &Base, SILModule *M, LSLocationValueMap &Values, SILInstruction *InsertPt) { // If this is a class reference type, we have reached end of the type tree. if (Base.getType(M).getClassOrBoundGenericClass()) return; // This is a leaf node, we must have a value for it. LSLocationList NextLevel; Base.getNextLevelLSLocations(NextLevel, M); if (NextLevel.empty()) return; // This is not a leaf node, reduce the next level node one by one. for (auto &X : NextLevel) { LSValue::reduceInner(X, M, Values, InsertPt); } // This is NOT a leaf node, we need to construct a value for it. auto Iter = NextLevel.begin(); LSValue &FirstVal = Values[*Iter]; // There is only 1 children node and its value's projection path is not // empty, keep stripping it. if (NextLevel.size() == 1 && !FirstVal.hasEmptyProjectionPath()) { Values[Base] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeLSLocations(Values, NextLevel); return; } bool HasIdenticalBase = true; SILValue FirstBase = FirstVal.getBase(); for (auto &X : NextLevel) { HasIdenticalBase &= (FirstBase == Values[X].getBase()); } // This is NOT a leaf node and it has multiple children, but they have the // same value base. if (NextLevel.size() > 1 && HasIdenticalBase) { if (!FirstVal.hasEmptyProjectionPath()) { Values[Base] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeLSLocations(Values, NextLevel); return; } } // In 3 cases do we need aggregation. // // 1. If there is only 1 child and we cannot strip off any projections, // that means we need to create an aggregation. // // 2. There are multiple children and they have the same base, but empty // projection paths. // // 3. Children have values from different bases, We need to create // extractions and aggregation in this case. // llvm::SmallVector<SILValue, 8> Vals; for (auto &X : NextLevel) { Vals.push_back(Values[X].materialize(InsertPt)); } SILBuilder Builder(InsertPt); Builder.setCurrentDebugScope(InsertPt->getFunction()->getDebugScope()); // We use an auto-generated SILLocation for now. NullablePtr<swift::SILInstruction> AI = Projection::createAggFromFirstLevelProjections( Builder, RegularLocation::getAutoGeneratedLocation(), Base.getType(M).getObjectType(), Vals); // This is the Value for the current base. ProjectionPath P(Base.getType(M)); Values[Base] = LSValue(SILValue(AI.get()), P); removeLSLocations(Values, NextLevel); }
SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *Mod, MemLocationValueMap &Values, SILInstruction *InsertPt) { // Walk bottom up the projection tree, try to reason about how to construct // a single SILValue out of all the available values for all the memory // locations. // // First, get a list of all the leaf nodes and intermediate nodes for the // Base memory location. MemLocationList ALocs; ProjectionPathList Paths; ProjectionPath::expandTypeIntoLeafProjectionPaths(Base.getType(), Mod, Paths, false); for (auto &X : Paths) { ALocs.push_back(MemLocation::createMemLocation(Base.getBase(), X.getValue(), Base.getPath().getValue())); } // Second, go from leaf nodes to their parents. This guarantees that at the // point the parent is processed, its children have been processed already. for (auto I = ALocs.rbegin(), E = ALocs.rend(); I != E; ++I) { // This is a leaf node, we have a value for it. // // Reached the end of the projection tree, this is a leaf node. MemLocationList FirstLevel; I->getFirstLevelMemLocations(FirstLevel, Mod); if (FirstLevel.empty()) continue; // If this is a class reference type, we have reached end of the type tree. if (I->getType().getClassOrBoundGenericClass()) continue; // This is NOT a leaf node, we need to construct a value for it. // // If there are more than 1 children and all the children nodes have // LoadStoreValues with the same base. we can get away by not extracting // value // for every single field. // // Simply create a new node with all the aggregated base value, i.e. // stripping off the last level projection. // bool HasIdenticalValueBase = true; auto Iter = FirstLevel.begin(); LoadStoreValue &FirstVal = Values[*Iter]; SILValue FirstBase = FirstVal.getBase(); Iter = std::next(Iter); for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) { LoadStoreValue &V = Values[*Iter]; HasIdenticalValueBase &= (FirstBase == V.getBase()); } if (HasIdenticalValueBase && (FirstLevel.size() > 1 || !FirstVal.hasEmptyProjectionPath())) { Values[*I] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeMemLocations(Values, FirstLevel); continue; } // In 2 cases do we need aggregation. // // 1. If there is only 1 child and we can not strip off any projections, // that means we need to create an aggregation. // // 2. Children have values from different bases, We need to create // extractions and aggregation in this case. // llvm::SmallVector<SILValue, 8> Vals; for (auto &X : FirstLevel) { Vals.push_back(Values[X].materialize(InsertPt)); } SILBuilder Builder(InsertPt); NullablePtr<swift::SILInstruction> AI = Projection::createAggFromFirstLevelProjections( Builder, InsertPt->getLoc(), I->getType(), Vals); // This is the Value for the current node. ProjectionPath P; Values[*I] = LoadStoreValue(SILValue(AI.get()), P); removeMemLocations(Values, FirstLevel); // Keep iterating until we have reach the top-most level of the projection // tree. // i.e. the memory location represented by the Base. } assert(Values.size() == 1 && "Should have a single location this point"); // Finally materialize and return the forwarding SILValue. return Values.begin()->second.materialize(InsertPt); }