예제 #1
0
파일: SILGenStmt.cpp 프로젝트: ahti/swift
void StmtEmitter::visitRepeatWhileStmt(RepeatWhileStmt *S) {
  // Create a new basic block and jump into it.
  SILBasicBlock *loopBB = createBasicBlock();
  SGF.B.emitBlock(loopBB, S);
  
  // Set the destinations for 'break' and 'continue'
  JumpDest endDest = createJumpDest(S->getBody());
  JumpDest condDest = createJumpDest(S->getBody());
  SGF.BreakContinueDestStack.push_back({ S, endDest, condDest });

  // Emit the body, which is always evaluated the first time around.
  SGF.emitProfilerIncrement(S->getBody());
  visit(S->getBody());

  // Let's not differ from C99 6.8.5.2: "The evaluation of the controlling
  // expression takes place after each execution of the loop body."
  emitOrDeleteBlock(SGF, condDest, S);

  if (SGF.B.hasValidInsertionPoint()) {
    // Evaluate the condition with the false edge leading directly
    // to the continuation block.
    auto NumTrueTaken = SGF.loadProfilerCount(S->getBody());
    auto NumFalseTaken = SGF.loadProfilerCount(S);
    Condition Cond = SGF.emitCondition(S->getCond(), /*hasFalseCode*/ false,
                                       /*invertValue*/ false, /*contArgs*/ {},
                                       NumTrueTaken, NumFalseTaken);

    Cond.enterTrue(SGF);
    if (SGF.B.hasValidInsertionPoint()) {
      SGF.B.createBranch(S->getCond(), loopBB);
    }
    
    Cond.exitTrue(SGF);
    // Complete the conditional execution.
    Cond.complete(SGF);
  }
  
  emitOrDeleteBlock(SGF, endDest, S);
  SGF.BreakContinueDestStack.pop_back();
}
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.
}
void StmtEmitter::visitForStmt(ForStmt *S) {
  // Enter a new scope.
  LexicalScope ForScope(SGF.Cleanups, SGF, CleanupLocation(S));
  
  // Emit any local 'var' variables declared in the initializer.
  for (auto D : S->getInitializerVarDecls()) {
    SGF.visit(D);
  }
  
  if (auto *Initializer = S->getInitializer().getPtrOrNull()) {
    SGF.emitIgnoredExpr(Initializer);
  }
  
  // If we ever reach an unreachable point, stop emitting statements.
  // This will need revision if we ever add goto.
  if (!SGF.B.hasValidInsertionPoint()) return;
  
  // Create a new basic block and jump into it.
  SILBasicBlock *loopBB = createBasicBlock();
  SGF.B.emitBlock(loopBB, S);

  JumpDest endDest = createJumpDest(S->getBody());
  
  // Evaluate the condition with the false edge leading directly
  // to the continuation block.
  Condition Cond = S->getCond().isNonNull() ?
    SGF.emitCondition(S->getCond().get(), /*hasFalseCode*/ false) :
    Condition(loopBB, 0, 0, S); // Infinite loop.
  
  // If there's a true edge, emit the body in it.
  if (Cond.hasTrue()) {
    Cond.enterTrue(SGF);
    SGF.emitProfilerIncrement(S->getBody());

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

    visit(S->getBody());

    SGF.BreakContinueDestStack.pop_back();
    
    emitOrDeleteBlock(SGF, incDest, S);
    
    if (SGF.B.hasValidInsertionPoint() && S->getIncrement().isNonNull()) {
      FullExpr Scope(SGF.Cleanups, CleanupLocation(S->getIncrement().get()));
      // Ignore the result of the increment expression.
      SGF.emitIgnoredExpr(S->getIncrement().get());
    }

    if (SGF.B.hasValidInsertionPoint()) {
      // Associate the loop body's closing brace with this branch.
      RegularLocation L(S->getBody());
      L.pointToEnd();
      SGF.B.createBranch(L, loopBB);
    }
    Cond.exitTrue(SGF);
  }
  
  // Complete the conditional execution.
  Cond.complete(SGF);
  
  emitOrDeleteBlock(SGF, endDest, S);
}