示例#1
0
/// Return a basic block suitable to be the destination block of a
/// try_apply instruction.  The block is implicitly emitted and filled in.
SILBasicBlock *
SILGenFunction::getTryApplyErrorDest(SILLocation loc,
                                     SILResultInfo exnResult,
                                     bool suppressErrorPath) {
  assert(exnResult.getConvention() == ResultConvention::Owned);

  // For now, don't try to re-use destination blocks for multiple
  // failure sites.
  SILBasicBlock *destBB = createBasicBlock(FunctionSection::Postmatter);
  SILValue exn = destBB->createArgument(exnResult.getSILType());

  assert(B.hasValidInsertionPoint() && B.insertingAtEndOfBlock());
  SavedInsertionPoint savedIP(*this, destBB, FunctionSection::Postmatter);

  // If we're suppressing error paths, just wrap it up as unreachable
  // and return.
  if (suppressErrorPath) {
    B.createUnreachable(loc);
    return destBB;
  }

  // We don't want to exit here with a dead cleanup on the stack,
  // so push the scope first.
  FullExpr scope(Cleanups, CleanupLocation::get(loc));
  emitThrow(loc, emitManagedRValueWithCleanup(exn));

  return destBB;
}
示例#2
0
/// Perform a foreign error check by testing whether the error was nil.
static void
emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc,
                            ManagedValue errorSlot, bool suppressErrorCheck) {
  // If we're suppressing the check, just don't check.
  if (suppressErrorCheck) return;

  SILValue optionalError = gen.B.emitLoadValueOperation(
      loc, errorSlot.forward(gen), LoadOwnershipQualifier::Take);

  ASTContext &ctx = gen.getASTContext();

  // Switch on the optional error.
  SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter);
  errorBB->createArgument(optionalError->getType().unwrapAnyOptionalType());
  SILBasicBlock *contBB = gen.createBasicBlock();
  gen.B.createSwitchEnum(loc, optionalError, /*default*/ nullptr,
                         { { ctx.getOptionalSomeDecl(), errorBB },
                           { ctx.getOptionalNoneDecl(), contBB } });

  // Emit the error block. Pass in none for the errorSlot since we have passed
  // in the errorSlot as our BB argument so we can pass ownership correctly. In
  // emitForeignErrorBlock, we will create the appropriate cleanup for the
  // argument.
  gen.emitForeignErrorBlock(loc, errorBB, None);

  // Return the result.
  gen.B.emitBlock(contBB);
  return;
}
示例#3
0
Condition SILGenFunction::emitCondition(SILValue V, SILLocation Loc,
                                        bool hasFalseCode, bool invertValue,
                                        ArrayRef<SILType> contArgs) {
  assert(B.hasValidInsertionPoint() &&
         "emitting condition at unreachable point");

  SILBasicBlock *ContBB = createBasicBlock();

  for (SILType argTy : contArgs) {
    ContBB->createArgument(argTy);
  }
  
  SILBasicBlock *FalseBB, *FalseDestBB;
  if (hasFalseCode) {
    FalseBB = FalseDestBB = createBasicBlock();
  } else {
    FalseBB = nullptr;
    FalseDestBB = ContBB;
  }

  SILBasicBlock *TrueBB = createBasicBlock();

  if (invertValue)
    B.createCondBranch(Loc, V, FalseDestBB, TrueBB);
  else
    B.createCondBranch(Loc, V, TrueBB, FalseDestBB);
  
  return Condition(TrueBB, FalseBB, ContBB, Loc);
}
示例#4
0
/// Perform a foreign error check by testing whether the call result is nil.
static ManagedValue
emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc,
                          ManagedValue origResult, ManagedValue errorSlot,
                          bool suppressErrorCheck) {
  // Take local ownership of the optional result value.
  SILValue optionalResult = origResult.forward(gen);

  SILType resultObjectType =
    optionalResult->getType().getAnyOptionalObjectType();

  ASTContext &ctx = gen.getASTContext();

  // If we're suppressing the check, just do an unchecked take.
  if (suppressErrorCheck) {
    SILValue objectResult =
      gen.B.createUncheckedEnumData(loc, optionalResult,
                                    ctx.getOptionalSomeDecl());
    return gen.emitManagedRValueWithCleanup(objectResult);
  }

  // Switch on the optional result.
  SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter);
  SILBasicBlock *contBB = gen.createBasicBlock();
  gen.B.createSwitchEnum(loc, optionalResult, /*default*/ nullptr,
                         { { ctx.getOptionalSomeDecl(), contBB },
                           { ctx.getOptionalNoneDecl(), errorBB } });

  // Emit the error block.
  gen.emitForeignErrorBlock(loc, errorBB, errorSlot);

  // In the continuation block, take ownership of the now non-optional
  // result value.
  gen.B.emitBlock(contBB);
  SILValue objectResult = contBB->createArgument(resultObjectType);
  return gen.emitManagedRValueWithCleanup(objectResult);
}
示例#5
0
void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
  // Create the optimized function !
  SILModule &M = F->getModule();
  std::string Name = getUniqueName(createOptimizedSILFunctionName(), M);
  SILLinkage linkage = F->getLinkage();
  if (isAvailableExternally(linkage))
    linkage = SILLinkage::Shared;

  DEBUG(llvm::dbgs() << "  -> create specialized function " << Name << "\n");
  
  NewF = M.createFunction(
      linkage, Name,
      createOptimizedSILFunctionType(), nullptr, F->getLocation(), F->isBare(),
      F->isTransparent(), F->isFragile(), F->isThunk(), F->getClassVisibility(),
      F->getInlineStrategy(), F->getEffectsKind(), 0, F->getDebugScope(),
      F->getDeclContext());
  if (F->hasUnqualifiedOwnership()) {
    NewF->setUnqualifiedOwnership();
  }

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

  // 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->createArgument(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 = LoweredType.getFunctionInterfaceResultType();
  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->createArgument(ResultType, 0);
    SILBasicBlock *ErrorBlock = Thunk->createBasicBlock();
    SILType Error =
        SILType::getPrimitiveObjectType(FunctionTy->getErrorResult().getType());
    auto *ErrorArg = ErrorBlock->createArgument(Error, 0);
    Builder.createTryApply(Loc, FRI, LoweredType, ArrayRef<Substitution>(),
                           ThunkArgs, NormalBlock, ErrorBlock);

    Builder.setInsertionPoint(ErrorBlock);
    Builder.createThrow(Loc, ErrorArg);
    Builder.setInsertionPoint(NormalBlock);
  } else {
    ReturnValue = Builder.createApply(Loc, FRI, LoweredType, ResultType,
                                      ArrayRef<Substitution>(), 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);
}
示例#6
0
/// \brief Populate the body of the cloned closure, modifying instructions as
/// necessary. This is where we create the actual specialized BB Arguments.
void ClosureSpecCloner::populateCloned() {
  SILFunction *Cloned = getCloned();
  SILFunction *ClosureUser = CallSiteDesc.getApplyCallee();

  // Create arguments for the entry block.
  SILBasicBlock *ClosureUserEntryBB = &*ClosureUser->begin();
  SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock();

  // Remove the closure argument.
  SILArgument *ClosureArg = nullptr;
  for (size_t i = 0, e = ClosureUserEntryBB->args_size(); i != e; ++i) {
    SILArgument *Arg = ClosureUserEntryBB->getArgument(i);
    if (i == CallSiteDesc.getClosureIndex()) {
      ClosureArg = Arg;
      continue;
    }

    // Otherwise, create a new argument which copies the original argument
    SILValue MappedValue =
        ClonedEntryBB->createArgument(Arg->getType(), Arg->getDecl());
    ValueMap.insert(std::make_pair(Arg, MappedValue));
  }

  // Next we need to add in any arguments that are not captured as arguments to
  // the cloned function.
  //
  // We do not insert the new mapped arguments into the value map since there by
  // definition is nothing in the partial apply user function that references
  // such arguments. After this pass is done the only thing that will reference
  // the arguments is the partial apply that we will create.
  SILFunction *ClosedOverFun = CallSiteDesc.getClosureCallee();
  CanSILFunctionType ClosedOverFunTy = ClosedOverFun->getLoweredFunctionType();
  unsigned NumTotalParams = ClosedOverFunTy->getParameters().size();
  unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments();
  llvm::SmallVector<SILValue, 4> NewPAIArgs;
  for (auto &PInfo : ClosedOverFunTy->getParameters().slice(NumNotCaptured)) {
    SILValue MappedValue = ClonedEntryBB->createArgument(PInfo.getSILType());
    NewPAIArgs.push_back(MappedValue);
  }

  SILBuilder &Builder = getBuilder();
  Builder.setInsertionPoint(ClonedEntryBB);

  // Clone FRI and PAI, and replace usage of the removed closure argument
  // with result of cloned PAI.
  SILValue FnVal =
      Builder.createFunctionRef(CallSiteDesc.getLoc(), ClosedOverFun);
  auto *NewClosure = CallSiteDesc.createNewClosure(Builder, FnVal, NewPAIArgs);
  ValueMap.insert(std::make_pair(ClosureArg, SILValue(NewClosure)));

  BBMap.insert(std::make_pair(ClosureUserEntryBB, ClonedEntryBB));
  // Recursively visit original BBs in depth-first preorder, starting with the
  // entry block, cloning all instructions other than terminators.
  visitSILBasicBlock(ClosureUserEntryBB);

  // Now iterate over the BBs and fix up the terminators.
  for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) {
    Builder.setInsertionPoint(BI->second);
    visit(BI->first->getTerminator());
  }

  // Then insert a release in all non failure exit BBs if our partial apply was
  // guaranteed. This is b/c it was passed at +0 originally and we need to
  // balance the initial increment of the newly created closure.
  if (CallSiteDesc.isClosureGuaranteed() &&
      CallSiteDesc.closureHasRefSemanticContext()) {
    for (SILBasicBlock *BB : CallSiteDesc.getNonFailureExitBBs()) {
      SILBasicBlock *OpBB = BBMap[BB];

      TermInst *TI = OpBB->getTerminator();
      auto Loc = CleanupLocation::get(NewClosure->getLoc());

      // If we have a return, we place the release right before it so we know
      // that it will be executed at the end of the epilogue.
      if (isa<ReturnInst>(TI)) {
        Builder.setInsertionPoint(TI);
        Builder.createReleaseValue(Loc, SILValue(NewClosure),
                                   Atomicity::Atomic);
        continue;
      }

      // We use casts where findAllNonFailureExitBBs should have made sure that
      // this is true. This will ensure that the code is updated when we hit the
      // cast failure in debug builds.
      auto *Unreachable = cast<UnreachableInst>(TI);
      auto PrevIter = std::prev(SILBasicBlock::iterator(Unreachable));
      auto NoReturnApply = FullApplySite::isa(&*PrevIter);

      // We insert the release value right before the no return apply so that if
      // the partial apply is passed into the no-return function as an @owned
      // value, we will retain the partial apply before we release it and
      // potentially eliminate it.
      Builder.setInsertionPoint(NoReturnApply.getInstruction());
      Builder.createReleaseValue(Loc, SILValue(NewClosure), Atomicity::Atomic);
    }
  }
}
示例#7
0
/// Emit a store of a native error to the foreign-error slot.
static void emitStoreToForeignErrorSlot(SILGenFunction &gen,
                                        SILLocation loc,
                                        SILValue foreignErrorSlot,
                                        const BridgedErrorSource &errorSrc) {
  ASTContext &ctx = gen.getASTContext();

  // The foreign error slot has type SomePointer<SomeError?>,
  // or possibly an optional thereof.

  // If the pointer itself is optional, we need to branch based on
  // whether it's really there.
  if (SILType errorPtrObjectTy =
        foreignErrorSlot->getType().getAnyOptionalObjectType()) {
    SILBasicBlock *contBB = gen.createBasicBlock();
    SILBasicBlock *noSlotBB = gen.createBasicBlock();
    SILBasicBlock *hasSlotBB = gen.createBasicBlock();
    gen.B.createSwitchEnum(loc, foreignErrorSlot, nullptr,
                 { { ctx.getOptionalSomeDecl(), hasSlotBB },
                   { ctx.getOptionalNoneDecl(), noSlotBB } });

    // If we have the slot, emit a store to it.
    gen.B.emitBlock(hasSlotBB);
    SILValue slot = hasSlotBB->createArgument(errorPtrObjectTy);
    emitStoreToForeignErrorSlot(gen, loc, slot, errorSrc);
    gen.B.createBranch(loc, contBB);

    // Otherwise, just release the error.
    gen.B.emitBlock(noSlotBB);
    errorSrc.emitRelease(gen, loc);
    gen.B.createBranch(loc, contBB);

    // Continue.
    gen.B.emitBlock(contBB);
    return;
  }

  // Okay, break down the components of SomePointer<SomeError?>.
  // TODO: this should really be an unlowered AST type?
  CanType bridgedErrorPtrType =
    foreignErrorSlot->getType().getSwiftRValueType();

  PointerTypeKind ptrKind;
  CanType bridgedErrorProto =
    CanType(bridgedErrorPtrType->getAnyPointerElementType(ptrKind));

  FullExpr scope(gen.Cleanups, CleanupLocation::get(loc));
  WritebackScope writebacks(gen);

  // Convert the error to a bridged form.
  SILValue bridgedError = errorSrc.emitBridged(gen, loc, bridgedErrorProto);

  // Store to the "pointee" property.
  // If we can't find it, diagnose and then just don't store anything.
  VarDecl *pointeeProperty = ctx.getPointerPointeePropertyDecl(ptrKind);
  if (!pointeeProperty) {
    gen.SGM.diagnose(loc, diag::could_not_find_pointer_pointee_property,
                     bridgedErrorPtrType);
    return;
  }

  // Otherwise, do a normal assignment.
  LValue lvalue =
    gen.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot),
                           bridgedErrorPtrType, pointeeProperty,
                           AccessKind::Write,
                           AccessSemantics::Ordinary);
  RValue rvalue(gen, loc, bridgedErrorProto,
                gen.emitManagedRValueWithCleanup(bridgedError));
  gen.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue));
}
示例#8
0
void GenericCloner::populateCloned() {
  SILFunction *Cloned = getCloned();

  // Create arguments for the entry block.
  SILBasicBlock *OrigEntryBB = &*Original.begin();
  SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock();
  getBuilder().setInsertionPoint(ClonedEntryBB);

  llvm::SmallVector<AllocStackInst *, 8> AllocStacks;
  AllocStackInst *ReturnValueAddr = nullptr;

  // Create the entry basic block with the function arguments.
  auto I = OrigEntryBB->args_begin(), E = OrigEntryBB->args_end();
  int ArgIdx = 0;
  while (I != E) {
    SILArgument *OrigArg = *I;
    RegularLocation Loc((Decl *)OrigArg->getDecl());
    AllocStackInst *ASI = nullptr;
    SILType mappedType = remapType(OrigArg->getType());
    if (ReInfo.isArgConverted(ArgIdx)) {
      // We need an alloc_stack as a replacement for the indirect parameter.
      assert(mappedType.isAddress());
      mappedType = mappedType.getObjectType();
      ASI = getBuilder().createAllocStack(Loc, mappedType);
      ValueMap[OrigArg] = ASI;
      AllocStacks.push_back(ASI);
      if (ReInfo.isResultIndex(ArgIdx)) {
        // This result is converted from indirect to direct. The return inst
        // needs to load the value from the alloc_stack. See below.
        assert(!ReturnValueAddr);
        ReturnValueAddr = ASI;
      } else {
        // Store the new direct parameter to the alloc_stack.
        auto *NewArg =
            ClonedEntryBB->createArgument(mappedType, OrigArg->getDecl());
        getBuilder().createStore(Loc, NewArg, ASI,
                                 StoreOwnershipQualifier::Unqualified);

        // Try to create a new debug_value from an existing debug_value_addr.
        for (Operand *ArgUse : OrigArg->getUses()) {
          if (auto *DVAI = dyn_cast<DebugValueAddrInst>(ArgUse->getUser())) {
            getBuilder().createDebugValue(DVAI->getLoc(), NewArg,
                                          DVAI->getVarInfo());
            break;
          }
        }
      }
    } else {
      auto *NewArg =
          ClonedEntryBB->createArgument(mappedType, OrigArg->getDecl());
      ValueMap[OrigArg] = NewArg;
    }
    ++I;
    ++ArgIdx;
  }

  BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB));
  // Recursively visit original BBs in depth-first preorder, starting with the
  // entry block, cloning all instructions other than terminators.
  visitSILBasicBlock(OrigEntryBB);

  // Now iterate over the BBs and fix up the terminators.
  for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) {
    getBuilder().setInsertionPoint(BI->second);
    TermInst *OrigTermInst = BI->first->getTerminator();
    if (auto *RI = dyn_cast<ReturnInst>(OrigTermInst)) {
      SILValue ReturnValue;
      if (ReturnValueAddr) {
        // The result is converted from indirect to direct. We have to load the
        // returned value from the alloc_stack.
        ReturnValue =
            getBuilder().createLoad(ReturnValueAddr->getLoc(), ReturnValueAddr,
                                    LoadOwnershipQualifier::Unqualified);
      }
      for (AllocStackInst *ASI : reverse(AllocStacks)) {
        getBuilder().createDeallocStack(ASI->getLoc(), ASI);
      }
      if (ReturnValue) {
        getBuilder().createReturn(RI->getLoc(), ReturnValue);
        continue;
      }
    } else if (isa<ThrowInst>(OrigTermInst)) {
      for (AllocStackInst *ASI : reverse(AllocStacks)) {
        getBuilder().createDeallocStack(ASI->getLoc(), ASI);
      }
    }
    visit(BI->first->getTerminator());
  }
}