<commit_before>//===--- PrunedLiveness.cpp - Compute liveness from selected uses ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/PrunedLiveness.h"
#include "swift/SIL/BasicBlockDatastructures.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/OwnershipUtils.h"

using namespace swift;

/// Mark blocks live during a reverse CFG traversal from one specific block
/// containing a user.
void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB) {
  // If we are visiting this block, then it is not already LiveOut. Mark it
  // LiveWithin to indicate a liveness boundary within the block.
  markBlockLive(userBB, LiveWithin);

  SmallVector<SILBasicBlock *, 8> predBBWorklist({userBB});
  while (!predBBWorklist.empty()) {
    SILBasicBlock *bb = predBBWorklist.pop_back_val();

    // The popped `bb` is live; now mark all its predecessors LiveOut.
    //
    // Traversal terminates at any previously visited block, including the
    // blocks initialized as definition blocks.
    for (auto *predBB : bb->getPredecessorBlocks()) {
      switch (getBlockLiveness(predBB)) {
      case Dead:
        predBBWorklist.push_back(predBB);
        LLVM_FALLTHROUGH;
      case LiveWithin:
        markBlockLive(predBB, LiveOut);
        break;
      case LiveOut:
        break;
      }
    }
  }
}

/// Update the current def's liveness based on one specific use instruction.
///
/// Return the updated liveness of the \p use block (LiveOut or LiveWithin).
///
/// Terminators are not live out of the block.
PrunedLiveBlocks::IsLive PrunedLiveBlocks::updateForUse(SILInstruction *user) {
  SWIFT_ASSERT_ONLY(seenUse = true);

  auto *bb = user->getParent();
  switch (getBlockLiveness(bb)) {
  case LiveOut:
    return LiveOut;
  case LiveWithin:
    return LiveWithin;
  case Dead: {
    // This use block has not yet been marked live. Mark it and its predecessor
    // blocks live.
    computeUseBlockLiveness(bb);
    return getBlockLiveness(bb);
  }
  }
  llvm_unreachable("covered switch");
}

//===----------------------------------------------------------------------===//
//                            MARK: PrunedLiveness
//===----------------------------------------------------------------------===//

void PrunedLiveness::updateForUse(SILInstruction *user, bool lifetimeEnding) {
  auto useBlockLive = liveBlocks.updateForUse(user);
  // Record all uses of blocks on the liveness boundary. For blocks marked
  // LiveWithin, the boundary is considered to be the last use in the block.
  if (!lifetimeEnding && useBlockLive == PrunedLiveBlocks::LiveOut) {
    return;
  }
  // Note that a user may use the current value from multiple operands. If any
  // of the uses are non-lifetime-ending, then we must consider the user
  // itself non-lifetime-ending; it cannot be a final destroy point because
  // the value of the non-lifetime-ending operand must be kept alive until the
  // end of the user. Consider a call that takes the same value using
  // different conventions:
  //
  //   apply %f(%val, %val) : $(@guaranteed, @owned) -> ()
  //
  // This call is not considered the end of %val's lifetime. The @owned
  // argument must be copied.
  auto iterAndSuccess = users.try_emplace(user, lifetimeEnding);
  if (!iterAndSuccess.second)
    iterAndSuccess.first->second &= lifetimeEnding;
}

bool PrunedLiveness::updateForBorrowingOperand(Operand *op) {
  assert(op->getOperandOwnership() == OperandOwnership::Borrow);

  // A nested borrow scope is considered a use-point at each scope ending
  // instruction.
  //
  // TODO: Handle reborrowed copies by considering the extended borrow
  // scope. Temporarily bail-out on reborrows because we can't handle uses
  // that aren't dominated by currentDef.
  if (!BorrowingOperand(op).visitScopeEndingUses([this](Operand *end) {
        if (end->getOperandOwnership() == OperandOwnership::Reborrow) {
          return false;
        }
        updateForUse(end->getUser(), /*lifetimeEnding*/ false);
        return true;
      })) {
    return false;
  }
  return true;
}

void PrunedLiveness::extendAcrossLiveness(PrunedLiveness &otherLivesness) {
  // update this liveness for all the interesting users in otherLivesness.
  for (std::pair<SILInstruction *, bool> userAndEnd : otherLivesness.users) {
    updateForUse(userAndEnd.first, userAndEnd.second);
  }
}

bool PrunedLiveness::isWithinBoundary(SILInstruction *inst) const {
  SILBasicBlock *block = inst->getParent();
  switch (getBlockLiveness(block)) {
  case PrunedLiveBlocks::Dead:
    return false;
  case PrunedLiveBlocks::LiveWithin:
    break;
  case PrunedLiveBlocks::LiveOut:
    return true;
  }
  // The boundary is within this block. This instruction is before the boundary
  // iff any interesting uses occur after it.
  for (SILInstruction &inst :
         make_range(std::next(inst->getIterator()), block->end())) {
    switch (isInterestingUser(&inst)) {
    case PrunedLiveness::NonUser:
      break;
    case PrunedLiveness::NonLifetimeEndingUse:
    case PrunedLiveness::LifetimeEndingUse:
      return true;
    }
  }
  return false;
}

bool PrunedLiveness::areUsesWithinBoundary(ArrayRef<Operand *> uses,
                                           DeadEndBlocks &deadEndBlocks) const {
  for (auto *use : uses) {
    auto *user = use->getUser();
    if (!isWithinBoundary(user) && !deadEndBlocks.isDeadEnd(user->getParent()))
      return false;
  }
  return true;
}

// An SSA def meets all the criteria for pruned liveness--def dominates all uses
// with no holes in the liverange. The lifetime-ending uses are also
// recorded--destroy_value or end_borrow. However destroy_values may not
// jointly-post dominate if dead-end blocks are present.
void PrunedLiveness::computeSSALiveness(SILValue def) {
  initializeDefBlock(def->getParentBlock());
  for (Operand *use : def->getUses()) {
    updateForUse(use->getUser(), use->isLifetimeEnding());
  }
}

void PrunedLivenessBoundary::visitInsertionPoints(
    llvm::function_ref<void(SILBasicBlock::iterator insertPt)> visitor,
    DeadEndBlocks *deBlocks) {
  for (SILInstruction *user : lastUsers) {
    if (!isa<TermInst>(user)) {
      visitor(std::next(user->getIterator()));
      continue;
    }
    auto *predBB = user->getParent();
    for (SILBasicBlock *succ : predBB->getSuccessors()) {
      if (deBlocks && deBlocks->isDeadEnd(succ))
        continue;

      assert(succ->getSinglePredecessorBlock() == predBB);
      visitor(succ->begin());
    }
  }
  for (SILBasicBlock *edge : boundaryEdges) {
    if (deBlocks && deBlocks->isDeadEnd(edge))
      continue;

    visitor(edge->begin());
  }
}

// Use \p liveness to find the last use in \p bb and add it to \p
// boundary.lastUsers.
static void findLastUserInBlock(SILBasicBlock *bb,
                                PrunedLivenessBoundary &boundary,
                                const PrunedLiveness &liveness) {
  for (auto instIter = bb->rbegin(), endIter = bb->rend(); instIter != endIter;
       ++instIter) {
    auto *inst = &*instIter;
    if (liveness.isInterestingUser(inst) == PrunedLiveness::NonUser)
      continue;

    boundary.lastUsers.push_back(inst);
  }
  llvm_unreachable("No user in LiveWithin block");
}

void PrunedLivenessBoundary::compute(const PrunedLiveness &liveness) {
  for (SILBasicBlock *bb : liveness.getDiscoveredBlocks()) {
    // Process each block that has not been visited and is not LiveOut.
    switch (liveness.getBlockLiveness(bb)) {
    case PrunedLiveBlocks::LiveOut:
      for (SILBasicBlock *succBB : bb->getSuccessors()) {
        if (liveness.getBlockLiveness(succBB) == PrunedLiveBlocks::Dead) {
          boundaryEdges.push_back(succBB);
        }
      }
      break;
    case PrunedLiveBlocks::LiveWithin: {
      // The liveness boundary is inside this block. Insert a final destroy
      // inside the block if it doesn't already have one.
      findLastUserInBlock(bb, *this, liveness);
      break;
    }
    case PrunedLiveBlocks::Dead:
      llvm_unreachable("All discovered blocks must be live");
    }
  }
}

void PrunedLivenessBoundary::compute(const PrunedLiveness &liveness,
                                     ArrayRef<SILBasicBlock *> postDomBlocks) {
  if (postDomBlocks.empty())
    return; // all paths must be dead-ends or infinite loops

  BasicBlockWorklist blockWorklist(postDomBlocks[0]->getParent());

  // Visit each post-dominating block as the starting point for a
  // backward CFG traversal.
  for (auto *bb : postDomBlocks) {
    blockWorklist.push(bb);
  }
  while (auto *bb = blockWorklist.pop()) {
    // Process each block that has not been visited and is not LiveOut.
    switch (liveness.getBlockLiveness(bb)) {
    case PrunedLiveBlocks::LiveOut:
      // A lifetimeEndBlock may be determined to be LiveOut after analyzing the
      // extended liveness. It is irrelevent for finding the boundary.
      break;
    case PrunedLiveBlocks::LiveWithin: {
      // The liveness boundary is inside this block. Insert a final destroy
      // inside the block if it doesn't already have one.
      findLastUserInBlock(bb, *this, liveness);
      break;
    }
    case PrunedLiveBlocks::Dead:
      // Continue searching upward to find the pruned liveness boundary.
      for (auto *predBB : bb->getPredecessorBlocks()) {
        if (liveness.getBlockLiveness(predBB) == PrunedLiveBlocks::LiveOut) {
          boundaryEdges.push_back(bb);
        } else {
          blockWorklist.pushIfNotVisited(predBB);
        }
      }
      break;
    }
  }
}
<commit_msg>Fix an obvious bug in findLastUserInBlock.<commit_after>//===--- PrunedLiveness.cpp - Compute liveness from selected uses ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/PrunedLiveness.h"
#include "swift/SIL/BasicBlockDatastructures.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/OwnershipUtils.h"

using namespace swift;

/// Mark blocks live during a reverse CFG traversal from one specific block
/// containing a user.
void PrunedLiveBlocks::computeUseBlockLiveness(SILBasicBlock *userBB) {
  // If we are visiting this block, then it is not already LiveOut. Mark it
  // LiveWithin to indicate a liveness boundary within the block.
  markBlockLive(userBB, LiveWithin);

  SmallVector<SILBasicBlock *, 8> predBBWorklist({userBB});
  while (!predBBWorklist.empty()) {
    SILBasicBlock *bb = predBBWorklist.pop_back_val();

    // The popped `bb` is live; now mark all its predecessors LiveOut.
    //
    // Traversal terminates at any previously visited block, including the
    // blocks initialized as definition blocks.
    for (auto *predBB : bb->getPredecessorBlocks()) {
      switch (getBlockLiveness(predBB)) {
      case Dead:
        predBBWorklist.push_back(predBB);
        LLVM_FALLTHROUGH;
      case LiveWithin:
        markBlockLive(predBB, LiveOut);
        break;
      case LiveOut:
        break;
      }
    }
  }
}

/// Update the current def's liveness based on one specific use instruction.
///
/// Return the updated liveness of the \p use block (LiveOut or LiveWithin).
///
/// Terminators are not live out of the block.
PrunedLiveBlocks::IsLive PrunedLiveBlocks::updateForUse(SILInstruction *user) {
  SWIFT_ASSERT_ONLY(seenUse = true);

  auto *bb = user->getParent();
  switch (getBlockLiveness(bb)) {
  case LiveOut:
    return LiveOut;
  case LiveWithin:
    return LiveWithin;
  case Dead: {
    // This use block has not yet been marked live. Mark it and its predecessor
    // blocks live.
    computeUseBlockLiveness(bb);
    return getBlockLiveness(bb);
  }
  }
  llvm_unreachable("covered switch");
}

//===----------------------------------------------------------------------===//
//                            MARK: PrunedLiveness
//===----------------------------------------------------------------------===//

void PrunedLiveness::updateForUse(SILInstruction *user, bool lifetimeEnding) {
  auto useBlockLive = liveBlocks.updateForUse(user);
  // Record all uses of blocks on the liveness boundary. For blocks marked
  // LiveWithin, the boundary is considered to be the last use in the block.
  if (!lifetimeEnding && useBlockLive == PrunedLiveBlocks::LiveOut) {
    return;
  }
  // Note that a user may use the current value from multiple operands. If any
  // of the uses are non-lifetime-ending, then we must consider the user
  // itself non-lifetime-ending; it cannot be a final destroy point because
  // the value of the non-lifetime-ending operand must be kept alive until the
  // end of the user. Consider a call that takes the same value using
  // different conventions:
  //
  //   apply %f(%val, %val) : $(@guaranteed, @owned) -> ()
  //
  // This call is not considered the end of %val's lifetime. The @owned
  // argument must be copied.
  auto iterAndSuccess = users.try_emplace(user, lifetimeEnding);
  if (!iterAndSuccess.second)
    iterAndSuccess.first->second &= lifetimeEnding;
}

bool PrunedLiveness::updateForBorrowingOperand(Operand *op) {
  assert(op->getOperandOwnership() == OperandOwnership::Borrow);

  // A nested borrow scope is considered a use-point at each scope ending
  // instruction.
  //
  // TODO: Handle reborrowed copies by considering the extended borrow
  // scope. Temporarily bail-out on reborrows because we can't handle uses
  // that aren't dominated by currentDef.
  if (!BorrowingOperand(op).visitScopeEndingUses([this](Operand *end) {
        if (end->getOperandOwnership() == OperandOwnership::Reborrow) {
          return false;
        }
        updateForUse(end->getUser(), /*lifetimeEnding*/ false);
        return true;
      })) {
    return false;
  }
  return true;
}

void PrunedLiveness::extendAcrossLiveness(PrunedLiveness &otherLivesness) {
  // update this liveness for all the interesting users in otherLivesness.
  for (std::pair<SILInstruction *, bool> userAndEnd : otherLivesness.users) {
    updateForUse(userAndEnd.first, userAndEnd.second);
  }
}

bool PrunedLiveness::isWithinBoundary(SILInstruction *inst) const {
  SILBasicBlock *block = inst->getParent();
  switch (getBlockLiveness(block)) {
  case PrunedLiveBlocks::Dead:
    return false;
  case PrunedLiveBlocks::LiveWithin:
    break;
  case PrunedLiveBlocks::LiveOut:
    return true;
  }
  // The boundary is within this block. This instruction is before the boundary
  // iff any interesting uses occur after it.
  for (SILInstruction &inst :
         make_range(std::next(inst->getIterator()), block->end())) {
    switch (isInterestingUser(&inst)) {
    case PrunedLiveness::NonUser:
      break;
    case PrunedLiveness::NonLifetimeEndingUse:
    case PrunedLiveness::LifetimeEndingUse:
      return true;
    }
  }
  return false;
}

bool PrunedLiveness::areUsesWithinBoundary(ArrayRef<Operand *> uses,
                                           DeadEndBlocks &deadEndBlocks) const {
  for (auto *use : uses) {
    auto *user = use->getUser();
    if (!isWithinBoundary(user) && !deadEndBlocks.isDeadEnd(user->getParent()))
      return false;
  }
  return true;
}

// An SSA def meets all the criteria for pruned liveness--def dominates all uses
// with no holes in the liverange. The lifetime-ending uses are also
// recorded--destroy_value or end_borrow. However destroy_values may not
// jointly-post dominate if dead-end blocks are present.
void PrunedLiveness::computeSSALiveness(SILValue def) {
  initializeDefBlock(def->getParentBlock());
  for (Operand *use : def->getUses()) {
    updateForUse(use->getUser(), use->isLifetimeEnding());
  }
}

void PrunedLivenessBoundary::visitInsertionPoints(
    llvm::function_ref<void(SILBasicBlock::iterator insertPt)> visitor,
    DeadEndBlocks *deBlocks) {
  for (SILInstruction *user : lastUsers) {
    if (!isa<TermInst>(user)) {
      visitor(std::next(user->getIterator()));
      continue;
    }
    auto *predBB = user->getParent();
    for (SILBasicBlock *succ : predBB->getSuccessors()) {
      if (deBlocks && deBlocks->isDeadEnd(succ))
        continue;

      assert(succ->getSinglePredecessorBlock() == predBB);
      visitor(succ->begin());
    }
  }
  for (SILBasicBlock *edge : boundaryEdges) {
    if (deBlocks && deBlocks->isDeadEnd(edge))
      continue;

    visitor(edge->begin());
  }
}

// Use \p liveness to find the last use in \p bb and add it to \p
// boundary.lastUsers.
static void findLastUserInBlock(SILBasicBlock *bb,
                                PrunedLivenessBoundary &boundary,
                                const PrunedLiveness &liveness) {
  for (auto instIter = bb->rbegin(), endIter = bb->rend(); instIter != endIter;
       ++instIter) {
    auto *inst = &*instIter;
    if (liveness.isInterestingUser(inst) == PrunedLiveness::NonUser)
      continue;

    boundary.lastUsers.push_back(inst);
    return;
  }
  llvm_unreachable("No user in LiveWithin block");
}

void PrunedLivenessBoundary::compute(const PrunedLiveness &liveness) {
  for (SILBasicBlock *bb : liveness.getDiscoveredBlocks()) {
    // Process each block that has not been visited and is not LiveOut.
    switch (liveness.getBlockLiveness(bb)) {
    case PrunedLiveBlocks::LiveOut:
      for (SILBasicBlock *succBB : bb->getSuccessors()) {
        if (liveness.getBlockLiveness(succBB) == PrunedLiveBlocks::Dead) {
          boundaryEdges.push_back(succBB);
        }
      }
      break;
    case PrunedLiveBlocks::LiveWithin: {
      // The liveness boundary is inside this block. Insert a final destroy
      // inside the block if it doesn't already have one.
      findLastUserInBlock(bb, *this, liveness);
      break;
    }
    case PrunedLiveBlocks::Dead:
      llvm_unreachable("All discovered blocks must be live");
    }
  }
}

void PrunedLivenessBoundary::compute(const PrunedLiveness &liveness,
                                     ArrayRef<SILBasicBlock *> postDomBlocks) {
  if (postDomBlocks.empty())
    return; // all paths must be dead-ends or infinite loops

  BasicBlockWorklist blockWorklist(postDomBlocks[0]->getParent());

  // Visit each post-dominating block as the starting point for a
  // backward CFG traversal.
  for (auto *bb : postDomBlocks) {
    blockWorklist.push(bb);
  }
  while (auto *bb = blockWorklist.pop()) {
    // Process each block that has not been visited and is not LiveOut.
    switch (liveness.getBlockLiveness(bb)) {
    case PrunedLiveBlocks::LiveOut:
      // A lifetimeEndBlock may be determined to be LiveOut after analyzing the
      // extended liveness. It is irrelevent for finding the boundary.
      break;
    case PrunedLiveBlocks::LiveWithin: {
      // The liveness boundary is inside this block. Insert a final destroy
      // inside the block if it doesn't already have one.
      findLastUserInBlock(bb, *this, liveness);
      break;
    }
    case PrunedLiveBlocks::Dead:
      // Continue searching upward to find the pruned liveness boundary.
      for (auto *predBB : bb->getPredecessorBlocks()) {
        if (liveness.getBlockLiveness(predBB) == PrunedLiveBlocks::LiveOut) {
          boundaryEdges.push_back(bb);
        } else {
          blockWorklist.pushIfNotVisited(predBB);
        }
      }
      break;
    }
  }
}
<|endoftext|>


<commit_before>//===--- PlaygroundTransform.cpp - Playground Transform -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the playground transform for Swift.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Types.h"
#include "swift/Sema/CodeCompletionTypeChecking.h"
#include "swift/Subsystems.h"

using namespace swift;

//===----------------------------------------------------------------------===//
// performPlaygroundTransform
//===----------------------------------------------------------------------===//

class Instrumenter {
private:
  ASTContext &Context;
  DeclContext *TypeCheckDC;
public:
  Instrumenter (ASTContext &C, DeclContext *DC) :
    Context(C), TypeCheckDC(DC) { }

  Stmt *transformStmt(Stmt *S) {
    switch (S->getKind()) {
    default:
      return S;
    case StmtKind::Brace:
      return transformBraceStmt(llvm::cast<BraceStmt>(S));
    case StmtKind::If:
      return transformIfStmt(llvm::cast<IfStmt>(S));
    }
  }

  // transform*() return their input if it's unmodified,
  // or a modified copy of their input otherwise.
  IfStmt *transformIfStmt(IfStmt *IS) {
    if (Stmt *TS = IS->getThenStmt()) {
      Stmt *NTS = transformStmt(TS);
      if (NTS != TS) {
        IS->setThenStmt(NTS);
      }
    }

    if (Stmt *ES = IS->getElseStmt()) {
      Stmt *NES = transformStmt(ES);
      if (NES != ES) {
        IS->setElseStmt(NES);
      }
    }

    return IS;
  }

  BraceStmt *transformBraceStmt(BraceStmt *BS) {
    llvm::ArrayRef<ASTNode> OriginalElements = BS->getElements();
    typedef llvm::SmallVector<swift::ASTNode, 3> ElementVector;
    ElementVector Elements(OriginalElements.begin(),
                           OriginalElements.end());

    bool Modified = false;

    for (size_t EI = 0;
         EI != Elements.size();
         ++EI) {
      swift::ASTNode &Element = Elements[EI];
      if (Expr *E = Element.dyn_cast<Expr*>()) {
        if (AssignExpr *AE = llvm::dyn_cast<AssignExpr>(E)) {
          Expr *Log = logAssignExpr(AE);
          if (Log) {
            Modified = true;
            Elements.insert(Elements.begin() + (EI + 1), Log);
            ++EI;
          }
        }
      } else if (Stmt *S = Element.dyn_cast<Stmt*>()) {
        Stmt *NS = transformStmt(S);
        if (NS != S) {
          Modified = true;
          Elements[EI] = NS;
        }
      } else if (Decl *D = Element.dyn_cast<Decl*>()) {
        (void)D;
      }
    }

    if (Modified) {
      return swift::BraceStmt::create(Context, BS->getLBraceLoc(),
                                      Context.AllocateCopy(Elements),
                                      BS->getRBraceLoc());
    } else {
      return BS;
    }
  }

  // log*() functions return a newly-created log expression to be inserted
  // after the expression they're looking at.
  Expr *logAssignExpr(AssignExpr *AE) {
    Expr *Dest = AE->getDest();
    if (DeclRefExpr *DRE = llvm::dyn_cast<DeclRefExpr>(Dest)) {
      return buildLoggerCall(DRE->getDecl());
    }
    return nullptr;
  }

  Expr *buildLoggerCall(ValueDecl *VD) {
    Expr *Header = new (Context) StringLiteralExpr("", SourceRange());
    Header->setImplicit(true);

    Expr *MaxChildren = new (Context) IntegerLiteralExpr("0", SourceLoc(),
                                                         true);

    Expr *MaxDepth = new (Context) IntegerLiteralExpr("0", SourceLoc(),
                                                      true);

    Expr *ArgExprs[] = {
        new (Context) DeclRefExpr(ConcreteDeclRef(VD),
                                  SourceLoc(),
                                  true, // implicit
                                  false, // uses direct property access
                                  Type()),
        Header,
        MaxChildren,
        MaxDepth
      };

    TupleExpr *Args = new (Context) TupleExpr(SourceLoc(),
                                              Context.AllocateCopy(ArgExprs),
                                              (Identifier*)nullptr,
                                              SourceLoc(),
                                              false, // hasTrailingClosure
                                              true, // implicit
                                              Type());

    UnresolvedDeclRefExpr *LoggerRef =
      new (Context) UnresolvedDeclRefExpr(
        Context.getIdentifier("playground_log"),
        DeclRefKind::Ordinary,
        SourceLoc());
    LoggerRef->setImplicit(true);

    Expr *Call = new (Context) CallExpr(LoggerRef, Args, true, Type());

    if (!typeCheckCompletionContextExpr(Context, TypeCheckDC, Call)) {
      return nullptr;
    }

    return Call;
  }
};

void swift::performPlaygroundTransform(SourceFile &SF) {
  class ExpressionFinder : public ASTWalker {
    FuncDecl *WrappedDecl = nullptr;
    FuncDecl *ExpressionDecl = nullptr;
    StringRef WrappedName = "__lldb_wrapped_expr";
    StringRef ExpressionName = "__lldb_expr";
  public:
    virtual bool walkToDeclPre(Decl *D) {
      if (FuncDecl *FD = llvm::dyn_cast<FuncDecl>(D)) {
        StringRef FuncName = FD->getName().str();
        if (!FuncName.endswith(WrappedName)) {
          WrappedDecl = FD;
          return false;
        } else if (!FuncName.endswith(ExpressionName)) {
          ExpressionDecl = FD;
          return false;
        }
      }
      return true;
    }
    FuncDecl *getFunctionToTransform() {
      return WrappedDecl ? WrappedDecl : ExpressionDecl;
    }
  };

  ExpressionFinder EF;
  for (Decl* D : SF.Decls) {
    D->walk(EF);
  }

  if (FuncDecl *FuncToTransform = EF.getFunctionToTransform()) {
    if (BraceStmt *Body = FuncToTransform->getBody()) {
      ASTContext &Context(SF.getASTContext());

      Module *LoggerModule = Context.getModule(
        std::make_pair(Context.getIdentifier("PlaygroundLoggerLibrary"),
                       SourceLoc()));

      if (LoggerModule)
      {
        SmallVector<ValueDecl*, 1> LoggerDecls;

        LoggerModule->lookupValue(Module::AccessPathTy(),
                                  Context.getIdentifier("playground_log"),
                                  NLKind::UnqualifiedLookup,
                                  LoggerDecls);

        if (LoggerDecls.size() == 1) {
          Instrumenter I(Context, FuncToTransform);
          BraceStmt *NewBody = I.transformBraceStmt(Body);
          if (NewBody != Body) {
            FuncToTransform->setBody(NewBody);
          }
        }
      }
    }
  }
}
<commit_msg>Modified the playground transform to<commit_after>//===--- PlaygroundTransform.cpp - Playground Transform -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the playground transform for Swift.
//
//===----------------------------------------------------------------------===//

#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Types.h"
#include "swift/Sema/CodeCompletionTypeChecking.h"
#include "swift/Subsystems.h"

using namespace swift;

//===----------------------------------------------------------------------===//
// performPlaygroundTransform
//===----------------------------------------------------------------------===//

class Instrumenter {
private:
  ASTContext &Context;
  DeclContext *TypeCheckDC;
public:
  Instrumenter (ASTContext &C, DeclContext *DC) :
    Context(C), TypeCheckDC(DC) { }

  Stmt *transformStmt(Stmt *S) {
    switch (S->getKind()) {
    default:
      return S;
    case StmtKind::Brace:
      return transformBraceStmt(llvm::cast<BraceStmt>(S));
    case StmtKind::If:
      return transformIfStmt(llvm::cast<IfStmt>(S));
    }
  }

  // transform*() return their input if it's unmodified,
  // or a modified copy of their input otherwise.
  IfStmt *transformIfStmt(IfStmt *IS) {
    if (Stmt *TS = IS->getThenStmt()) {
      Stmt *NTS = transformStmt(TS);
      if (NTS != TS) {
        IS->setThenStmt(NTS);
      }
    }

    if (Stmt *ES = IS->getElseStmt()) {
      Stmt *NES = transformStmt(ES);
      if (NES != ES) {
        IS->setElseStmt(NES);
      }
    }

    return IS;
  }

  BraceStmt *transformBraceStmt(BraceStmt *BS) {
    llvm::ArrayRef<ASTNode> OriginalElements = BS->getElements();
    typedef llvm::SmallVector<swift::ASTNode, 3> ElementVector;
    ElementVector Elements(OriginalElements.begin(),
                           OriginalElements.end());

    bool Modified = false;

    for (size_t EI = 0;
         EI != Elements.size();
         ++EI) {
      swift::ASTNode &Element = Elements[EI];
      if (Expr *E = Element.dyn_cast<Expr*>()) {
        if (AssignExpr *AE = llvm::dyn_cast<AssignExpr>(E)) {
          Expr *Log = logAssignExpr(AE);
          if (Log) {
            Modified = true;
            Elements.insert(Elements.begin() + (EI + 1), Log);
            ++EI;
          }
        }
      } else if (Stmt *S = Element.dyn_cast<Stmt*>()) {
        Stmt *NS = transformStmt(S);
        if (NS != S) {
          Modified = true;
          Elements[EI] = NS;
        }
      } else if (Decl *D = Element.dyn_cast<Decl*>()) {
        (void)D;
      }
    }

    if (Modified) {
      return swift::BraceStmt::create(Context, BS->getLBraceLoc(),
                                      Context.AllocateCopy(Elements),
                                      BS->getRBraceLoc());
    } else {
      return BS;
    }
  }

  // log*() functions return a newly-created log expression to be inserted
  // after the expression they're looking at.
  Expr *logAssignExpr(AssignExpr *AE) {
    Expr *Dest = AE->getDest();
    if (DeclRefExpr *DRE = llvm::dyn_cast<DeclRefExpr>(Dest)) {
      return buildLoggerCall(DRE->getDecl());
    }
    return nullptr;
  }

  Expr *buildLoggerCall(ValueDecl *VD) {
    Expr *Name = new (Context) StringLiteralExpr("", SourceRange());
    Expr *Header = new (Context) StringLiteralExpr("", SourceRange());
    Header->setImplicit(true);

    Expr *LoggerArgExprs[] = {
        new (Context) DeclRefExpr(ConcreteDeclRef(VD),
                                  SourceLoc(),
                                  true, // implicit
                                  false, // uses direct property access
                                  Type()),
        Name,
        Header
      };

    TupleExpr *LoggerArgs = new (Context) TupleExpr(
      SourceLoc(),
      Context.AllocateCopy(LoggerArgExprs),
      (Identifier*)nullptr,
      SourceLoc(),
      false, // hasTrailingClosure
      true, // implicit
      Type());

    UnresolvedDeclRefExpr *LoggerRef =
      new (Context) UnresolvedDeclRefExpr(
        Context.getIdentifier("playground_log"),
        DeclRefKind::Ordinary,
        SourceLoc());

    LoggerRef->setImplicit(true);

    Expr *LoggerCall = new (Context) CallExpr(LoggerRef, LoggerArgs, true,
                                              Type());

    Expr *SendDataArgExprs[] = {
        LoggerCall
      };

    TupleExpr *SendDataArgs = new (Context) TupleExpr(
      SourceLoc(),
      Context.AllocateCopy(SendDataArgExprs),
      (Identifier*)nullptr,
      SourceLoc(),
      false, // hasTrailingClosure
      true, // implicit
      Type());

    UnresolvedDeclRefExpr *SendDataRef =
      new (Context) UnresolvedDeclRefExpr(
        Context.getIdentifier("DVTSendPlaygroundLogDataToHost"),
        DeclRefKind::Ordinary,
        SourceLoc());

    SendDataRef->setImplicit(true);

    Expr *SendDataCall = new (Context) CallExpr(SendDataRef, SendDataArgs, true,
                                                Type());

    if (!typeCheckCompletionContextExpr(Context, TypeCheckDC, SendDataCall)) {
      return nullptr;
    }

    return SendDataCall;
  }
};

void swift::performPlaygroundTransform(SourceFile &SF) {
  class ExpressionFinder : public ASTWalker {
    FuncDecl *WrappedDecl = nullptr;
    FuncDecl *ExpressionDecl = nullptr;
    StringRef WrappedName = "__lldb_wrapped_expr";
    StringRef ExpressionName = "__lldb_expr";
  public:
    virtual bool walkToDeclPre(Decl *D) {
      if (FuncDecl *FD = llvm::dyn_cast<FuncDecl>(D)) {
        StringRef FuncName = FD->getName().str();
        if (!FuncName.endswith(WrappedName)) {
          WrappedDecl = FD;
          return false;
        } else if (!FuncName.endswith(ExpressionName)) {
          ExpressionDecl = FD;
          return false;
        }
      }
      return true;
    }
    FuncDecl *getFunctionToTransform() {
      return WrappedDecl ? WrappedDecl : ExpressionDecl;
    }
  };

  ExpressionFinder EF;
  for (Decl* D : SF.Decls) {
    D->walk(EF);
  }

  if (FuncDecl *FuncToTransform = EF.getFunctionToTransform()) {
    if (BraceStmt *Body = FuncToTransform->getBody()) {
      ASTContext &Context(SF.getASTContext());

      Module *LoggerModule = Context.getModule(
        std::make_pair(Context.getIdentifier("PlaygroundLoggerLibrary"),
                       SourceLoc()));

      Module *CommModule = Context.getModule(
        std::make_pair(Context.getIdentifier("DVTPlaygroundCommunication"),
                       SourceLoc()));

      if (LoggerModule && CommModule)
      {
        SmallVector<ValueDecl*, 1> Decls;

        bool OK = true;

        LoggerModule->lookupValue(Module::AccessPathTy(),
                                  Context.getIdentifier("playground_log"),
                                  NLKind::UnqualifiedLookup,
                                  Decls);

        if (Decls.size() != 1)
          OK = false;

        Decls.clear();

        CommModule->lookupValue(
          Module::AccessPathTy(),
          Context.getIdentifier("DVTSendPlaygroundLogDataToHost"),
          NLKind::UnqualifiedLookup,
          Decls);

        if (Decls.size() != 1)
          OK = false;

        if (OK) {
          Instrumenter I(Context, FuncToTransform);
          BraceStmt *NewBody = I.transformBraceStmt(Body);
          if (NewBody != Body) {
            FuncToTransform->setBody(NewBody);
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/tracing/core/trace_writer_impl.h"

#include <string.h>

#include <algorithm>
#include <type_traits>
#include <utility>

#include "perfetto/base/logging.h"
#include "perfetto/protozero/proto_utils.h"
#include "src/tracing/core/shared_memory_arbiter_impl.h"

#include "perfetto/trace/trace_packet.pbzero.h"

using protozero::proto_utils::kMessageLengthFieldSize;
using protozero::proto_utils::WriteRedundantVarInt;
using ChunkHeader = perfetto::SharedMemoryABI::ChunkHeader;

namespace perfetto {

namespace {
constexpr size_t kPacketHeaderSize = SharedMemoryABI::kPacketHeaderSize;
}  // namespace

TraceWriterImpl::TraceWriterImpl(SharedMemoryArbiterImpl* shmem_arbiter,
                                 WriterID id,
                                 BufferID target_buffer)
    : shmem_arbiter_(shmem_arbiter),
      id_(id),
      target_buffer_(target_buffer),
      protobuf_stream_writer_(this) {
  // TODO(primiano): we could handle the case of running out of TraceWriterID(s)
  // more gracefully and always return a no-op TracePacket in NewTracePacket().
  PERFETTO_CHECK(id_ != 0);

  cur_packet_.reset(new protos::pbzero::TracePacket());
  cur_packet_->Finalize();  // To avoid the DCHECK in NewTracePacket().
}

TraceWriterImpl::~TraceWriterImpl() {
  if (cur_chunk_.is_valid()) {
    cur_packet_->Finalize();
#if !defined(PERFETTO_BUILD_WITH_CHROMIUM)
    // TODO(primiano) Remove this ifdef when https://crbug.com/844379 is
    // resolved.
    Flush();
#endif
  }
  shmem_arbiter_->ReleaseWriterID(id_);
}

void TraceWriterImpl::Flush(std::function<void()> callback) {
  // Flush() cannot be called in the middle of a TracePacket.
  PERFETTO_CHECK(cur_packet_->is_finalized());

  if (cur_chunk_.is_valid()) {
    shmem_arbiter_->ReturnCompletedChunk(std::move(cur_chunk_), target_buffer_,
                                         &patch_list_);
    shmem_arbiter_->FlushPendingCommitDataRequests(callback);
  } else {
    PERFETTO_DCHECK(patch_list_.empty());
  }
  protobuf_stream_writer_.Reset({nullptr, nullptr});
}

TraceWriterImpl::TracePacketHandle TraceWriterImpl::NewTracePacket() {
  // If we hit this, the caller is calling NewTracePacket() without having
  // finalized the previous packet.
  PERFETTO_DCHECK(cur_packet_->is_finalized());

  fragmenting_packet_ = false;

  // Reserve space for the size of the message. Note: this call might re-enter
  // into this class invoking GetNewBuffer() if there isn't enough space or if
  // this is the very first call to NewTracePacket().
  static_assert(kPacketHeaderSize == kMessageLengthFieldSize,
                "The packet header must match the Message header size");

  // It doesn't make sense to begin a packet that is going to fragment
  // immediately after (8 is just an arbitrary estimation on the minimum size of
  // a realistic packet).
  if (protobuf_stream_writer_.bytes_available() < kPacketHeaderSize + 8)
    protobuf_stream_writer_.Reset(GetNewBuffer());

  cur_packet_->Reset(&protobuf_stream_writer_);
  uint8_t* header = protobuf_stream_writer_.ReserveBytes(kPacketHeaderSize);
  memset(header, 0, kPacketHeaderSize);
  cur_packet_->set_size_field(header);
  cur_chunk_.IncrementPacketCount();
  TracePacketHandle handle(cur_packet_.get());
  cur_fragment_start_ = protobuf_stream_writer_.write_ptr();
  fragmenting_packet_ = true;
  return handle;
}

// Called by the Message. We can get here in two cases:
// 1. In the middle of writing a Message,
// when |fragmenting_packet_| == true. In this case we want to update the
// chunk header with a partial packet and start a new partial packet in the
// new chunk.
// 2. While calling ReserveBytes() for the packet header in NewTracePacket().
// In this case |fragmenting_packet_| == false and we just want a new chunk
// without creating any fragments.
protozero::ContiguousMemoryRange TraceWriterImpl::GetNewBuffer() {
  if (fragmenting_packet_) {
    uint8_t* const wptr = protobuf_stream_writer_.write_ptr();
    PERFETTO_DCHECK(wptr >= cur_fragment_start_);
    uint32_t partial_size = static_cast<uint32_t>(wptr - cur_fragment_start_);
    PERFETTO_DCHECK(partial_size < cur_chunk_.size());

    // Backfill the packet header with the fragment size.
    PERFETTO_DCHECK(partial_size > 0);
    cur_packet_->inc_size_already_written(partial_size);
    cur_chunk_.SetFlag(ChunkHeader::kLastPacketContinuesOnNextChunk);
    WriteRedundantVarInt(partial_size, cur_packet_->size_field());

    // Descend in the stack of non-finalized nested submessages (if any) and
    // detour their |size_field| into the |patch_list_|. At this point we have
    // to release the chunk and they cannot write anymore into that.
    // TODO(primiano): add tests to cover this logic.
    for (auto* nested_msg = cur_packet_->nested_message(); nested_msg;
         nested_msg = nested_msg->nested_message()) {
      uint8_t* const cur_hdr = nested_msg->size_field();

      // If this is false the protozero Message has already been instructed to
      // write, upon Finalize(), its size into the patch list.
      bool size_field_points_within_chunk =
          cur_hdr >= cur_chunk_.payload_begin() &&
          cur_hdr + kMessageLengthFieldSize <= cur_chunk_.end();

      if (size_field_points_within_chunk) {
        auto offset =
            static_cast<uint16_t>(cur_hdr - cur_chunk_.payload_begin());
        const ChunkID cur_chunk_id =
            cur_chunk_.header()->chunk_id.load(std::memory_order_relaxed);
        Patch* patch = patch_list_.emplace_back(cur_chunk_id, offset);
        nested_msg->set_size_field(&patch->size_field[0]);
      } else {
#if PERFETTO_DCHECK_IS_ON()
        // Ensure that the size field of the message points to an element of the
        // patch list.
        auto patch_it = std::find_if(
            patch_list_.begin(), patch_list_.end(),
            [cur_hdr](const Patch& p) { return &p.size_field[0] == cur_hdr; });
        PERFETTO_DCHECK(patch_it != patch_list_.end());
#endif
      }
    }  // for(nested_msg
  }    // if(fragmenting_packet)

  if (cur_chunk_.is_valid()) {
    // ReturnCompletedChunk will consume the first patched entries from
    // |patch_list_| and shrink it.
    shmem_arbiter_->ReturnCompletedChunk(std::move(cur_chunk_), target_buffer_,
                                         &patch_list_);
  }

  // Start a new chunk.

  ChunkHeader::Packets packets = {};
  if (fragmenting_packet_) {
    packets.count = 1;
    packets.flags = ChunkHeader::kFirstPacketContinuesFromPrevChunk;
  }

  // The memory order of the stores below doesn't really matter. This |header|
  // is just a local temporary object. The GetNewChunk() call below will copy it
  // into the shared buffer with the proper barriers.
  ChunkHeader header = {};
  header.writer_id.store(id_, std::memory_order_relaxed);
  header.chunk_id.store(next_chunk_id_++, std::memory_order_relaxed);
  header.packets.store(packets, std::memory_order_relaxed);

  cur_chunk_ = shmem_arbiter_->GetNewChunk(header);
  uint8_t* payload_begin = cur_chunk_.payload_begin();
  if (fragmenting_packet_) {
    cur_packet_->set_size_field(payload_begin);
    memset(payload_begin, 0, kPacketHeaderSize);
    payload_begin += kPacketHeaderSize;
    cur_fragment_start_ = payload_begin;
  }

  return protozero::ContiguousMemoryRange{payload_begin, cur_chunk_.end()};
}

WriterID TraceWriterImpl::writer_id() const {
  return id_;
}

// Base class ctor/dtor definition.
TraceWriter::TraceWriter() = default;
TraceWriter::~TraceWriter() = default;

}  // namespace perfetto
<commit_msg>Re-enabled TraceWriter flushing on destruction am: 34675596d8<commit_after>/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/tracing/core/trace_writer_impl.h"

#include <string.h>

#include <algorithm>
#include <type_traits>
#include <utility>

#include "perfetto/base/logging.h"
#include "perfetto/protozero/proto_utils.h"
#include "src/tracing/core/shared_memory_arbiter_impl.h"

#include "perfetto/trace/trace_packet.pbzero.h"

using protozero::proto_utils::kMessageLengthFieldSize;
using protozero::proto_utils::WriteRedundantVarInt;
using ChunkHeader = perfetto::SharedMemoryABI::ChunkHeader;

namespace perfetto {

namespace {
constexpr size_t kPacketHeaderSize = SharedMemoryABI::kPacketHeaderSize;
}  // namespace

TraceWriterImpl::TraceWriterImpl(SharedMemoryArbiterImpl* shmem_arbiter,
                                 WriterID id,
                                 BufferID target_buffer)
    : shmem_arbiter_(shmem_arbiter),
      id_(id),
      target_buffer_(target_buffer),
      protobuf_stream_writer_(this) {
  // TODO(primiano): we could handle the case of running out of TraceWriterID(s)
  // more gracefully and always return a no-op TracePacket in NewTracePacket().
  PERFETTO_CHECK(id_ != 0);

  cur_packet_.reset(new protos::pbzero::TracePacket());
  cur_packet_->Finalize();  // To avoid the DCHECK in NewTracePacket().
}

TraceWriterImpl::~TraceWriterImpl() {
  if (cur_chunk_.is_valid()) {
    cur_packet_->Finalize();
    Flush();
  }
  shmem_arbiter_->ReleaseWriterID(id_);
}

void TraceWriterImpl::Flush(std::function<void()> callback) {
  // Flush() cannot be called in the middle of a TracePacket.
  PERFETTO_CHECK(cur_packet_->is_finalized());

  if (cur_chunk_.is_valid()) {
    shmem_arbiter_->ReturnCompletedChunk(std::move(cur_chunk_), target_buffer_,
                                         &patch_list_);
    shmem_arbiter_->FlushPendingCommitDataRequests(callback);
  } else {
    PERFETTO_DCHECK(patch_list_.empty());
  }
  protobuf_stream_writer_.Reset({nullptr, nullptr});
}

TraceWriterImpl::TracePacketHandle TraceWriterImpl::NewTracePacket() {
  // If we hit this, the caller is calling NewTracePacket() without having
  // finalized the previous packet.
  PERFETTO_DCHECK(cur_packet_->is_finalized());

  fragmenting_packet_ = false;

  // Reserve space for the size of the message. Note: this call might re-enter
  // into this class invoking GetNewBuffer() if there isn't enough space or if
  // this is the very first call to NewTracePacket().
  static_assert(kPacketHeaderSize == kMessageLengthFieldSize,
                "The packet header must match the Message header size");

  // It doesn't make sense to begin a packet that is going to fragment
  // immediately after (8 is just an arbitrary estimation on the minimum size of
  // a realistic packet).
  if (protobuf_stream_writer_.bytes_available() < kPacketHeaderSize + 8)
    protobuf_stream_writer_.Reset(GetNewBuffer());

  cur_packet_->Reset(&protobuf_stream_writer_);
  uint8_t* header = protobuf_stream_writer_.ReserveBytes(kPacketHeaderSize);
  memset(header, 0, kPacketHeaderSize);
  cur_packet_->set_size_field(header);
  cur_chunk_.IncrementPacketCount();
  TracePacketHandle handle(cur_packet_.get());
  cur_fragment_start_ = protobuf_stream_writer_.write_ptr();
  fragmenting_packet_ = true;
  return handle;
}

// Called by the Message. We can get here in two cases:
// 1. In the middle of writing a Message,
// when |fragmenting_packet_| == true. In this case we want to update the
// chunk header with a partial packet and start a new partial packet in the
// new chunk.
// 2. While calling ReserveBytes() for the packet header in NewTracePacket().
// In this case |fragmenting_packet_| == false and we just want a new chunk
// without creating any fragments.
protozero::ContiguousMemoryRange TraceWriterImpl::GetNewBuffer() {
  if (fragmenting_packet_) {
    uint8_t* const wptr = protobuf_stream_writer_.write_ptr();
    PERFETTO_DCHECK(wptr >= cur_fragment_start_);
    uint32_t partial_size = static_cast<uint32_t>(wptr - cur_fragment_start_);
    PERFETTO_DCHECK(partial_size < cur_chunk_.size());

    // Backfill the packet header with the fragment size.
    PERFETTO_DCHECK(partial_size > 0);
    cur_packet_->inc_size_already_written(partial_size);
    cur_chunk_.SetFlag(ChunkHeader::kLastPacketContinuesOnNextChunk);
    WriteRedundantVarInt(partial_size, cur_packet_->size_field());

    // Descend in the stack of non-finalized nested submessages (if any) and
    // detour their |size_field| into the |patch_list_|. At this point we have
    // to release the chunk and they cannot write anymore into that.
    // TODO(primiano): add tests to cover this logic.
    for (auto* nested_msg = cur_packet_->nested_message(); nested_msg;
         nested_msg = nested_msg->nested_message()) {
      uint8_t* const cur_hdr = nested_msg->size_field();

      // If this is false the protozero Message has already been instructed to
      // write, upon Finalize(), its size into the patch list.
      bool size_field_points_within_chunk =
          cur_hdr >= cur_chunk_.payload_begin() &&
          cur_hdr + kMessageLengthFieldSize <= cur_chunk_.end();

      if (size_field_points_within_chunk) {
        auto offset =
            static_cast<uint16_t>(cur_hdr - cur_chunk_.payload_begin());
        const ChunkID cur_chunk_id =
            cur_chunk_.header()->chunk_id.load(std::memory_order_relaxed);
        Patch* patch = patch_list_.emplace_back(cur_chunk_id, offset);
        nested_msg->set_size_field(&patch->size_field[0]);
      } else {
#if PERFETTO_DCHECK_IS_ON()
        // Ensure that the size field of the message points to an element of the
        // patch list.
        auto patch_it = std::find_if(
            patch_list_.begin(), patch_list_.end(),
            [cur_hdr](const Patch& p) { return &p.size_field[0] == cur_hdr; });
        PERFETTO_DCHECK(patch_it != patch_list_.end());
#endif
      }
    }  // for(nested_msg
  }    // if(fragmenting_packet)

  if (cur_chunk_.is_valid()) {
    // ReturnCompletedChunk will consume the first patched entries from
    // |patch_list_| and shrink it.
    shmem_arbiter_->ReturnCompletedChunk(std::move(cur_chunk_), target_buffer_,
                                         &patch_list_);
  }

  // Start a new chunk.

  ChunkHeader::Packets packets = {};
  if (fragmenting_packet_) {
    packets.count = 1;
    packets.flags = ChunkHeader::kFirstPacketContinuesFromPrevChunk;
  }

  // The memory order of the stores below doesn't really matter. This |header|
  // is just a local temporary object. The GetNewChunk() call below will copy it
  // into the shared buffer with the proper barriers.
  ChunkHeader header = {};
  header.writer_id.store(id_, std::memory_order_relaxed);
  header.chunk_id.store(next_chunk_id_++, std::memory_order_relaxed);
  header.packets.store(packets, std::memory_order_relaxed);

  cur_chunk_ = shmem_arbiter_->GetNewChunk(header);
  uint8_t* payload_begin = cur_chunk_.payload_begin();
  if (fragmenting_packet_) {
    cur_packet_->set_size_field(payload_begin);
    memset(payload_begin, 0, kPacketHeaderSize);
    payload_begin += kPacketHeaderSize;
    cur_fragment_start_ = payload_begin;
  }

  return protozero::ContiguousMemoryRange{payload_begin, cur_chunk_.end()};
}

WriterID TraceWriterImpl::writer_id() const {
  return id_;
}

// Base class ctor/dtor definition.
TraceWriter::TraceWriter() = default;
TraceWriter::~TraceWriter() = default;

}  // namespace perfetto
<|endoftext|>


<commit_before>#include "ImageStack.h"
#include "Func.h"

using namespace ImageStack;
using namespace ImageStack::Lazy;

#define work(X) ((X+X*X*X)/(sqrt(X)+X*X))
//#define work(X) (X)

#define X_TILE_SIZE 256
#define Y_TILE_SIZE 32

void blur_fast(Image in, Image out) {
    __m256 one_third = _mm256_set1_ps(1.0f/3);

    for (int c = 0; c < in.channels; c++) {
        for (int t = 0; t < in.frames; t++) {

#pragma omp parallel for
            for (int yTile = 0; yTile < in.height; yTile += Y_TILE_SIZE) {
                __m256 v0, v1, v2, sum, avg;
                float tmp[(X_TILE_SIZE)*(Y_TILE_SIZE+2)];
                for (int xTile = 0; xTile < in.width; xTile += X_TILE_SIZE) {
                    float *tmpPtr = (float *)tmp;
                    for (int y = -1; y < Y_TILE_SIZE+1; y++) {
                        const float *inPtr = &(in(xTile, yTile+y, t, c));
                        for (int x = 0; x < X_TILE_SIZE; x += 8) {
                            v0 = _mm256_loadu_ps(inPtr-1);
                            v1 = _mm256_loadu_ps(inPtr+1);
                            v2 = _mm256_loadu_ps(inPtr);
                            sum = _mm256_add_ps(_mm256_add_ps(v0, v1), v2);
                            avg = _mm256_mul_ps(sum, one_third);
                            _mm256_storeu_ps(tmpPtr, avg);
                            tmpPtr += 8;
                            inPtr += 8;
                        }
                    }
                    tmpPtr = (float *)tmp;
                    for (int y = 0; y < Y_TILE_SIZE; y++) {
                        float *outPtr = &(out(xTile, yTile+y, t, c));
                        for (int x = 0; x < X_TILE_SIZE; x += 8) {
                            v0 = _mm256_loadu_ps(tmpPtr+(2*X_TILE_SIZE));
                            v1 = _mm256_loadu_ps(tmpPtr+X_TILE_SIZE);
                            v2 = _mm256_loadu_ps(tmpPtr);
                            tmpPtr += 8;
                            sum = _mm256_add_ps(_mm256_add_ps(v0, v1), v2);
                            avg = _mm256_mul_ps(sum, one_third);
                            _mm256_storeu_ps(outPtr, avg);
                            outPtr += 8;
                        }
                    }
                }
            }
        }
    }
}

int main(int argc, char **argv) {
    start();

    try {
        Image in = Load::apply("in.tmp");
        Image out(in.width, in.height, in.frames, in.channels);

        asm ("# even");
        Image even = subsampleX(in, 2, 0);
        asm ("# odd");
        Image odd = subsampleX(in, 2, 1);
        asm ("# flipped");
        Image flipped = subsampleX(in, -1, in.width-1);
        asm ("# done");

        Image evenRows = subsampleY(in, 2, 0);
        Image oddRows = subsampleY(in, 2, 1);
        Image flipY = subsampleY(in, -1, in.height-1);

        Save::apply(even, "even.tmp");
        Save::apply(odd, "odd.tmp");
        Save::apply(flipped, "flipped.tmp");

        Save::apply(evenRows, "evenRows.tmp");
        Save::apply(oddRows, "oddRows.tmp");
        Save::apply(flipY, "flipY.tmp");

        /*
        printf("Inline...\n");
        out.set(0);
        double t1s = currentTime();
        for (int i = 0; i < 10; i++) {
            // blur the square root
            // inline
            auto tmp = zeroBoundary(work(in));
            auto bx = shiftX(tmp, -1) + tmp + shiftX(tmp, 1);
            auto by = shiftY(bx, -1) + bx + shiftY(bx, 1);
            out.set(by*(1.0f/9));
        }
        double t1e = currentTime();
        Save::apply(out, "out_inline.tmp");

        printf("Root...\n");
        out.set(0);
        double t2s = currentTime();
        for (int i = 0; i < 10; i++) {
            // root
            Image tmp = work(in);
            Image bx = shiftX(zeroBoundary(tmp), -1) + tmp + shiftX(zeroBoundary(tmp), 1);
            Image by = (shiftY(zeroBoundary(bx), -1) + bx + shiftY(zeroBoundary(bx), 1))/9;
            out = by;
        }
        double t2e = currentTime();
        Save::apply(out, "out_root.tmp");

        printf("Chunk...\n");
        out.set(0);
        double t3s = currentTime();
        for (int i = 0; i < 10; i++) {
            // chunk
            auto tmp = zeroBoundary(work(in));
            Func bx = shiftX(tmp, -1) + tmp + shiftX(tmp, 1);
            out.set((shiftY(bx, -1) + bx + shiftY(bx, 1))/9);
        }
        double t3e = currentTime();
        Save::apply(out, "out_chunk.tmp");

        printf("Manual...\n");
        out.set(0);
        double t4s = currentTime();
        for (int i = 0; i < 10; i++) {
            blur_fast(in.region(1, 1, 0, 0, in.width-2, in.height-2, in.frames, in.channels),
                      out.region(1, 1, 0, 0, in.width-2, in.height-2, in.frames, in.channels));
        }
        double t4e = currentTime();
        Save::apply(out, "out_manual.tmp");

        printf("%f %f %f %f\n", t1e-t1s, t2e-t2s, t3e-t3s, t4e-t4s);
        */

    } catch (Exception &e) {
        printf("Failure: %s\n", e.message);
    }

    return 0;
}

<commit_msg>subsampling has bugs. checked in func_test.cpp exposes them<commit_after>#include "ImageStack.h"
#include "Func.h"

using namespace ImageStack;
using namespace ImageStack::Lazy;

#define work(X) ((X+X*X*X)/(sqrt(X)+X*X))
//#define work(X) (X)

#define X_TILE_SIZE 256
#define Y_TILE_SIZE 32

void blur_fast(Image in, Image out) {
    __m256 one_third = _mm256_set1_ps(1.0f/3);

    for (int c = 0; c < in.channels; c++) {
        for (int t = 0; t < in.frames; t++) {

#pragma omp parallel for
            for (int yTile = 0; yTile < in.height; yTile += Y_TILE_SIZE) {
                __m256 v0, v1, v2, sum, avg;
                float tmp[(X_TILE_SIZE)*(Y_TILE_SIZE+2)];
                for (int xTile = 0; xTile < in.width; xTile += X_TILE_SIZE) {
                    float *tmpPtr = (float *)tmp;
                    for (int y = -1; y < Y_TILE_SIZE+1; y++) {
                        const float *inPtr = &(in(xTile, yTile+y, t, c));
                        for (int x = 0; x < X_TILE_SIZE; x += 8) {
                            v0 = _mm256_loadu_ps(inPtr-1);
                            v1 = _mm256_loadu_ps(inPtr+1);
                            v2 = _mm256_loadu_ps(inPtr);
                            sum = _mm256_add_ps(_mm256_add_ps(v0, v1), v2);
                            avg = _mm256_mul_ps(sum, one_third);
                            _mm256_storeu_ps(tmpPtr, avg);
                            tmpPtr += 8;
                            inPtr += 8;
                        }
                    }
                    tmpPtr = (float *)tmp;
                    for (int y = 0; y < Y_TILE_SIZE; y++) {
                        float *outPtr = &(out(xTile, yTile+y, t, c));
                        for (int x = 0; x < X_TILE_SIZE; x += 8) {
                            v0 = _mm256_loadu_ps(tmpPtr+(2*X_TILE_SIZE));
                            v1 = _mm256_loadu_ps(tmpPtr+X_TILE_SIZE);
                            v2 = _mm256_loadu_ps(tmpPtr);
                            tmpPtr += 8;
                            sum = _mm256_add_ps(_mm256_add_ps(v0, v1), v2);
                            avg = _mm256_mul_ps(sum, one_third);
                            _mm256_storeu_ps(outPtr, avg);
                            outPtr += 8;
                        }
                    }
                }
            }
        }
    }
}

int main(int argc, char **argv) {
    start();

    try {
        Image in = Load::apply("in.tmp");
        Image out(in.width, in.height, in.frames, in.channels);

        Image even = subsampleX(in, 2, 0);
        Image odd = subsampleX(in, 2, 1);
        Image flipped = subsampleX(in, -1, in.width-1);
        Image evenRows = subsampleY(in, 2, 0);
        Image oddRows = subsampleY(in, 2, 1);
        Image flipY = subsampleY(in, -1, in.height-1);

        Image small(in.width/2, in.height/2, in.frames, in.channels);
        auto zb = zeroBoundary(in);
        Func sx = subsampleX(zb, 2, -1) + 3*subsampleX(zb, 2, 0) + 3*subsampleX(zb, 2, 1) + subsampleX(zb, 2, 2);
        auto sy = subsampleY(sx, 2, -1) + 3*subsampleY(sx, 2, 0) + 3*subsampleY(sx, 2, 1) + subsampleY(sx, 2, 2);
        small.set(sy/64);
        Save::apply(small, "small.tmp");

        Save::apply(even, "even.tmp");
        Save::apply(odd, "odd.tmp");
        Save::apply(flipped, "flipped.tmp");

        Save::apply(evenRows, "evenRows.tmp");
        Save::apply(oddRows, "oddRows.tmp");
        Save::apply(flipY, "flipY.tmp");

        /*
        printf("Inline...\n");
        out.set(0);
        double t1s = currentTime();
        for (int i = 0; i < 10; i++) {
            // blur the square root
            // inline
            auto tmp = zeroBoundary(work(in));
            auto bx = shiftX(tmp, -1) + tmp + shiftX(tmp, 1);
            auto by = shiftY(bx, -1) + bx + shiftY(bx, 1);
            out.set(by*(1.0f/9));
        }
        double t1e = currentTime();
        Save::apply(out, "out_inline.tmp");

        printf("Root...\n");
        out.set(0);
        double t2s = currentTime();
        for (int i = 0; i < 10; i++) {
            // root
            Image tmp = work(in);
            Image bx = shiftX(zeroBoundary(tmp), -1) + tmp + shiftX(zeroBoundary(tmp), 1);
            Image by = (shiftY(zeroBoundary(bx), -1) + bx + shiftY(zeroBoundary(bx), 1))/9;
            out = by;
        }
        double t2e = currentTime();
        Save::apply(out, "out_root.tmp");

        printf("Chunk...\n");
        out.set(0);
        double t3s = currentTime();
        for (int i = 0; i < 10; i++) {
            // chunk
            auto tmp = zeroBoundary(work(in));
            Func bx = shiftX(tmp, -1) + tmp + shiftX(tmp, 1);
            out.set((shiftY(bx, -1) + bx + shiftY(bx, 1))/9);
        }
        double t3e = currentTime();
        Save::apply(out, "out_chunk.tmp");

        printf("Manual...\n");
        out.set(0);
        double t4s = currentTime();
        for (int i = 0; i < 10; i++) {
            blur_fast(in.region(1, 1, 0, 0, in.width-2, in.height-2, in.frames, in.channels),
                      out.region(1, 1, 0, 0, in.width-2, in.height-2, in.frames, in.channels));
        }
        double t4e = currentTime();
        Save::apply(out, "out_manual.tmp");

        printf("%f %f %f %f\n", t1e-t1s, t2e-t2s, t3e-t3s, t4e-t4s);
        */

    } catch (Exception &e) {
        printf("Failure: %s\n", e.message);
    }

    return 0;
}

<|endoftext|>


<commit_before>/*********************************************************************
*
*  Copyright (c) 2017, Saurav Agarwal
*  All rights reserved.
*
*********************************************************************/

#include "G2OSolver.h"
#include "g2o/core/block_solver.h"
#include "g2o/core/factory.h"
#include "g2o/core/robust_kernel_impl.h"
#include "g2o/core/optimization_algorithm_factory.h"
#include "g2o/core/optimization_algorithm_levenberg.h"
#include "g2o/types/slam2d/types_slam2d.h"
#include "g2o/solvers/cholmod/linear_solver_cholmod.h"
#include <open_karto/Karto.h>
#include <ros/console.h>

typedef g2o::BlockSolver< g2o::BlockSolverTraits<-1, -1> > SlamBlockSolver;

typedef g2o::LinearSolverCholmod<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;

G2OSolver::G2OSolver()
{
  // Initialize the SparseOptimizer
  SlamLinearSolver* linearSolver = new SlamLinearSolver();

  linearSolver->setBlockOrdering(false);

  SlamBlockSolver* blockSolver = new SlamBlockSolver(linearSolver);

  optimizer_.setAlgorithm(new g2o::OptimizationAlgorithmLevenberg(blockSolver));

  latestNodeID_ = 0;

  useRobustKernel_ = true;
}

G2OSolver::~G2OSolver()
{
  // destroy all the singletons
  g2o::Factory::destroy();

  g2o::OptimizationAlgorithmFactory::destroy();

  g2o::HyperGraphActionLibrary::destroy();
}

void G2OSolver::Clear()
{
  corrections_.clear();
}

const karto::ScanSolver::IdPoseVector& G2OSolver::GetCorrections() const
{
  return corrections_;
}

void G2OSolver::Compute()
{
  corrections_.clear();

  // Fix the first node in the graph to hold the map in place
  g2o::OptimizableGraph::Vertex* first = optimizer_.vertex(0);

  if(!first)
  {
    ROS_ERROR("[g2o] No Node with ID 0 found!");
    return;
  }

  first->setFixed(true);

  // Do the graph optimization
  optimizer_.initializeOptimization();

  int iter = optimizer_.optimize(500);

  if (iter > 0)
  {
    ROS_INFO("[g2o] Optimization finished after %d iterations.", iter);
  }
  else
  {
    ROS_ERROR("[g2o] Optimization failed, result might be invalid!");
    return;
  }

  // Write the result so it can be used by the mapper
  g2o::SparseOptimizer::VertexContainer nodes = optimizer_.activeVertices();

  for (g2o::SparseOptimizer::VertexContainer::const_iterator n = nodes.begin(); n != nodes.end(); n++)
  {

    double estimate[3];

    if((*n)->getEstimateData(estimate))
    {
      karto::Pose2 pose(estimate[0], estimate[1], estimate[2]);

      corrections_.push_back(std::make_pair((*n)->id(), pose));
    }
    else
    {
      ROS_ERROR("[g2o] Could not get estimated pose from Optimizer!");
    }
  }
}

void G2OSolver::AddNode(karto::Vertex<karto::LocalizedRangeScan>* pVertex)
{

  karto::Pose2 odom = pVertex->GetObject()->GetCorrectedPose();

  g2o::VertexSE2* poseVertex = new g2o::VertexSE2;

  poseVertex->setEstimate(g2o::SE2(odom.GetX(), odom.GetY(), odom.GetHeading()));

  poseVertex->setId(pVertex->GetObject()->GetUniqueId());

  optimizer_.addVertex(poseVertex);

  latestNodeID_ = pVertex->GetObject()->GetUniqueId();

  ROS_DEBUG("[g2o] Adding node %d.", pVertex->GetObject()->GetUniqueId());

}

void G2OSolver::AddConstraint(karto::Edge<karto::LocalizedRangeScan>* pEdge)
{
  // Create a new edge
  g2o::EdgeSE2* odometry = new g2o::EdgeSE2;

  // Set source and target
  int sourceID = pEdge->GetSource()->GetObject()->GetUniqueId();

  int targetID = pEdge->GetTarget()->GetObject()->GetUniqueId();

  odometry->vertices()[0] = optimizer_.vertex(sourceID);

  odometry->vertices()[1] = optimizer_.vertex(targetID);

  if(odometry->vertices()[0] == NULL)
  {

    ROS_ERROR("[g2o] Source vertex with id %d does not exist!", sourceID);

    delete odometry;

    return;
  }
  if(odometry->vertices()[0] == NULL)
  {

    ROS_ERROR("[g2o] Target vertex with id %d does not exist!", targetID);

    delete odometry;

    return;
  }

  // Set the measurement (odometry distance between vertices)
  karto::LinkInfo* pLinkInfo = (karto::LinkInfo*)(pEdge->GetLabel());

  karto::Pose2 diff = pLinkInfo->GetPoseDifference();

  g2o::SE2 measurement(diff.GetX(), diff.GetY(), diff.GetHeading());

  odometry->setMeasurement(measurement);

  // Set the covariance of the measurement
  karto::Matrix3 precisionMatrix = pLinkInfo->GetCovariance().Inverse();

  Eigen::Matrix<double,3,3> info;

  info(0,0) = precisionMatrix(0,0);

  info(0,1) = info(1,0) = precisionMatrix(0,1);

  info(0,2) = info(2,0) = precisionMatrix(0,2);

  info(1,1) = precisionMatrix(1,1);

  info(1,2) = info(2,1) = precisionMatrix(1,2);

  info(2,2) = precisionMatrix(2,2);

  odometry->setInformation(info);

  if(useRobustKernel_)
  {

    g2o::RobustKernelDCS* rk = new g2o::RobustKernelDCS;

    odometry->setRobustKernel(rk);

  }

  // Add the constraint to the optimizer
  ROS_DEBUG("[g2o] Adding Edge from node %d to node %d.", sourceID, targetID);

  optimizer_.addEdge(odometry);

}

void G2OSolver::getGraph(std::vector<Eigen::Vector2d> &nodes, std::vector<std::pair<Eigen::Vector2d, Eigen::Vector2d> > &edges)
{
  using namespace g2o;

  //HyperGraph::VertexIDMap vertexMap = optimizer_.vertices();

  //HyperGraph::EdgeSet edgeSet = optimizer_.edges();

  double *data = new double[3];

  for (SparseOptimizer::VertexIDMap::iterator it = optimizer_.vertices().begin(); it != optimizer_.vertices().end(); ++it)
  {

    VertexSE2* v = dynamic_cast<VertexSE2*>(it->second);

    if(v)
    {

      v->getEstimateData(data);

      Eigen::Vector2d pose(data[0], data[1]);

      nodes.push_back(pose);

    }
  }

  double *data1 = new double[3];

  double *data2 = new double[3];

  // for (SparseOptimizer::EdgeSet::iterator it = optimizer_.edges().begin(); it != optimizer_.edges().end(); ++it)
  // {

  //   EdgeSE2* e = dynamic_cast<EdgeSE2*>(*it);

  //   if(e)
  //   {

  //     VertexSE2* v1 = dynamic_cast<VertexSE2*>(e->vertices()[0]);

  //     v1->getEstimateData(data1);

  //     Eigen::Vector2d poseFrom(data1[0], data1[1]);

  //     VertexSE2* v2 = dynamic_cast<VertexSE2*>(e->vertices()[1]);

  //     v2->getEstimateData(data2);

  //     Eigen::Vector2d poseTo(data2[0], data2[1]);

  //     edges.push_back(std::make_pair(poseFrom, poseTo));

  //   }

  // }

  delete data;

  delete data1;

  delete data2;

}
<commit_msg>Update G2OSolver.cpp<commit_after>/*********************************************************************
*
*  Copyright (c) 2017, Saurav Agarwal
*  All rights reserved.
*
*********************************************************************/

#include "G2OSolver.h"
#include "g2o/core/block_solver.h"
#include "g2o/core/factory.h"
#include "g2o/core/robust_kernel_impl.h"
#include "g2o/core/optimization_algorithm_factory.h"
#include "g2o/core/optimization_algorithm_levenberg.h"
#include "g2o/types/slam2d/types_slam2d.h"
#include "g2o/solvers/cholmod/linear_solver_cholmod.h"
#include <open_karto/Karto.h>
#include <ros/console.h>

typedef g2o::BlockSolver< g2o::BlockSolverTraits<-1, -1> > SlamBlockSolver;

typedef g2o::LinearSolverCholmod<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;

G2OSolver::G2OSolver()
{
  // Initialize the SparseOptimizer
   auto linearSolver = g2o::make_unique<SlamLinearSolver>();

  linearSolver->setBlockOrdering(false);

  auto blockSolver = g2o::make_unique<SlamBlockSolver>(std::move(linearSolver));

  optimizer_.setAlgorithm(new g2o::OptimizationAlgorithmLevenberg(blockSolver));

  latestNodeID_ = 0;

  useRobustKernel_ = true;
}

G2OSolver::~G2OSolver()
{
  // destroy all the singletons
  g2o::Factory::destroy();

  g2o::OptimizationAlgorithmFactory::destroy();

  g2o::HyperGraphActionLibrary::destroy();
}

void G2OSolver::Clear()
{
  corrections_.clear();
}

const karto::ScanSolver::IdPoseVector& G2OSolver::GetCorrections() const
{
  return corrections_;
}

void G2OSolver::Compute()
{
  corrections_.clear();

  // Fix the first node in the graph to hold the map in place
  g2o::OptimizableGraph::Vertex* first = optimizer_.vertex(0);

  if(!first)
  {
    ROS_ERROR("[g2o] No Node with ID 0 found!");
    return;
  }

  first->setFixed(true);

  // Do the graph optimization
  optimizer_.initializeOptimization();

  int iter = optimizer_.optimize(500);

  if (iter > 0)
  {
    ROS_INFO("[g2o] Optimization finished after %d iterations.", iter);
  }
  else
  {
    ROS_ERROR("[g2o] Optimization failed, result might be invalid!");
    return;
  }

  // Write the result so it can be used by the mapper
  g2o::SparseOptimizer::VertexContainer nodes = optimizer_.activeVertices();

  for (g2o::SparseOptimizer::VertexContainer::const_iterator n = nodes.begin(); n != nodes.end(); n++)
  {

    double estimate[3];

    if((*n)->getEstimateData(estimate))
    {
      karto::Pose2 pose(estimate[0], estimate[1], estimate[2]);

      corrections_.push_back(std::make_pair((*n)->id(), pose));
    }
    else
    {
      ROS_ERROR("[g2o] Could not get estimated pose from Optimizer!");
    }
  }
}

void G2OSolver::AddNode(karto::Vertex<karto::LocalizedRangeScan>* pVertex)
{

  karto::Pose2 odom = pVertex->GetObject()->GetCorrectedPose();

  g2o::VertexSE2* poseVertex = new g2o::VertexSE2;

  poseVertex->setEstimate(g2o::SE2(odom.GetX(), odom.GetY(), odom.GetHeading()));

  poseVertex->setId(pVertex->GetObject()->GetUniqueId());

  optimizer_.addVertex(poseVertex);

  latestNodeID_ = pVertex->GetObject()->GetUniqueId();

  ROS_DEBUG("[g2o] Adding node %d.", pVertex->GetObject()->GetUniqueId());

}

void G2OSolver::AddConstraint(karto::Edge<karto::LocalizedRangeScan>* pEdge)
{
  // Create a new edge
  g2o::EdgeSE2* odometry = new g2o::EdgeSE2;

  // Set source and target
  int sourceID = pEdge->GetSource()->GetObject()->GetUniqueId();

  int targetID = pEdge->GetTarget()->GetObject()->GetUniqueId();

  odometry->vertices()[0] = optimizer_.vertex(sourceID);

  odometry->vertices()[1] = optimizer_.vertex(targetID);

  if(odometry->vertices()[0] == NULL)
  {

    ROS_ERROR("[g2o] Source vertex with id %d does not exist!", sourceID);

    delete odometry;

    return;
  }
  if(odometry->vertices()[0] == NULL)
  {

    ROS_ERROR("[g2o] Target vertex with id %d does not exist!", targetID);

    delete odometry;

    return;
  }

  // Set the measurement (odometry distance between vertices)
  karto::LinkInfo* pLinkInfo = (karto::LinkInfo*)(pEdge->GetLabel());

  karto::Pose2 diff = pLinkInfo->GetPoseDifference();

  g2o::SE2 measurement(diff.GetX(), diff.GetY(), diff.GetHeading());

  odometry->setMeasurement(measurement);

  // Set the covariance of the measurement
  karto::Matrix3 precisionMatrix = pLinkInfo->GetCovariance().Inverse();

  Eigen::Matrix<double,3,3> info;

  info(0,0) = precisionMatrix(0,0);

  info(0,1) = info(1,0) = precisionMatrix(0,1);

  info(0,2) = info(2,0) = precisionMatrix(0,2);

  info(1,1) = precisionMatrix(1,1);

  info(1,2) = info(2,1) = precisionMatrix(1,2);

  info(2,2) = precisionMatrix(2,2);

  odometry->setInformation(info);

  if(useRobustKernel_)
  {

    g2o::RobustKernelDCS* rk = new g2o::RobustKernelDCS;

    odometry->setRobustKernel(rk);

  }

  // Add the constraint to the optimizer
  ROS_DEBUG("[g2o] Adding Edge from node %d to node %d.", sourceID, targetID);

  optimizer_.addEdge(odometry);

}

void G2OSolver::getGraph(std::vector<Eigen::Vector2d> &nodes, std::vector<std::pair<Eigen::Vector2d, Eigen::Vector2d> > &edges)
{
  using namespace g2o;

  //HyperGraph::VertexIDMap vertexMap = optimizer_.vertices();

  //HyperGraph::EdgeSet edgeSet = optimizer_.edges();

  double *data = new double[3];

  for (SparseOptimizer::VertexIDMap::iterator it = optimizer_.vertices().begin(); it != optimizer_.vertices().end(); ++it)
  {

    VertexSE2* v = dynamic_cast<VertexSE2*>(it->second);

    if(v)
    {

      v->getEstimateData(data);

      Eigen::Vector2d pose(data[0], data[1]);

      nodes.push_back(pose);

    }
  }

  double *data1 = new double[3];

  double *data2 = new double[3];

  // for (SparseOptimizer::EdgeSet::iterator it = optimizer_.edges().begin(); it != optimizer_.edges().end(); ++it)
  // {

  //   EdgeSE2* e = dynamic_cast<EdgeSE2*>(*it);

  //   if(e)
  //   {

  //     VertexSE2* v1 = dynamic_cast<VertexSE2*>(e->vertices()[0]);

  //     v1->getEstimateData(data1);

  //     Eigen::Vector2d poseFrom(data1[0], data1[1]);

  //     VertexSE2* v2 = dynamic_cast<VertexSE2*>(e->vertices()[1]);

  //     v2->getEstimateData(data2);

  //     Eigen::Vector2d poseTo(data2[0], data2[1]);

  //     edges.push_back(std::make_pair(poseFrom, poseTo));

  //   }

  // }

  delete data;

  delete data1;

  delete data2;

}
<|endoftext|>


<commit_before>//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 assembly -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file the shared super class printer that converts from our internal
// representation of machine-dependent LLVM code to Intel and AT&T format
// assembly language.
// This printer is the output mechanism used by `llc'.
//
//===----------------------------------------------------------------------===//

#include "X86AsmPrinter.h"
#include "X86ATTAsmPrinter.h"
#include "X86IntelAsmPrinter.h"
#include "X86MachineFunctionInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CallingConv.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Target/TargetAsmInfo.h"

using namespace llvm;

Statistic<> llvm::EmittedInsts("asm-printer",
                               "Number of machine instrs printed");

static X86FunctionInfo calculateFunctionInfo(const Function *F,
                                             const TargetData *TD) {
  X86FunctionInfo Info;
  uint64_t Size = 0;

  switch (F->getCallingConv()) {
  case CallingConv::X86_StdCall:
    Info.setDecorationStyle(StdCall);
    break;
  case CallingConv::X86_FastCall:
    Info.setDecorationStyle(FastCall);
    break;
  default:
    return Info;
  }

  for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
       AI != AE; ++AI)
    Size += TD->getTypeSize(AI->getType());

  // Size should be aligned to DWORD boundary
  Size = ((Size + 3)/4)*4;

  // We're not supporting tooooo huge arguments :)
  Info.setBytesToPopOnReturn((unsigned int)Size);
  return Info;
}

/// decorateName - Query FunctionInfoMap and use this information for various
/// name decoration.
void X86SharedAsmPrinter::decorateName(std::string &Name,
                                       const GlobalValue *GV) {
  const Function *F = dyn_cast<Function>(GV);
  if (!F) return;

  // We don't want to decorate non-stdcall or non-fastcall functions right now
  unsigned CC = F->getCallingConv();
  if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall)
    return;

  FMFInfoMap::const_iterator info_item = FunctionInfoMap.find(F);

  const X86FunctionInfo *Info;
  if (info_item == FunctionInfoMap.end()) {
    // Calculate apropriate function info and populate map
    FunctionInfoMap[F] = calculateFunctionInfo(F, TM.getTargetData());
    Info = &FunctionInfoMap[F];
  } else {
    Info = &info_item->second;
  }

  switch (Info->getDecorationStyle()) {
  case None:
    break;
  case StdCall:
    if (!F->isVarArg()) // Variadic functions do not receive @0 suffix.
      Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
    break;
  case FastCall:
    if (!F->isVarArg()) // Variadic functions do not receive @0 suffix.
      Name += '@' + utostr_32(Info->getBytesToPopOnReturn());

    if (Name[0] == '_') {
      Name[0] = '@';
    } else {
      Name = '@' + Name;
    }
    break;
  default:
    assert(0 && "Unsupported DecorationStyle");
  }
}

/// doInitialization
bool X86SharedAsmPrinter::doInitialization(Module &M) {
  if (Subtarget->isTargetDarwin()) {
    const X86Subtarget *Subtarget = &TM.getSubtarget<X86Subtarget>();
    if (!Subtarget->is64Bit())
      X86PICStyle = PICStyle::Stub;

    // Emit initial debug information.
    DW.BeginModule(&M);
  }

  return AsmPrinter::doInitialization(M);
}

bool X86SharedAsmPrinter::doFinalization(Module &M) {
  // Note: this code is not shared by the Intel printer as it is too different
  // from how MASM does things.  When making changes here don't forget to look
  // at X86IntelAsmPrinter::doFinalization().
  const TargetData *TD = TM.getTargetData();

  // Print out module-level global variables here.
  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I) {
    if (!I->hasInitializer()) continue;   // External global require no code

    // Check to see if this is a special global used by LLVM, if so, emit it.
    if (EmitSpecialLLVMGlobal(I))
      continue;

    std::string name = Mang->getValueName(I);
    Constant *C = I->getInitializer();
    unsigned Size = TD->getTypeSize(C->getType());
    unsigned Align = TD->getPreferredAlignmentLog(I);

    if (C->isNullValue() && /* FIXME: Verify correct */
        (I->hasInternalLinkage() || I->hasWeakLinkage() ||
         I->hasLinkOnceLinkage() ||
         (Subtarget->isTargetDarwin() &&
          I->hasExternalLinkage() && !I->hasSection()))) {
      if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
      if (I->hasExternalLinkage()) {
          O << "\t.globl\t" << name << "\n";
          O << "\t.zerofill __DATA__, __common, " << name << ", "
            << Size << ", " << Align;
      } else {
        SwitchToDataSection(TAI->getDataSection(), I);
        if (TAI->getLCOMMDirective() != NULL) {
          if (I->hasInternalLinkage()) {
            O << TAI->getLCOMMDirective() << name << "," << Size;
            if (Subtarget->isTargetDarwin())
              O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
          } else
            O << TAI->getCOMMDirective()  << name << "," << Size;
        } else {
          if (!Subtarget->isTargetCygwin()) {
            if (I->hasInternalLinkage())
              O << "\t.local\t" << name << "\n";
          }
          O << TAI->getCOMMDirective()  << name << "," << Size;
          if (TAI->getCOMMDirectiveTakesAlignment())
            O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
        }
      }
      O << "\t\t" << TAI->getCommentString() << " " << I->getName() << "\n";
    } else {
      switch (I->getLinkage()) {
      case GlobalValue::LinkOnceLinkage:
      case GlobalValue::WeakLinkage:
        if (Subtarget->isTargetDarwin()) {
          O << "\t.globl " << name << "\n"
            << "\t.weak_definition " << name << "\n";
          SwitchToDataSection(".section __DATA,__const_coal,coalesced", I);
        } else if (Subtarget->isTargetCygwin()) {
          std::string SectionName(".section\t.data$linkonce." +
                                  name +
                                  ",\"aw\"\n");
          SwitchToDataSection(SectionName.c_str(), I);
          O << "\t.globl " << name << "\n"
            << "\t.linkonce same_size\n";
        } else {
          std::string SectionName("\t.section\t.llvm.linkonce.d." +
                                  name +
                                  ",\"aw\",@progbits\n");
          SwitchToDataSection(SectionName.c_str(), I);
          O << "\t.weak " << name << "\n";
        }
        break;
      case GlobalValue::AppendingLinkage:
        // FIXME: appending linkage variables should go into a section of
        // their name or something.  For now, just emit them as external.
      case GlobalValue::DLLExportLinkage:
        DLLExportedGVs.insert(Mang->makeNameProper(I->getName(),""));
        // FALL THROUGH
      case GlobalValue::ExternalLinkage:
        // If external or appending, declare as a global symbol
        O << "\t.globl " << name << "\n";
        // FALL THROUGH
      case GlobalValue::InternalLinkage: {
        if (TAI->getCStringSection()) {
          const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
          if (CVA && CVA->isCString()) {
            SwitchToDataSection(TAI->getCStringSection(), I);
            break;
          }
        }
        SwitchToDataSection(TAI->getDataSection(), I);
        break;
      }
      default:
        assert(0 && "Unknown linkage type!");
      }

      EmitAlignment(Align, I);
      O << name << ":\t\t\t\t" << TAI->getCommentString() << " " << I->getName()
        << "\n";
      if (TAI->hasDotTypeDotSizeDirective())
        O << "\t.size " << name << ", " << Size << "\n";

      EmitGlobalConstant(C);
      O << '\n';
    }
  }

  // Output linker support code for dllexported globals
  if (DLLExportedGVs.begin() != DLLExportedGVs.end()) {
    SwitchToDataSection(".section .drectve", 0);
  }

  for (std::set<std::string>::iterator i = DLLExportedGVs.begin(),
         e = DLLExportedGVs.end();
         i != e; ++i) {
    O << "\t.ascii \" -export:" << *i << ",data\"\n";
  }

  if (DLLExportedFns.begin() != DLLExportedFns.end()) {
    SwitchToDataSection(".section .drectve", 0);
  }

  for (std::set<std::string>::iterator i = DLLExportedFns.begin(),
         e = DLLExportedFns.end();
         i != e; ++i) {
    O << "\t.ascii \" -export:" << *i << "\"\n";
  }

  if (Subtarget->isTargetDarwin()) {
    SwitchToDataSection("", 0);

    // Output stubs for dynamically-linked functions
    unsigned j = 1;
    for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
         i != e; ++i, ++j) {
      SwitchToDataSection(".section __IMPORT,__jump_table,symbol_stubs,"
                          "self_modifying_code+pure_instructions,5", 0);
      O << "L" << *i << "$stub:\n";
      O << "\t.indirect_symbol " << *i << "\n";
      O << "\thlt ; hlt ; hlt ; hlt ; hlt\n";
    }

    O << "\n";

    // Output stubs for external and common global variables.
    if (GVStubs.begin() != GVStubs.end())
      SwitchToDataSection(
                    ".section __IMPORT,__pointers,non_lazy_symbol_pointers", 0);
    for (std::set<std::string>::iterator i = GVStubs.begin(), e = GVStubs.end();
         i != e; ++i) {
      O << "L" << *i << "$non_lazy_ptr:\n";
      O << "\t.indirect_symbol " << *i << "\n";
      O << "\t.long\t0\n";
    }

    // Emit initial debug information.
    DW.EndModule();

    // Funny Darwin hack: This flag tells the linker that no global symbols
    // contain code that falls through to other global symbols (e.g. the obvious
    // implementation of multiple entry points).  If this doesn't occur, the
    // linker can safely perform dead code stripping.  Since LLVM never
    // generates code that does this, it is always safe to set.
    O << "\t.subsections_via_symbols\n";
  }

  AsmPrinter::doFinalization(M);
  return false; // success
}

/// createX86CodePrinterPass - Returns a pass that prints the X86 assembly code
/// for a MachineFunction to the given output stream, using the given target
/// machine description.
///
FunctionPass *llvm::createX86CodePrinterPass(std::ostream &o,
                                             X86TargetMachine &tm) {
  const X86Subtarget *Subtarget = &tm.getSubtarget<X86Subtarget>();

  if (Subtarget->isFlavorIntel()) {
    return new X86IntelAsmPrinter(o, tm, tm.getTargetAsmInfo());
  } else {
    return new X86ATTAsmPrinter(o, tm, tm.getTargetAsmInfo());
  }
}
<commit_msg>Doh. Must check if GV is constant first.<commit_after>//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 assembly -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file the shared super class printer that converts from our internal
// representation of machine-dependent LLVM code to Intel and AT&T format
// assembly language.
// This printer is the output mechanism used by `llc'.
//
//===----------------------------------------------------------------------===//

#include "X86AsmPrinter.h"
#include "X86ATTAsmPrinter.h"
#include "X86IntelAsmPrinter.h"
#include "X86MachineFunctionInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CallingConv.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Target/TargetAsmInfo.h"

using namespace llvm;

Statistic<> llvm::EmittedInsts("asm-printer",
                               "Number of machine instrs printed");

static X86FunctionInfo calculateFunctionInfo(const Function *F,
                                             const TargetData *TD) {
  X86FunctionInfo Info;
  uint64_t Size = 0;

  switch (F->getCallingConv()) {
  case CallingConv::X86_StdCall:
    Info.setDecorationStyle(StdCall);
    break;
  case CallingConv::X86_FastCall:
    Info.setDecorationStyle(FastCall);
    break;
  default:
    return Info;
  }

  for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
       AI != AE; ++AI)
    Size += TD->getTypeSize(AI->getType());

  // Size should be aligned to DWORD boundary
  Size = ((Size + 3)/4)*4;

  // We're not supporting tooooo huge arguments :)
  Info.setBytesToPopOnReturn((unsigned int)Size);
  return Info;
}

/// decorateName - Query FunctionInfoMap and use this information for various
/// name decoration.
void X86SharedAsmPrinter::decorateName(std::string &Name,
                                       const GlobalValue *GV) {
  const Function *F = dyn_cast<Function>(GV);
  if (!F) return;

  // We don't want to decorate non-stdcall or non-fastcall functions right now
  unsigned CC = F->getCallingConv();
  if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall)
    return;

  FMFInfoMap::const_iterator info_item = FunctionInfoMap.find(F);

  const X86FunctionInfo *Info;
  if (info_item == FunctionInfoMap.end()) {
    // Calculate apropriate function info and populate map
    FunctionInfoMap[F] = calculateFunctionInfo(F, TM.getTargetData());
    Info = &FunctionInfoMap[F];
  } else {
    Info = &info_item->second;
  }

  switch (Info->getDecorationStyle()) {
  case None:
    break;
  case StdCall:
    if (!F->isVarArg()) // Variadic functions do not receive @0 suffix.
      Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
    break;
  case FastCall:
    if (!F->isVarArg()) // Variadic functions do not receive @0 suffix.
      Name += '@' + utostr_32(Info->getBytesToPopOnReturn());

    if (Name[0] == '_') {
      Name[0] = '@';
    } else {
      Name = '@' + Name;
    }
    break;
  default:
    assert(0 && "Unsupported DecorationStyle");
  }
}

/// doInitialization
bool X86SharedAsmPrinter::doInitialization(Module &M) {
  if (Subtarget->isTargetDarwin()) {
    const X86Subtarget *Subtarget = &TM.getSubtarget<X86Subtarget>();
    if (!Subtarget->is64Bit())
      X86PICStyle = PICStyle::Stub;

    // Emit initial debug information.
    DW.BeginModule(&M);
  }

  return AsmPrinter::doInitialization(M);
}

bool X86SharedAsmPrinter::doFinalization(Module &M) {
  // Note: this code is not shared by the Intel printer as it is too different
  // from how MASM does things.  When making changes here don't forget to look
  // at X86IntelAsmPrinter::doFinalization().
  const TargetData *TD = TM.getTargetData();

  // Print out module-level global variables here.
  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I) {
    if (!I->hasInitializer()) continue;   // External global require no code

    // Check to see if this is a special global used by LLVM, if so, emit it.
    if (EmitSpecialLLVMGlobal(I))
      continue;

    std::string name = Mang->getValueName(I);
    Constant *C = I->getInitializer();
    unsigned Size = TD->getTypeSize(C->getType());
    unsigned Align = TD->getPreferredAlignmentLog(I);

    if (C->isNullValue() && /* FIXME: Verify correct */
        (I->hasInternalLinkage() || I->hasWeakLinkage() ||
         I->hasLinkOnceLinkage() ||
         (Subtarget->isTargetDarwin() &&
          I->hasExternalLinkage() && !I->hasSection()))) {
      if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
      if (I->hasExternalLinkage()) {
          O << "\t.globl\t" << name << "\n";
          O << "\t.zerofill __DATA__, __common, " << name << ", "
            << Size << ", " << Align;
      } else {
        SwitchToDataSection(TAI->getDataSection(), I);
        if (TAI->getLCOMMDirective() != NULL) {
          if (I->hasInternalLinkage()) {
            O << TAI->getLCOMMDirective() << name << "," << Size;
            if (Subtarget->isTargetDarwin())
              O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
          } else
            O << TAI->getCOMMDirective()  << name << "," << Size;
        } else {
          if (!Subtarget->isTargetCygwin()) {
            if (I->hasInternalLinkage())
              O << "\t.local\t" << name << "\n";
          }
          O << TAI->getCOMMDirective()  << name << "," << Size;
          if (TAI->getCOMMDirectiveTakesAlignment())
            O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
        }
      }
      O << "\t\t" << TAI->getCommentString() << " " << I->getName() << "\n";
    } else {
      switch (I->getLinkage()) {
      case GlobalValue::LinkOnceLinkage:
      case GlobalValue::WeakLinkage:
        if (Subtarget->isTargetDarwin()) {
          O << "\t.globl " << name << "\n"
            << "\t.weak_definition " << name << "\n";
          SwitchToDataSection(".section __DATA,__const_coal,coalesced", I);
        } else if (Subtarget->isTargetCygwin()) {
          std::string SectionName(".section\t.data$linkonce." +
                                  name +
                                  ",\"aw\"\n");
          SwitchToDataSection(SectionName.c_str(), I);
          O << "\t.globl " << name << "\n"
            << "\t.linkonce same_size\n";
        } else {
          std::string SectionName("\t.section\t.llvm.linkonce.d." +
                                  name +
                                  ",\"aw\",@progbits\n");
          SwitchToDataSection(SectionName.c_str(), I);
          O << "\t.weak " << name << "\n";
        }
        break;
      case GlobalValue::AppendingLinkage:
        // FIXME: appending linkage variables should go into a section of
        // their name or something.  For now, just emit them as external.
      case GlobalValue::DLLExportLinkage:
        DLLExportedGVs.insert(Mang->makeNameProper(I->getName(),""));
        // FALL THROUGH
      case GlobalValue::ExternalLinkage:
        // If external or appending, declare as a global symbol
        O << "\t.globl " << name << "\n";
        // FALL THROUGH
      case GlobalValue::InternalLinkage: {
        if (I->isConstant()) {
          const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
          if (TAI->getCStringSection() && CVA && CVA->isCString()) {
            SwitchToDataSection(TAI->getCStringSection(), I);
            break;
          }
        }
        SwitchToDataSection(TAI->getDataSection(), I);
        break;
      }
      default:
        assert(0 && "Unknown linkage type!");
      }

      EmitAlignment(Align, I);
      O << name << ":\t\t\t\t" << TAI->getCommentString() << " " << I->getName()
        << "\n";
      if (TAI->hasDotTypeDotSizeDirective())
        O << "\t.size " << name << ", " << Size << "\n";

      EmitGlobalConstant(C);
      O << '\n';
    }
  }

  // Output linker support code for dllexported globals
  if (DLLExportedGVs.begin() != DLLExportedGVs.end()) {
    SwitchToDataSection(".section .drectve", 0);
  }

  for (std::set<std::string>::iterator i = DLLExportedGVs.begin(),
         e = DLLExportedGVs.end();
         i != e; ++i) {
    O << "\t.ascii \" -export:" << *i << ",data\"\n";
  }

  if (DLLExportedFns.begin() != DLLExportedFns.end()) {
    SwitchToDataSection(".section .drectve", 0);
  }

  for (std::set<std::string>::iterator i = DLLExportedFns.begin(),
         e = DLLExportedFns.end();
         i != e; ++i) {
    O << "\t.ascii \" -export:" << *i << "\"\n";
  }

  if (Subtarget->isTargetDarwin()) {
    SwitchToDataSection("", 0);

    // Output stubs for dynamically-linked functions
    unsigned j = 1;
    for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
         i != e; ++i, ++j) {
      SwitchToDataSection(".section __IMPORT,__jump_table,symbol_stubs,"
                          "self_modifying_code+pure_instructions,5", 0);
      O << "L" << *i << "$stub:\n";
      O << "\t.indirect_symbol " << *i << "\n";
      O << "\thlt ; hlt ; hlt ; hlt ; hlt\n";
    }

    O << "\n";

    // Output stubs for external and common global variables.
    if (GVStubs.begin() != GVStubs.end())
      SwitchToDataSection(
                    ".section __IMPORT,__pointers,non_lazy_symbol_pointers", 0);
    for (std::set<std::string>::iterator i = GVStubs.begin(), e = GVStubs.end();
         i != e; ++i) {
      O << "L" << *i << "$non_lazy_ptr:\n";
      O << "\t.indirect_symbol " << *i << "\n";
      O << "\t.long\t0\n";
    }

    // Emit initial debug information.
    DW.EndModule();

    // Funny Darwin hack: This flag tells the linker that no global symbols
    // contain code that falls through to other global symbols (e.g. the obvious
    // implementation of multiple entry points).  If this doesn't occur, the
    // linker can safely perform dead code stripping.  Since LLVM never
    // generates code that does this, it is always safe to set.
    O << "\t.subsections_via_symbols\n";
  }

  AsmPrinter::doFinalization(M);
  return false; // success
}

/// createX86CodePrinterPass - Returns a pass that prints the X86 assembly code
/// for a MachineFunction to the given output stream, using the given target
/// machine description.
///
FunctionPass *llvm::createX86CodePrinterPass(std::ostream &o,
                                             X86TargetMachine &tm) {
  const X86Subtarget *Subtarget = &tm.getSubtarget<X86Subtarget>();

  if (Subtarget->isFlavorIntel()) {
    return new X86IntelAsmPrinter(o, tm, tm.getTargetAsmInfo());
  } else {
    return new X86ATTAsmPrinter(o, tm, tm.getTargetAsmInfo());
  }
}
<|endoftext|>