示例#1
0
/// In this function we create the actual cloned function and its proper cloned
/// type. But we do not create any body. This implies that the creation of the
/// actual arguments in the function is in populateCloned.
///
/// \arg PAUser The function that is being passed the partial apply.
/// \arg PAI The partial apply that is being passed to PAUser.
/// \arg ClosureIndex The index of the partial apply in PAUser's function
///                   signature.
/// \arg ClonedName The name of the cloned function that we will create.
SILFunction *
ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder,
                              const CallSiteDescriptor &CallSiteDesc,
                              StringRef ClonedName) {
  SILFunction *ClosureUser = CallSiteDesc.getApplyCallee();

  // This is the list of new interface parameters of the cloned function.
  llvm::SmallVector<SILParameterInfo, 4> NewParameterInfoList;

  // First add to NewParameterInfoList all of the SILParameterInfo in the
  // original function except for the closure.
  CanSILFunctionType ClosureUserFunTy = ClosureUser->getLoweredFunctionType();
  auto ClosureUserConv = ClosureUser->getConventions();
  unsigned Index = ClosureUserConv.getSILArgIndexOfFirstParam();
  for (auto &param : ClosureUserConv.getParameters()) {
    if (Index != CallSiteDesc.getClosureIndex())
      NewParameterInfoList.push_back(param);
    ++Index;
  }

  // Then add any arguments that are captured in the closure to the function's
  // argument type. Since they are captured, we need to pass them directly into
  // the new specialized function.
  SILFunction *ClosedOverFun = CallSiteDesc.getClosureCallee();
  auto ClosedOverFunConv = ClosedOverFun->getConventions();
  SILModule &M = ClosureUser->getModule();

  // Captured parameters are always appended to the function signature. If the
  // type of the captured argument is:
  // - direct and trivial, pass the argument as Direct_Unowned.
  // - direct and non-trivial, pass the argument as Direct_Owned.
  // - indirect, pass the argument using the same parameter convention as in the
  // original closure.
  //
  // We use the type of the closure here since we allow for the closure to be an
  // external declaration.
  unsigned NumTotalParams = ClosedOverFunConv.getNumParameters();
  unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments();
  for (auto &PInfo : ClosedOverFunConv.getParameters().slice(NumNotCaptured)) {
    ParameterConvention ParamConv;
    if (PInfo.isFormalIndirect()) {
      ParamConv = PInfo.getConvention();
      assert(!SILModuleConventions(M).useLoweredAddresses()
             || ParamConv == ParameterConvention::Indirect_Inout
             || ParamConv == ParameterConvention::Indirect_InoutAliasable);
    } else {
      ParamConv = ClosedOverFunConv.getSILType(PInfo).isTrivial(M)
                      ? ParameterConvention::Direct_Unowned
                      : ParameterConvention::Direct_Owned;
    }

    SILParameterInfo NewPInfo(PInfo.getType(), ParamConv);
    NewParameterInfoList.push_back(NewPInfo);
  }

  // The specialized function is always a thin function. This is important
  // because we may add additional parameters after the Self parameter of
  // witness methods. In this case the new function is not a method anymore.
  auto ExtInfo = ClosureUserFunTy->getExtInfo();
  ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin);

  auto ClonedTy = SILFunctionType::get(
      ClosureUserFunTy->getGenericSignature(), ExtInfo,
      ClosureUserFunTy->getCoroutineKind(),
      ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList,
      ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(),
      ClosureUserFunTy->getOptionalErrorResult(), M.getASTContext());

  // We make this function bare so we don't have to worry about decls in the
  // SILArgument.
  auto *Fn = FunctionBuilder.createFunction(
      // It's important to use a shared linkage for the specialized function
      // and not the original linkage.
      // Otherwise the new function could have an external linkage (in case the
      // original function was de-serialized) and would not be code-gen'd.
      // It's also important to disconnect this specialized function from any
      // classes (the classSubclassScope), because that may incorrectly
      // influence the linkage.
      getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName,
      ClonedTy, ClosureUser->getGenericEnvironment(),
      ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(),
      CallSiteDesc.isSerialized(), IsNotDynamic, ClosureUser->getEntryCount(),
      ClosureUser->isThunk(),
      /*classSubclassScope=*/SubclassScope::NotApplicable,
      ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(),
      ClosureUser, ClosureUser->getDebugScope());
  if (!ClosureUser->hasQualifiedOwnership()) {
    Fn->setUnqualifiedOwnership();
  }
  for (auto &Attr : ClosureUser->getSemanticsAttrs())
    Fn->addSemanticsAttr(Attr);
  return Fn;
}
SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) {
    // apply{partial_apply(x,y)}(z) -> apply(z,x,y) is triggered
    // from visitPartialApplyInst(), so bail here.
    if (isa<PartialApplyInst>(AI->getCallee()))
        return nullptr;

    if (auto *CFI = dyn_cast<ConvertFunctionInst>(AI->getCallee())) {
        return optimizeApplyOfConvertFunctionInst(AI, CFI);
    }

    // Optimize readonly functions with no meaningful users.
    SILFunction *Fn = AI->getReferencedFunction();
    if (Fn && Fn->getEffectsKind() < EffectsKind::ReadWrite) {
        UserListTy Users;
        if (isTryApplyResultNotUsed(Users, AI)) {
            SILBasicBlock *BB = AI->getParent();
            SILBasicBlock *NormalBB = AI->getNormalBB();
            SILBasicBlock *ErrorBB = AI->getErrorBB();
            SILLocation Loc = AI->getLoc();
            Builder.setInsertionPoint(BB);
            Builder.setCurrentDebugScope(AI->getDebugScope());
            eraseApply(AI, Users);

            // Replace the try_apply with a cond_br false, which will be removed by
            // SimplifyCFG. We don't want to modify the CFG in SILCombine.
            auto *TrueLit = Builder.createIntegerLiteral(Loc,
                            SILType::getBuiltinIntegerType(1, Builder.getASTContext()), 0);
            Builder.createCondBranch(Loc, TrueLit, NormalBB, ErrorBB);

            NormalBB->eraseBBArg(0);
            ErrorBB->eraseBBArg(0);
            return nullptr;
        }
        // We found a user that we can't handle.
    }

    // (try_apply (thin_to_thick_function f)) to (try_apply f)
    if (auto *TTTFI = dyn_cast<ThinToThickFunctionInst>(AI->getCallee())) {
        // TODO: Handle substitutions and indirect results
        if (AI->hasSubstitutions() || AI->hasIndirectResults())
            return nullptr;
        SmallVector<SILValue, 4> Arguments;
        for (auto &Op : AI->getArgumentOperands()) {
            Arguments.push_back(Op.get());
        }
        // The type of the substitution is the source type of the thin to thick
        // instruction.
        SILType substTy = TTTFI->getOperand()->getType();
        auto *NewAI = Builder.createTryApply(AI->getLoc(), TTTFI->getOperand(),
                                             substTy,
                                             AI->getSubstitutions(), Arguments,
                                             AI->getNormalBB(), AI->getErrorBB());
        return NewAI;
    }

    // (apply (witness_method)) -> propagate information about
    // a concrete type from init_existential_addr or init_existential_ref.
    if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee())) {
        propagateConcreteTypeOfInitExistential(AI, WMI);
        return nullptr;
    }

    // (apply (function_ref method_from_protocol_extension)) ->
    // propagate information about a concrete type from init_existential_addr or
    // init_existential_ref.
    if (isa<FunctionRefInst>(AI->getCallee())) {
        if (propagateConcreteTypeOfInitExistential(AI)) {
            return nullptr;
        }
    }

    return nullptr;
}
示例#3
0
/// In this function we create the actual cloned function and its proper cloned
/// type. But we do not create any body. This implies that the creation of the
/// actual arguments in the function is in populateCloned.
///
/// \arg PAUser The function that is being passed the partial apply.
/// \arg PAI The partial apply that is being passed to PAUser.
/// \arg ClosureIndex The index of the partial apply in PAUser's function
///                   signature.
/// \arg ClonedName The name of the cloned function that we will create.
SILFunction *
ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc,
                              StringRef ClonedName) {
  SILFunction *ClosureUser = CallSiteDesc.getApplyCallee();

  // This is the list of new interface parameters of the cloned function.
  llvm::SmallVector<SILParameterInfo, 4> NewParameterInfoList;

  // First add to NewParameterInfoList all of the SILParameterInfo in the
  // original function except for the closure.
  CanSILFunctionType ClosureUserFunTy = ClosureUser->getLoweredFunctionType();
  unsigned Index = ClosureUserFunTy->getNumIndirectResults();
  for (auto &param : ClosureUserFunTy->getParameters()) {
    if (Index != CallSiteDesc.getClosureIndex())
      NewParameterInfoList.push_back(param);
    ++Index;
  }

  // Then add any arguments that are captured in the closure to the function's
  // argument type. Since they are captured, we need to pass them directly into
  // the new specialized function.
  SILFunction *ClosedOverFun = CallSiteDesc.getClosureCallee();
  CanSILFunctionType ClosedOverFunTy = ClosedOverFun->getLoweredFunctionType();
  SILModule &M = ClosureUser->getModule();

  // Captured parameters are always appended to the function signature. If the
  // type of the captured argument is trivial, pass the argument as
  // Direct_Unowned. Otherwise pass it as Direct_Owned.
  //
  // We use the type of the closure here since we allow for the closure to be an
  // external declaration.
  unsigned NumTotalParams = ClosedOverFunTy->getParameters().size();
  unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments();
  for (auto &PInfo : ClosedOverFunTy->getParameters().slice(NumNotCaptured)) {
    if (PInfo.getSILType().isTrivial(M)) {
      SILParameterInfo NewPInfo(PInfo.getType(),
                                ParameterConvention::Direct_Unowned);
      NewParameterInfoList.push_back(NewPInfo);
      continue;
    }

    SILParameterInfo NewPInfo(PInfo.getType(),
                              ParameterConvention::Direct_Owned);
    NewParameterInfoList.push_back(NewPInfo);
  }

  // The specialized function is always a thin function. This is important
  // because we may add additional parameters after the Self parameter of
  // witness methods. In this case the new function is not a method anymore.
  auto ExtInfo = ClosureUserFunTy->getExtInfo();
  ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin);

  auto ClonedTy = SILFunctionType::get(
      ClosureUserFunTy->getGenericSignature(), ExtInfo,
      ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList,
      ClosureUserFunTy->getAllResults(),
      ClosureUserFunTy->getOptionalErrorResult(),
      M.getASTContext());

  // We make this function bare so we don't have to worry about decls in the
  // SILArgument.
  auto *Fn = M.createFunction(
      // It's important to use a shared linkage for the specialized function
      // and not the original linkage.
      // Otherwise the new function could have an external linkage (in case the
      // original function was de-serialized) and would not be code-gen'd.
      getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()),
      ClonedName, ClonedTy,
      ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(),
      IsBare, ClosureUser->isTransparent(), CallSiteDesc.isFragile(),
      ClosureUser->isThunk(), ClosureUser->getClassVisibility(),
      ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(),
      ClosureUser, ClosureUser->getDebugScope());
  Fn->setDeclCtx(ClosureUser->getDeclContext());
  if (ClosureUser->hasUnqualifiedOwnership()) {
    Fn->setUnqualifiedOwnership();
  }
  for (auto &Attr : ClosureUser->getSemanticsAttrs())
    Fn->addSemanticsAttr(Attr);
  return Fn;
}
SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) {
    Builder.setCurrentDebugScope(AI->getDebugScope());
    // apply{partial_apply(x,y)}(z) -> apply(z,x,y) is triggered
    // from visitPartialApplyInst(), so bail here.
    if (isa<PartialApplyInst>(AI->getCallee()))
        return nullptr;

    if (auto *CFI = dyn_cast<ConvertFunctionInst>(AI->getCallee()))
        return optimizeApplyOfConvertFunctionInst(AI, CFI);

    // Optimize readonly functions with no meaningful users.
    SILFunction *SF = AI->getReferencedFunction();
    if (SF && SF->getEffectsKind() < EffectsKind::ReadWrite) {
        UserListTy Users;
        if (recursivelyCollectARCUsers(Users, AI)) {
            eraseApply(AI, Users);
            return nullptr;
        }
        // We found a user that we can't handle.
    }

    if (SF) {
        if (SF->getEffectsKind() < EffectsKind::ReadWrite) {
            // Try to optimize string concatenation.
            if (auto I = optimizeConcatenationOfStringLiterals(AI)) {
                return I;
            }
        }
        if (SF->hasSemanticsAttr("array.uninitialized")) {
            UserListTy Users;
            // If the uninitialized array is only written into then it can be removed.
            if (recursivelyCollectARCUsers(Users, AI)) {
                eraseApply(AI, Users);
                return nullptr;
            }
        }
    }


    // (apply (thin_to_thick_function f)) to (apply f)
    if (auto *TTTFI = dyn_cast<ThinToThickFunctionInst>(AI->getCallee())) {
        // TODO: Handle substitutions and indirect results
        if (AI->hasSubstitutions() || AI->hasIndirectResults())
            return nullptr;
        SmallVector<SILValue, 4> Arguments;
        for (auto &Op : AI->getArgumentOperands()) {
            Arguments.push_back(Op.get());
        }
        // The type of the substitution is the source type of the thin to thick
        // instruction.
        SILType substTy = TTTFI->getOperand()->getType();
        auto *NewAI = Builder.createApply(AI->getLoc(), TTTFI->getOperand(),
                                          substTy, AI->getType(),
                                          AI->getSubstitutions(), Arguments,
                                          AI->isNonThrowing());
        return NewAI;
    }

    // (apply (witness_method)) -> propagate information about
    // a concrete type from init_existential_addr or init_existential_ref.
    if (auto *WMI = dyn_cast<WitnessMethodInst>(AI->getCallee())) {
        propagateConcreteTypeOfInitExistential(AI, WMI);
        return nullptr;
    }

    // (apply (function_ref method_from_protocol_extension)) ->
    // propagate information about a concrete type from init_existential_addr or
    // init_existential_ref.
    if (isa<FunctionRefInst>(AI->getCallee())) {
        if (propagateConcreteTypeOfInitExistential(AI)) {
            return nullptr;
        }
    }

    // Optimize f_inverse(f(x)) -> x.
    if (optimizeIdentityCastComposition(AI, "convertFromObjectiveC",
                                        "convertToObjectiveC"))
        return nullptr;
    if (optimizeIdentityCastComposition(AI, "convertToObjectiveC",
                                        "convertFromObjectiveC"))
        return nullptr;

    return nullptr;
}
void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
  // Create the optimized function !
  SILModule &M = F->getModule();
  std::string Name = createOptimizedSILFunctionName();
  SILLinkage linkage = F->getLinkage();
  if (isAvailableExternally(linkage))
    linkage = SILLinkage::Shared;

  DEBUG(llvm::dbgs() << "  -> create specialized function " << Name << "\n");

  NewF = M.createFunction(linkage, Name, createOptimizedSILFunctionType(),
                          F->getGenericEnvironment(), F->getLocation(),
                          F->isBare(), F->isTransparent(), F->isSerialized(),
                          F->isThunk(), F->getClassVisibility(),
                          F->getInlineStrategy(), F->getEffectsKind(), nullptr,
                          F->getDebugScope());
  if (F->hasUnqualifiedOwnership()) {
    NewF->setUnqualifiedOwnership();
  }

  // Then we transfer the body of F to NewF.
  NewF->spliceBody(F);

  // Array semantic clients rely on the signature being as in the original
  // version.
  for (auto &Attr : F->getSemanticsAttrs()) {
    if (!StringRef(Attr).startswith("array."))
      NewF->addSemanticsAttr(Attr);
  }

  // Do the last bit of work to the newly created optimized function.
  ArgumentExplosionFinalizeOptimizedFunction();
  DeadArgumentFinalizeOptimizedFunction();

  // Create the thunk body !
  F->setThunk(IsThunk);
  // The thunk now carries the information on how the signature is
  // optimized. If we inline the thunk, we will get the benefit of calling
  // the signature optimized function without additional setup on the
  // caller side.
  F->setInlineStrategy(AlwaysInline);
  SILBasicBlock *ThunkBody = F->createBasicBlock();
  for (auto &ArgDesc : ArgumentDescList) {
    ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl);
  }

  SILLocation Loc = ThunkBody->getParent()->getLocation();
  SILBuilder Builder(ThunkBody);
  Builder.setCurrentDebugScope(ThunkBody->getParent()->getDebugScope());

  FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);

  // Create the args for the thunk's apply, ignoring any dead arguments.
  llvm::SmallVector<SILValue, 8> ThunkArgs;
  for (auto &ArgDesc : ArgumentDescList) {
    addThunkArgument(ArgDesc, Builder, ThunkBody, ThunkArgs);
  }

  // We are ignoring generic functions and functions with out parameters for
  // now.
  SILValue ReturnValue;
  SILType LoweredType = NewF->getLoweredType();
  SILType ResultType = NewF->getConventions().getSILResultType();
  auto FunctionTy = LoweredType.castTo<SILFunctionType>();
  if (FunctionTy->hasErrorResult()) {
    // We need a try_apply to call a function with an error result.
    SILFunction *Thunk = ThunkBody->getParent();
    SILBasicBlock *NormalBlock = Thunk->createBasicBlock();
    ReturnValue =
        NormalBlock->createPHIArgument(ResultType, ValueOwnershipKind::Owned);
    SILBasicBlock *ErrorBlock = Thunk->createBasicBlock();
    SILType Error =
        SILType::getPrimitiveObjectType(FunctionTy->getErrorResult().getType());
    auto *ErrorArg =
        ErrorBlock->createPHIArgument(Error, ValueOwnershipKind::Owned);
    Builder.createTryApply(Loc, FRI, LoweredType, SubstitutionList(),
                           ThunkArgs, NormalBlock, ErrorBlock);

    Builder.setInsertionPoint(ErrorBlock);
    Builder.createThrow(Loc, ErrorArg);
    Builder.setInsertionPoint(NormalBlock);
  } else {
    ReturnValue = Builder.createApply(Loc, FRI, LoweredType, ResultType,
                                      SubstitutionList(), ThunkArgs,
                                      false);
  }

  // Set up the return results.
  if (NewF->isNoReturnFunction()) {
    Builder.createUnreachable(Loc);
  } else {
    Builder.createReturn(Loc, ReturnValue);
  }

  // Do the last bit work to finalize the thunk.
  OwnedToGuaranteedFinalizeThunkFunction(Builder, F);
  assert(F->getDebugScope()->Parent != NewF->getDebugScope()->Parent);
}