void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
                                    Expr *ret) {
  SmallVector<SILValue, 4> directResults;

  if (F.getLoweredFunctionType()->hasIndirectResults()) {
    // Indirect return of an address-only value.
    FullExpr scope(Cleanups, CleanupLocation(ret));

    // Build an initialization which recursively destructures the tuple.
    SmallVector<CleanupHandle, 4> resultCleanups;
    InitializationPtr resultInit =
      prepareIndirectResultInit(*this, ret->getType()->getCanonicalType(),
                                directResults, resultCleanups);

    // Emit the result expression into the initialization.
    emitExprInto(ret, resultInit.get());

    // Deactivate all the cleanups for the result values.
    for (auto cleanup : resultCleanups) {
      Cleanups.forwardCleanup(cleanup);
    }
  } else {
    // SILValue return.
    FullExpr scope(Cleanups, CleanupLocation(ret));
    emitRValue(ret).forwardAll(*this, directResults);
  }
  Cleanups.emitBranchAndCleanups(ReturnDest, branchLoc, directResults);
}
void StmtEmitter::visitForEachStmt(ForEachStmt *S) {
  // Emit the 'iterator' variable that we'll be using for iteration.
  LexicalScope OuterForScope(SGF.Cleanups, SGF, CleanupLocation(S));
  SGF.visitPatternBindingDecl(S->getIterator());
  
  // If we ever reach an unreachable point, stop emitting statements.
  // This will need revision if we ever add goto.
  if (!SGF.B.hasValidInsertionPoint()) return;
  
  // If generator's optional result is address-only, create a stack allocation
  // to hold the results.  This will be initialized on every entry into the loop
  // header and consumed by the loop body. On loop exit, the terminating value
  // will be in the buffer.
  auto optTy = S->getIteratorNext()->getType()->getCanonicalType();
  auto &optTL = SGF.getTypeLowering(optTy);
  SILValue nextBufOrValue;

  if (optTL.isAddressOnly())
    nextBufOrValue = SGF.emitTemporaryAllocation(S, optTL.getLoweredType());
  
  // Create a new basic block and jump into it.
  JumpDest loopDest = createJumpDest(S->getBody());
  SGF.B.emitBlock(loopDest.getBlock(), S);
  
  // Set the destinations for 'break' and 'continue'.
  JumpDest endDest = createJumpDest(S->getBody());
  SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest });

  // Advance the generator.  Use a scope to ensure that any temporary stack
  // allocations in the subexpression are immediately released.
  if (optTL.isAddressOnly()) {
    Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext()));
    auto nextInit = SGF.useBufferAsTemporary(nextBufOrValue, optTL);
    SGF.emitExprInto(S->getIteratorNext(), nextInit.get());
    nextInit->getManagedAddress().forward(SGF);
  } else {
    Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext()));
    nextBufOrValue =
      SGF.emitRValueAsSingleValue(S->getIteratorNext()).forward(SGF);
  }
  
  // Continue if the value is present.
  Condition Cond = SGF.emitCondition(
         SGF.emitDoesOptionalHaveValue(S, nextBufOrValue), S,
         /*hasFalseCode=*/false, /*invertValue=*/false);

  if (Cond.hasTrue()) {
    Cond.enterTrue(SGF);
    SGF.emitProfilerIncrement(S->getBody());
    
    // Emit the loop body.
    // The declared variable(s) for the current element are destroyed
    // at the end of each loop iteration.
    {
      Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getBody()));
      // Emit the initialization for the pattern.  If any of the bound patterns
      // fail (because this is a 'for case' pattern with a refutable pattern,
      // the code should jump to the continue block.
      InitializationPtr initLoopVars
        = SGF.emitPatternBindingInitialization(S->getPattern(), loopDest);
      ManagedValue val;

      // If we had a loadable "next" generator value, we know it is present.
      // Get the value out of the optional, and wrap it up with a cleanup so
      // that any exits out of this scope properly clean it up.
      if (optTL.isLoadable()) {
        val = SGF.emitManagedRValueWithCleanup(nextBufOrValue);
      } else {
        val = SGF.emitManagedBufferWithCleanup(nextBufOrValue);
      }
      val = SGF.emitUncheckedGetOptionalValueFrom(S, val, optTL,
                                            SGFContext(initLoopVars.get()));
      if (!val.isInContext())
        RValue(SGF, S, optTy.getAnyOptionalObjectType(), val)
          .forwardInto(SGF, S, initLoopVars.get());

      // Now that the pattern has been initialized, check any where condition.
      // If it fails, loop around as if 'continue' happened.
      if (auto *Where = S->getWhere()) {
        auto cond = SGF.emitCondition(Where, /*hasFalse*/false, /*invert*/true);
        // If self is null, branch to the epilog.
        cond.enterTrue(SGF);
        SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, { });
        cond.exitTrue(SGF);
        cond.complete(SGF);
      }

      visit(S->getBody());
    }
    
    // Loop back to the header.
    if (SGF.B.hasValidInsertionPoint()) {
      // Associate the loop body's closing brace with this branch.
      RegularLocation L(S->getBody());
      L.pointToEnd();
      SGF.B.createBranch(L, loopDest.getBlock());
    }
    Cond.exitTrue(SGF);
  }
  
  // Complete the conditional execution.
  Cond.complete(SGF);
  
  emitOrDeleteBlock(SGF, endDest, S);
  SGF.BreakContinueDestStack.pop_back();
  
  // We do not need to destroy the value in the 'nextBuf' slot here, because
  // either the 'for' loop finished naturally and the buffer contains '.None',
  // or we exited by 'break' and the value in the buffer was consumed.
}
Esempio n. 3
0
void StmtEmitter::visitForEachStmt(ForEachStmt *S) {
  // Emit the 'iterator' variable that we'll be using for iteration.
  LexicalScope OuterForScope(SGF, CleanupLocation(S));
  SGF.visitPatternBindingDecl(S->getIterator());

  // If we ever reach an unreachable point, stop emitting statements.
  // This will need revision if we ever add goto.
  if (!SGF.B.hasValidInsertionPoint()) return;
  
  // If generator's optional result is address-only, create a stack allocation
  // to hold the results.  This will be initialized on every entry into the loop
  // header and consumed by the loop body. On loop exit, the terminating value
  // will be in the buffer.
  auto optTy = S->getIteratorNext()->getType()->getCanonicalType();
  auto &optTL = SGF.getTypeLowering(optTy);
  SILValue addrOnlyBuf;
  ManagedValue nextBufOrValue;

  if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses())
    addrOnlyBuf = SGF.emitTemporaryAllocation(S, optTL.getLoweredType());

  // Create a new basic block and jump into it.
  JumpDest loopDest = createJumpDest(S->getBody());
  SGF.B.emitBlock(loopDest.getBlock(), S);

  // Set the destinations for 'break' and 'continue'.
  JumpDest endDest = createJumpDest(S->getBody());
  SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest });

  // Then emit the loop destination block.
  //
  // Advance the generator.  Use a scope to ensure that any temporary stack
  // allocations in the subexpression are immediately released.
  if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
    // Create the initialization outside of the innerForScope so that the
    // innerForScope doesn't clean it up.
    auto nextInit = SGF.useBufferAsTemporary(addrOnlyBuf, optTL);
    {
      Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext()));
      SGF.emitExprInto(S->getIteratorNext(), nextInit.get());
    }
    nextBufOrValue = nextInit->getManagedAddress();

  } else {
    Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext()));
    nextBufOrValue = innerForScope.popPreservingValue(
        SGF.emitRValueAsSingleValue(S->getIteratorNext()));
  }

  SILBasicBlock *failExitingBlock = createBasicBlock();
  SwitchEnumBuilder switchEnumBuilder(SGF.B, S, nextBufOrValue);

  switchEnumBuilder.addOptionalSomeCase(
      createBasicBlock(), loopDest.getBlock(),
      [&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) {
        SGF.emitProfilerIncrement(S->getBody());

        // Emit the loop body.
        // The declared variable(s) for the current element are destroyed
        // at the end of each loop iteration.
        {
          Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getBody()));
          // Emit the initialization for the pattern.  If any of the bound
          // patterns
          // fail (because this is a 'for case' pattern with a refutable
          // pattern,
          // the code should jump to the continue block.
          InitializationPtr initLoopVars =
              SGF.emitPatternBindingInitialization(S->getPattern(), loopDest);

          // If we had a loadable "next" generator value, we know it is present.
          // Get the value out of the optional, and wrap it up with a cleanup so
          // that any exits out of this scope properly clean it up.
          //
          // *NOTE* If we do not have an address only value, then inputValue is
          // *already properly unwrapped.
          if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
            inputValue = SGF.emitUncheckedGetOptionalValueFrom(
                S, inputValue, optTL, SGFContext(initLoopVars.get()));
          }

          if (!inputValue.isInContext())
            RValue(SGF, S, optTy.getOptionalObjectType(), inputValue)
                .forwardInto(SGF, S, initLoopVars.get());

          // Now that the pattern has been initialized, check any where
          // condition.
          // If it fails, loop around as if 'continue' happened.
          if (auto *Where = S->getWhere()) {
            auto cond =
                SGF.emitCondition(Where, /*hasFalse*/ false, /*invert*/ true);
            // If self is null, branch to the epilog.
            cond.enterTrue(SGF);
            SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, {});
            cond.exitTrue(SGF);
            cond.complete(SGF);
          }

          visit(S->getBody());
        }

        // If we emitted an unreachable in the body, we will not have a valid
        // insertion point. Just return early.
        if (!SGF.B.hasValidInsertionPoint()) {
          scope.unreachableExit();
          return;
        }

        // Otherwise, associate the loop body's closing brace with this branch.
        RegularLocation L(S->getBody());
        L.pointToEnd();
        scope.exitAndBranch(L);
      },
      SGF.loadProfilerCount(S->getBody()));

  // We add loop fail block, just to be defensive about intermediate
  // transformations performing cleanups at scope.exit(). We still jump to the
  // contBlock.
  switchEnumBuilder.addOptionalNoneCase(
      createBasicBlock(), failExitingBlock,
      [&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) {
        assert(!inputValue && "None should not be passed an argument!");
        scope.exitAndBranch(S);
      },
      SGF.loadProfilerCount(S));

  std::move(switchEnumBuilder).emit();

  SGF.B.emitBlock(failExitingBlock);
  emitOrDeleteBlock(SGF, endDest, S);
  SGF.BreakContinueDestStack.pop_back();
}