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");
}
Exemple #2
0
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");
}
Exemple #3
0
/// 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);
}
Exemple #8
0
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);
}
Exemple #9
0
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);
}