<commit_before>#include "display.h"
#include <iostream>
#include <boost/foreach.hpp>

void Display::Draw(const std::vector<Point> &points)
{
  system("cls");

  for(int i = 0; i < view_width_; ++i)
    for(int j = 0; j < view_height_; ++j)
      grid_[i][j] = false;

  BOOST_FOREACH(const Point& p, points) {
    int x = static_cast<int>(p.x() / static_cast<double>(model_width_) * view_width_);
    int y = static_cast<int>(p.y() / static_cast<double>(model_height_) * view_height_);
    if(x >= 0 && x < view_width_ && y >=0 && y < view_height_)
      grid_[x][y] = true;
  }

  for(int i = 0; i < view_height_; ++i) {
    for(int j = 0; j < view_width_; ++j) {
      if(grid_[j][i])
        std::cout << "O";
      else
        std::cout << " ";
    }
    std::cout << "\n";
  }
}

// initialize with height and width
Display::Display(const int height, const int width)
  :model_height_(height), model_width_(width), view_width_(79), view_height_(79)
{
  boost::array<array_type::index, 2> shape = {{ view_width_, view_height_ }};
  grid_.resize(shape);
}
<commit_msg>Draws borders<commit_after>#include "display.h"
#include <iostream>
#include <boost/foreach.hpp>

void Display::Draw(const std::vector<Point> &points)
{
  system("cls");

  for(int i = 0; i < view_width_; ++i)
    for(int j = 0; j < view_height_; ++j)
      grid_[i][j] = false;

  BOOST_FOREACH(const Point& p, points) {
    int x = static_cast<int>(p.x() / static_cast<double>(model_width_) * view_width_);
    int y = static_cast<int>(p.y() / static_cast<double>(model_height_) * view_height_);
    if(x >= 0 && x < view_width_ && y >=0 && y < view_height_)
      grid_[x][y] = true;
  }

  std::string top_border(view_width_ + 2, '_');
  std::cout << top_border << "\n";

  for(int i = 0; i < view_height_; ++i) {
    std::cout << "|";
    for(int j = 0; j < view_width_; ++j) {
      if(grid_[j][i])
        std::cout << "O";
      else
        std::cout << " ";
    }
    std::cout << "|\n";
  }

  std::cout << top_border << std::endl;
}

// initialize with height and width
Display::Display(const int height, const int width)
  :model_height_(height), model_width_(width), view_width_(70), view_height_(70)
{
  boost::array<array_type::index, 2> shape = {{ view_width_, view_height_ }};
  grid_.resize(shape);
}
<|endoftext|>


<commit_before>//===- MemoryDependenceAnalysis.cpp - Mem Deps Implementation  --*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements an analysis that determines, for a given memory
// operation, what preceding memory operations it depends on.  It builds on
// alias analysis information, and tries to provide a lazy, caching interface to
// a common kind of alias information query.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Support/CFG.h"
#include "llvm/Target/TargetData.h"

using namespace llvm;

char MemoryDependenceAnalysis::ID = 0;

const Instruction* MemoryDependenceAnalysis::NonLocal = (Instruction*)-3;
const Instruction* MemoryDependenceAnalysis::None = (Instruction*)-4;

// Register this pass...
static RegisterPass<MemoryDependenceAnalysis> X("memdep",
                                                "Memory Dependence Analysis");

/// getAnalysisUsage - Does not modify anything.  It uses Alias Analysis.
///
void MemoryDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AU.addRequiredTransitive<AliasAnalysis>();
  AU.addRequiredTransitive<TargetData>();
}

// Find the dependency of a CallSite
const Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C, Instruction* start,
                                                             BasicBlock* block) {

  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
  TargetData& TD = getAnalysis<TargetData>();
  BasicBlock::iterator blockBegin = C.getInstruction()->getParent()->begin();
  BasicBlock::iterator QI = C.getInstruction();

  if (start) {
    QI = start;
    blockBegin = start->getParent()->end();
  } else if (!start && block) {
    QI = block->end();
    blockBegin = block->end();
  }

  while (QI != blockBegin) {
    --QI;

    // If this inst is a memory op, get the pointer it accessed
    Value* pointer = 0;
    uint64_t pointerSize = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
      pointer = S->getPointerOperand();
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
      pointer = L->getPointerOperand();
      pointerSize = TD.getTypeSize(L->getType());
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
      pointer = AI;
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
        pointerSize = C->getZExtValue() * TD.getTypeSize(AI->getAllocatedType());
      else
        pointerSize = ~0UL;
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
      pointer = V->getOperand(0);
      pointerSize = TD.getTypeSize(V->getType());
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
      pointer = F->getPointerOperand();

      // FreeInsts erase the entire structure
      pointerSize = ~0UL;
    } else if (CallSite::get(QI).getInstruction() != 0) {
      if (AA.getModRefInfo(C, CallSite::get(QI)) != AliasAnalysis::NoModRef) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(C.getInstruction(),
                                              std::make_pair(QI, true)));
          reverseDep[QI].insert(C.getInstruction());
        }
        return QI;
      } else {
        continue;
      }
    } else
      continue;

    if (AA.getModRefInfo(C, pointer, pointerSize) != AliasAnalysis::NoModRef) {
      if (!start && !block) {
        depGraphLocal.insert(std::make_pair(C.getInstruction(),
                                            std::make_pair(QI, true)));
        reverseDep[QI].insert(C.getInstruction());
      }
      return QI;
    }
  }

  // No dependence found
  depGraphLocal.insert(std::make_pair(C.getInstruction(), std::make_pair(NonLocal, true)));
  reverseDep[NonLocal].insert(C.getInstruction());
  return NonLocal;
}

void MemoryDependenceAnalysis::nonLocalHelper(Instruction* query,
                                              BasicBlock* block,
                                              DenseMap<BasicBlock*, Value*>& resp) {
  SmallPtrSet<BasicBlock*, 4> visited;
  SmallVector<BasicBlock*, 4> stack;
  stack.push_back(block);

  while (!stack.empty()) {
    BasicBlock* BB = stack.back();

    if (visited.count(BB)) {
      stack.pop_back();
      continue;
    }

    if (BB != block) {
      visited.insert(BB);

      const Instruction* localDep = getDependency(query, 0, BB);
      if (localDep != NonLocal) {
        resp.insert(std::make_pair(BB, const_cast<Instruction*>(localDep)));
        stack.pop_back();

        continue;
      }
    } else if (BB == block && stack.size() > 1) {
      visited.insert(BB);

      const Instruction* localDep = getDependency(query, 0, BB);
      if (localDep != query)
        resp.insert(std::make_pair(BB, const_cast<Instruction*>(localDep)));

      stack.pop_back();

      continue;
    }

    bool predOnStack = false;
    bool inserted = false;
    for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
         PI != PE; ++PI)
      if (!visited.count(*PI)) {
        stack.push_back(*PI);
        inserted = true;
      } else
        predOnStack = true;

    if (inserted)
      continue;
    else if (!inserted && !predOnStack) {
      resp.insert(std::make_pair(BB, const_cast<Instruction*>(None)));
    } else if (!inserted && predOnStack){
      resp.insert(std::make_pair(BB, const_cast<Instruction*>(NonLocal)));
    }

    stack.pop_back();
  }
}

void MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query,
                                                     DenseMap<BasicBlock*, Value*>& resp) {
  const Instruction* localDep = getDependency(query);
  if (localDep != NonLocal) {
    resp.insert(std::make_pair(query->getParent(), const_cast<Instruction*>(localDep)));
    return;
  }

  nonLocalHelper(query, query->getParent(), resp);
}

/// getDependency - Return the instruction on which a memory operation
/// depends.  The local paramter indicates if the query should only
/// evaluate dependencies within the same basic block.
const Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query,
                                                     Instruction* start,
                                                     BasicBlock* block) {
  // Start looking for dependencies with the queried inst
  BasicBlock::iterator QI = query;

  // Check for a cached result
  std::pair<const Instruction*, bool> cachedResult = depGraphLocal[query];
  // If we have a _confirmed_ cached entry, return it
  if (cachedResult.second)
    return cachedResult.first;
  else if (cachedResult.first && cachedResult.first != NonLocal)
  // If we have an unconfirmed cached entry, we can start our search from there
    QI = const_cast<Instruction*>(cachedResult.first);

  if (start)
    QI = start;
  else if (!start && block)
    QI = block->end();

  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
  TargetData& TD = getAnalysis<TargetData>();

  // Get the pointer value for which dependence will be determined
  Value* dependee = 0;
  uint64_t dependeeSize = 0;
  bool queryIsVolatile = false;
  if (StoreInst* S = dyn_cast<StoreInst>(query)) {
    dependee = S->getPointerOperand();
    dependeeSize = TD.getTypeSize(S->getOperand(0)->getType());
    queryIsVolatile = S->isVolatile();
  } else if (LoadInst* L = dyn_cast<LoadInst>(query)) {
    dependee = L->getPointerOperand();
    dependeeSize = TD.getTypeSize(L->getType());
    queryIsVolatile = L->isVolatile();
  } else if (VAArgInst* V = dyn_cast<VAArgInst>(query)) {
    dependee = V->getOperand(0);
    dependeeSize = TD.getTypeSize(V->getType());
  } else if (FreeInst* F = dyn_cast<FreeInst>(query)) {
    dependee = F->getPointerOperand();

    // FreeInsts erase the entire structure, not just a field
    dependeeSize = ~0UL;
  } else if (CallSite::get(query).getInstruction() != 0)
    return getCallSiteDependency(CallSite::get(query), start, block);
  else if (isa<AllocationInst>(query))
    return None;
  else
    return None;

  BasicBlock::iterator blockBegin = block ? block->begin()
                                          : query->getParent()->begin();

  while (QI != blockBegin) {
    --QI;

    // If this inst is a memory op, get the pointer it accessed
    Value* pointer = 0;
    uint64_t pointerSize = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
      // All volatile loads/stores depend on each other
      if (queryIsVolatile && S->isVolatile()) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(S, true)));
          reverseDep[S].insert(query);
        }

        return S;
      }

      pointer = S->getPointerOperand();
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
      // All volatile loads/stores depend on each other
      if (queryIsVolatile && L->isVolatile()) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(L, true)));
          reverseDep[L].insert(query);
        }

        return L;
      }

      pointer = L->getPointerOperand();
      pointerSize = TD.getTypeSize(L->getType());
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
      pointer = AI;
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
        pointerSize = C->getZExtValue() * TD.getTypeSize(AI->getAllocatedType());
      else
        pointerSize = ~0UL;
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
      pointer = V->getOperand(0);
      pointerSize = TD.getTypeSize(V->getType());
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
      pointer = F->getPointerOperand();

      // FreeInsts erase the entire structure
      pointerSize = ~0UL;
    } else if (CallSite::get(QI).getInstruction() != 0) {
      // Call insts need special handling.  Check is they can modify our pointer
      AliasAnalysis::ModRefResult MR = AA.getModRefInfo(CallSite::get(QI),
                                                      dependee, dependeeSize);

      if (MR != AliasAnalysis::NoModRef) {
        // Loads don't depend on read-only calls
        if (isa<LoadInst>(query) && MR == AliasAnalysis::Ref)
          continue;

        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true)));
          reverseDep[QI].insert(query);
        }

        return QI;
      } else {
        continue;
      }
    }

    // If we found a pointer, check if it could be the same as our pointer
    if (pointer) {
      AliasAnalysis::AliasResult R = AA.alias(pointer, pointerSize,
                                              dependee, dependeeSize);

      if (R != AliasAnalysis::NoAlias) {
        // May-alias loads don't depend on each other
        if (isa<LoadInst>(query) && isa<LoadInst>(QI) &&
            R == AliasAnalysis::MayAlias)
          continue;

        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true)));
          reverseDep[QI].insert(query);
        }

        return QI;
      }
    }
  }

  // If we found nothing, return the non-local flag
  if (!start && !block) {
    depGraphLocal.insert(std::make_pair(query,
                                        std::make_pair(NonLocal, true)));
    reverseDep[NonLocal].insert(query);
  }

  return NonLocal;
}

/// removeInstruction - Remove an instruction from the dependence analysis,
/// updating the dependence of instructions that previously depended on it.
void MemoryDependenceAnalysis::removeInstruction(Instruction* rem) {
  // Figure out the new dep for things that currently depend on rem
  const Instruction* newDep = NonLocal;

  depMapType::iterator depGraphEntry = depGraphLocal.find(rem);
  // We assume here that it's not in the reverse map if it's not in
  // the dep map.  Checking it could be expensive, so don't do it.

  if (depGraphEntry != depGraphLocal.end()) {
    if (depGraphEntry->second.first != NonLocal &&
        depGraphEntry->second.second) {
      // If we have dep info for rem, set them to it
      BasicBlock::iterator RI = const_cast<Instruction*>(depGraphEntry->second.first);
      RI++;
      newDep = RI;
    } else if (depGraphEntry->second.first == NonLocal &&
               depGraphEntry->second.second ) {
      // If we have a confirmed non-local flag, use it
      newDep = NonLocal;
    } else {
      // Otherwise, use the immediate successor of rem
      // NOTE: This is because, when getDependence is called, it will first check
      // the immediate predecessor of what is in the cache.
      BasicBlock::iterator RI = rem;
      RI++;
      newDep = RI;
    }

    SmallPtrSet<Instruction*, 4>& set = reverseDep[rem];
    for (SmallPtrSet<Instruction*, 4>::iterator I = set.begin(), E = set.end();
         I != E; ++I) {
      // Insert the new dependencies
      // Mark it as unconfirmed as long as it is not the non-local flag
      depGraphLocal[*I] = std::make_pair(newDep, !newDep);
    }
    reverseDep.erase(rem);
  }

  getAnalysis<AliasAnalysis>().deleteValue(rem);
}
<commit_msg>Make memdep fit in 80 cols.<commit_after>//===- MemoryDependenceAnalysis.cpp - Mem Deps Implementation  --*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements an analysis that determines, for a given memory
// operation, what preceding memory operations it depends on.  It builds on
// alias analysis information, and tries to provide a lazy, caching interface to
// a common kind of alias information query.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Support/CFG.h"
#include "llvm/Target/TargetData.h"

using namespace llvm;

char MemoryDependenceAnalysis::ID = 0;

const Instruction* MemoryDependenceAnalysis::NonLocal = (Instruction*)-3;
const Instruction* MemoryDependenceAnalysis::None = (Instruction*)-4;

// Register this pass...
static RegisterPass<MemoryDependenceAnalysis> X("memdep",
                                                "Memory Dependence Analysis");

/// getAnalysisUsage - Does not modify anything.  It uses Alias Analysis.
///
void MemoryDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AU.addRequiredTransitive<AliasAnalysis>();
  AU.addRequiredTransitive<TargetData>();
}

// Find the dependency of a CallSite
const Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C,
                                                           Instruction* start,
                                                            BasicBlock* block) {

  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
  TargetData& TD = getAnalysis<TargetData>();
  BasicBlock::iterator blockBegin = C.getInstruction()->getParent()->begin();
  BasicBlock::iterator QI = C.getInstruction();

  if (start) {
    QI = start;
    blockBegin = start->getParent()->end();
  } else if (!start && block) {
    QI = block->end();
    blockBegin = block->end();
  }

  while (QI != blockBegin) {
    --QI;

    // If this inst is a memory op, get the pointer it accessed
    Value* pointer = 0;
    uint64_t pointerSize = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
      pointer = S->getPointerOperand();
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
      pointer = L->getPointerOperand();
      pointerSize = TD.getTypeSize(L->getType());
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
      pointer = AI;
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
        pointerSize = C->getZExtValue() * \
                      TD.getTypeSize(AI->getAllocatedType());
      else
        pointerSize = ~0UL;
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
      pointer = V->getOperand(0);
      pointerSize = TD.getTypeSize(V->getType());
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
      pointer = F->getPointerOperand();

      // FreeInsts erase the entire structure
      pointerSize = ~0UL;
    } else if (CallSite::get(QI).getInstruction() != 0) {
      if (AA.getModRefInfo(C, CallSite::get(QI)) != AliasAnalysis::NoModRef) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(C.getInstruction(),
                                              std::make_pair(QI, true)));
          reverseDep[QI].insert(C.getInstruction());
        }
        return QI;
      } else {
        continue;
      }
    } else
      continue;

    if (AA.getModRefInfo(C, pointer, pointerSize) != AliasAnalysis::NoModRef) {
      if (!start && !block) {
        depGraphLocal.insert(std::make_pair(C.getInstruction(),
                                            std::make_pair(QI, true)));
        reverseDep[QI].insert(C.getInstruction());
      }
      return QI;
    }
  }

  // No dependence found
  depGraphLocal.insert(std::make_pair(C.getInstruction(),
                                      std::make_pair(NonLocal, true)));
  reverseDep[NonLocal].insert(C.getInstruction());
  return NonLocal;
}

void MemoryDependenceAnalysis::nonLocalHelper(Instruction* query,
                                              BasicBlock* block,
                                         DenseMap<BasicBlock*, Value*>& resp) {
  SmallPtrSet<BasicBlock*, 4> visited;
  SmallVector<BasicBlock*, 4> stack;
  stack.push_back(block);

  while (!stack.empty()) {
    BasicBlock* BB = stack.back();

    if (visited.count(BB)) {
      stack.pop_back();
      continue;
    }

    if (BB != block) {
      visited.insert(BB);

      const Instruction* localDep = getDependency(query, 0, BB);
      if (localDep != NonLocal) {
        resp.insert(std::make_pair(BB, const_cast<Instruction*>(localDep)));
        stack.pop_back();

        continue;
      }
    } else if (BB == block && stack.size() > 1) {
      visited.insert(BB);

      const Instruction* localDep = getDependency(query, 0, BB);
      if (localDep != query)
        resp.insert(std::make_pair(BB, const_cast<Instruction*>(localDep)));

      stack.pop_back();

      continue;
    }

    bool predOnStack = false;
    bool inserted = false;
    for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
         PI != PE; ++PI)
      if (!visited.count(*PI)) {
        stack.push_back(*PI);
        inserted = true;
      } else
        predOnStack = true;

    if (inserted)
      continue;
    else if (!inserted && !predOnStack) {
      resp.insert(std::make_pair(BB, const_cast<Instruction*>(None)));
    } else if (!inserted && predOnStack){
      resp.insert(std::make_pair(BB, const_cast<Instruction*>(NonLocal)));
    }

    stack.pop_back();
  }
}

/// getNonLocalDependency - Fills the passed-in map with the non-local
/// dependencies of the queries.  The map will contain NonLocal for
/// blocks between the query and its dependencies.
void MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query,
                                         DenseMap<BasicBlock*, Value*>& resp) {
  const Instruction* localDep = getDependency(query);
  if (localDep != NonLocal) {
    resp.insert(std::make_pair(query->getParent(),
                               const_cast<Instruction*>(localDep)));
    return;
  }

  nonLocalHelper(query, query->getParent(), resp);
}

/// getDependency - Return the instruction on which a memory operation
/// depends.  The local paramter indicates if the query should only
/// evaluate dependencies within the same basic block.
const Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query,
                                                     Instruction* start,
                                                     BasicBlock* block) {
  // Start looking for dependencies with the queried inst
  BasicBlock::iterator QI = query;

  // Check for a cached result
  std::pair<const Instruction*, bool> cachedResult = depGraphLocal[query];
  // If we have a _confirmed_ cached entry, return it
  if (cachedResult.second)
    return cachedResult.first;
  else if (cachedResult.first && cachedResult.first != NonLocal)
  // If we have an unconfirmed cached entry, we can start our search from there
    QI = const_cast<Instruction*>(cachedResult.first);

  if (start)
    QI = start;
  else if (!start && block)
    QI = block->end();

  AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
  TargetData& TD = getAnalysis<TargetData>();

  // Get the pointer value for which dependence will be determined
  Value* dependee = 0;
  uint64_t dependeeSize = 0;
  bool queryIsVolatile = false;
  if (StoreInst* S = dyn_cast<StoreInst>(query)) {
    dependee = S->getPointerOperand();
    dependeeSize = TD.getTypeSize(S->getOperand(0)->getType());
    queryIsVolatile = S->isVolatile();
  } else if (LoadInst* L = dyn_cast<LoadInst>(query)) {
    dependee = L->getPointerOperand();
    dependeeSize = TD.getTypeSize(L->getType());
    queryIsVolatile = L->isVolatile();
  } else if (VAArgInst* V = dyn_cast<VAArgInst>(query)) {
    dependee = V->getOperand(0);
    dependeeSize = TD.getTypeSize(V->getType());
  } else if (FreeInst* F = dyn_cast<FreeInst>(query)) {
    dependee = F->getPointerOperand();

    // FreeInsts erase the entire structure, not just a field
    dependeeSize = ~0UL;
  } else if (CallSite::get(query).getInstruction() != 0)
    return getCallSiteDependency(CallSite::get(query), start, block);
  else if (isa<AllocationInst>(query))
    return None;
  else
    return None;

  BasicBlock::iterator blockBegin = block ? block->begin()
                                          : query->getParent()->begin();

  while (QI != blockBegin) {
    --QI;

    // If this inst is a memory op, get the pointer it accessed
    Value* pointer = 0;
    uint64_t pointerSize = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
      // All volatile loads/stores depend on each other
      if (queryIsVolatile && S->isVolatile()) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(S, true)));
          reverseDep[S].insert(query);
        }

        return S;
      }

      pointer = S->getPointerOperand();
      pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
    } else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
      // All volatile loads/stores depend on each other
      if (queryIsVolatile && L->isVolatile()) {
        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query, std::make_pair(L, true)));
          reverseDep[L].insert(query);
        }

        return L;
      }

      pointer = L->getPointerOperand();
      pointerSize = TD.getTypeSize(L->getType());
    } else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
      pointer = AI;
      if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
        pointerSize = C->getZExtValue() * \
                      TD.getTypeSize(AI->getAllocatedType());
      else
        pointerSize = ~0UL;
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
      pointer = V->getOperand(0);
      pointerSize = TD.getTypeSize(V->getType());
    } else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
      pointer = F->getPointerOperand();

      // FreeInsts erase the entire structure
      pointerSize = ~0UL;
    } else if (CallSite::get(QI).getInstruction() != 0) {
      // Call insts need special handling. Check if they can modify our pointer
      AliasAnalysis::ModRefResult MR = AA.getModRefInfo(CallSite::get(QI),
                                                      dependee, dependeeSize);

      if (MR != AliasAnalysis::NoModRef) {
        // Loads don't depend on read-only calls
        if (isa<LoadInst>(query) && MR == AliasAnalysis::Ref)
          continue;

        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query,
                                              std::make_pair(QI, true)));
          reverseDep[QI].insert(query);
        }

        return QI;
      } else {
        continue;
      }
    }

    // If we found a pointer, check if it could be the same as our pointer
    if (pointer) {
      AliasAnalysis::AliasResult R = AA.alias(pointer, pointerSize,
                                              dependee, dependeeSize);

      if (R != AliasAnalysis::NoAlias) {
        // May-alias loads don't depend on each other
        if (isa<LoadInst>(query) && isa<LoadInst>(QI) &&
            R == AliasAnalysis::MayAlias)
          continue;

        if (!start && !block) {
          depGraphLocal.insert(std::make_pair(query,
                                              std::make_pair(QI, true)));
          reverseDep[QI].insert(query);
        }

        return QI;
      }
    }
  }

  // If we found nothing, return the non-local flag
  if (!start && !block) {
    depGraphLocal.insert(std::make_pair(query,
                                        std::make_pair(NonLocal, true)));
    reverseDep[NonLocal].insert(query);
  }

  return NonLocal;
}

/// removeInstruction - Remove an instruction from the dependence analysis,
/// updating the dependence of instructions that previously depended on it.
void MemoryDependenceAnalysis::removeInstruction(Instruction* rem) {
  // Figure out the new dep for things that currently depend on rem
  const Instruction* newDep = NonLocal;

  depMapType::iterator depGraphEntry = depGraphLocal.find(rem);
  // We assume here that it's not in the reverse map if it's not in
  // the dep map.  Checking it could be expensive, so don't do it.

  if (depGraphEntry != depGraphLocal.end()) {
    if (depGraphEntry->second.first != NonLocal &&
        depGraphEntry->second.second) {
      // If we have dep info for rem, set them to it
      BasicBlock::iterator RI =
                         const_cast<Instruction*>(depGraphEntry->second.first);
      RI++;
      newDep = RI;
    } else if (depGraphEntry->second.first == NonLocal &&
               depGraphEntry->second.second ) {
      // If we have a confirmed non-local flag, use it
      newDep = NonLocal;
    } else {
      // Otherwise, use the immediate successor of rem
      // NOTE: This is because, when getDependence is called, it will first
      // check the immediate predecessor of what is in the cache.
      BasicBlock::iterator RI = rem;
      RI++;
      newDep = RI;
    }

    SmallPtrSet<Instruction*, 4>& set = reverseDep[rem];
    for (SmallPtrSet<Instruction*, 4>::iterator I = set.begin(), E = set.end();
         I != E; ++I) {
      // Insert the new dependencies
      // Mark it as unconfirmed as long as it is not the non-local flag
      depGraphLocal[*I] = std::make_pair(newDep, !newDep);
    }
    reverseDep.erase(rem);
  }

  getAnalysis<AliasAnalysis>().deleteValue(rem);
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE libraries and the Kate part.
 *
 *  Copyright (C) 2009 by Michel Ludwig <michel.ludwig@kdemail.net>
 *  Copyright (C) 2008 Mirko Stocker <me@misto.ch>
 *  Copyright (C) 2004-2005 Anders Lund <anders@alweb.dk>
 *  Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
 *  Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
 *  Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
 *  Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "spellcheckdialog.h"
#include "spellcheckdialog.moc"

#include "katedocument.h"
#include "kateglobal.h"
#include "kateview.h"
#include "spellcheck/spellcheck.h"

#include <kaction.h>
#include <kactioncollection.h>
#include <kicon.h>
#include <kstandardaction.h>
#include <sonnet/dialog.h>
#include <sonnet/backgroundchecker.h>
#include <sonnet/speller.h>

#include <QMutexLocker>

#include <kdebug.h>

KateSpellCheckDialog::KateSpellCheckDialog( KateView* view )
  : QObject( view )
  , m_view (view)
  , m_speller (NULL)
  , m_backgroundChecker(NULL)
  , m_sonnetDialog(NULL)
  , m_globalSpellCheckRange(NULL)
  , m_spellCheckCancelledByUser(false)
{
}

KateSpellCheckDialog::~KateSpellCheckDialog()
{
    delete m_globalSpellCheckRange;
    delete m_sonnetDialog;
    delete m_backgroundChecker;
    delete m_speller;
}

void KateSpellCheckDialog::createActions( KActionCollection* ac )
{
    ac->addAction( KStandardAction::Spelling, this, SLOT(spellcheck()) );

    KAction *a = new KAction( i18n("Spelling (from cursor)..."), this);
    ac->addAction("tools_spelling_from_cursor", a );
    a->setIcon( KIcon( "tools-check-spelling" ) );
    a->setWhatsThis(i18n("Check the document's spelling from the cursor and forward"));
    connect( a, SIGNAL( triggered() ), this, SLOT(spellcheckFromCursor()) );

    m_spellcheckSelection = new KAction( i18n("Spellcheck Selection..."), this );
    ac->addAction("tools_spelling_selection", m_spellcheckSelection);
    m_spellcheckSelection->setIcon( KIcon( "tools-check-spelling" ) );
    m_spellcheckSelection->setWhatsThis(i18n("Check spelling of the selected text"));
    connect( m_spellcheckSelection, SIGNAL( triggered() ), this, SLOT(spellcheckSelection()) );
}

void KateSpellCheckDialog::updateActions ()
{
  m_spellcheckSelection->setEnabled (m_view->selection ());
}

void KateSpellCheckDialog::spellcheckFromCursor()
{
  spellcheck( m_view->cursorPosition() );
}

void KateSpellCheckDialog::spellcheckSelection()
{
  spellcheck( m_view->selectionRange().start(), m_view->selectionRange().end() );
}

void KateSpellCheckDialog::spellcheck()
{
  spellcheck( KTextEditor::Cursor( 0, 0 ) );
}

void KateSpellCheckDialog::spellcheck( const KTextEditor::Cursor &from, const KTextEditor::Cursor &to )
{
  KTextEditor::Cursor start = from;
  KTextEditor::Cursor end = to;

  if ( end.line() == 0 && end.column() == 0 )
  {
    end = m_view->doc()->documentEnd();
  }

  if ( !m_speller )
  {
    m_speller = new Sonnet::Speller();
  }
  else
  {
    m_speller->restore(KGlobal::config().data());
  }

  if ( !m_backgroundChecker )
  {
    m_backgroundChecker = new Sonnet::BackgroundChecker(*m_speller);
  }

  if ( !m_sonnetDialog )
  {
    m_sonnetDialog = new Sonnet::Dialog(m_backgroundChecker, m_view);
    m_sonnetDialog->showProgressDialog(200);
    m_sonnetDialog->showSpellCheckCompletionMessage();
    m_sonnetDialog->setSpellCheckContinuedAfterReplacement(false);

    connect(m_sonnetDialog,SIGNAL(done(const QString&)),this,SLOT(installNextSpellCheckRange()));

    connect(m_sonnetDialog,SIGNAL(replace(const QString&,int,const QString&)),
        this,SLOT(corrected(const QString&,int,const QString&)));

    connect(m_sonnetDialog,SIGNAL(misspelling(const QString&,int)),
        this,SLOT(misspelling(const QString&,int)));

    connect(m_sonnetDialog,SIGNAL(cancel()),
        this,SLOT(cancelClicked()));

    connect(m_sonnetDialog,SIGNAL(destroyed(QObject*)),
            this,SLOT(objectDestroyed(QObject*)));
  }

  QMutexLocker(m_view->doc()->smartMutex());
  delete m_globalSpellCheckRange;
  // we expand to handle the situation when the last word in the range is replace by a new one
  m_globalSpellCheckRange = m_view->doc()->newSmartRange( KTextEditor::Range( start, end ),
                                                          NULL,
                                                          KTextEditor::SmartRange::ExpandLeft | KTextEditor::SmartRange::ExpandRight);
  m_spellCheckCancelledByUser = false;
  performSpellCheck( *m_globalSpellCheckRange );
}

KTextEditor::Cursor KateSpellCheckDialog::locatePosition( int pos )
{
  uint remains;

  while ( m_spellLastPos < (uint)pos )
  {
    remains = pos - m_spellLastPos;
    uint l = m_view->doc()->lineLength( m_spellPosCursor.line() ) - m_spellPosCursor.column();
    if ( l > remains )
    {
      m_spellPosCursor.setColumn( m_spellPosCursor.column() + remains );
      m_spellLastPos = pos;
    }
    else
    {
      m_spellPosCursor.setLine( m_spellPosCursor.line() + 1 );
      m_spellPosCursor.setColumn(0);
      m_spellLastPos += l + 1;
    }
  }

  return m_spellPosCursor;
}

void KateSpellCheckDialog::misspelling( const QString& word, int pos )
{
  KTextEditor::Cursor cursor;
  int length;
  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );
  cursor = locatePosition( origPos );
  length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
            - origPos;

  m_view->setCursorPositionInternal (cursor, 1);
  m_view->setSelection( KTextEditor::Range(cursor, length) );
}

void KateSpellCheckDialog::corrected( const QString& word, int pos, const QString& newWord )
{
  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );

  int length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
                - origPos;

  KTextEditor::Cursor replacementStartCursor = locatePosition( origPos );
  KTextEditor::Range replacementRange = KTextEditor::Range( replacementStartCursor, length );
  KateDocument *doc = m_view->doc();
  KateGlobal::self()->spellCheckManager()->replaceCharactersEncodedIfNecessary( newWord, doc, replacementRange );

  m_currentSpellCheckRange.setRange( KTextEditor::Range( replacementStartCursor, m_currentSpellCheckRange.end() ) );
  // we have to be careful here: due to static word wrapping the text might change in addition to simply
  // the misspelled word being replaced, i.e. new line breaks might be inserted as well. As such, the text
  // in the 'Sonnet::Dialog' might be eventually out of sync with the visible text. Therefore, we 'restart'
  // spell checking from the current position.
  QMutexLocker( doc->smartMutex() );
  performSpellCheck( KTextEditor::Range( replacementStartCursor, m_globalSpellCheckRange->end() ) );
}

void KateSpellCheckDialog::performSpellCheck(const KTextEditor::Range& range)
{
  if(range.isEmpty()) {
    spellCheckDone();
  }
  m_languagesInSpellCheckRange = KateGlobal::self()->spellCheckManager()->spellCheckLanguageRanges(m_view->doc(), range);
  m_currentLanguageRangeIterator = m_languagesInSpellCheckRange.begin();
  m_currentSpellCheckRange = KTextEditor::Range::invalid();
  installNextSpellCheckRange();
  // first check if there is really something to spell check
  if(m_currentSpellCheckRange.isValid()) {
    m_sonnetDialog->show();
  }
}

void KateSpellCheckDialog::installNextSpellCheckRange()
{
  if ( m_spellCheckCancelledByUser
       || m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
  {
    m_currentSpellCheckRange = KTextEditor::Range::invalid();
    m_currentDecToEncOffsetList.clear();
    spellCheckDone();
    return;
  }
  KateSpellCheckManager *spellCheckManager = KateGlobal::self()->spellCheckManager();
  KTextEditor::Cursor nextRangeBegin = (m_currentSpellCheckRange.isValid() ? m_currentSpellCheckRange.end()
                                                                           : KTextEditor::Cursor::invalid());
  m_currentSpellCheckRange = KTextEditor::Range::invalid();
  m_currentDecToEncOffsetList.clear();
  QList<QPair<KTextEditor::Range, QString> > rangeDictionaryPairList;
  while ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
  {
    const KTextEditor::Range& currentLanguageRange = (*m_currentLanguageRangeIterator).first;
    const QString& dictionary = (*m_currentLanguageRangeIterator).second;
    KTextEditor::Range languageSubRange = (nextRangeBegin.isValid() ? KTextEditor::Range(nextRangeBegin, currentLanguageRange.end())
                                                                    : currentLanguageRange);

    rangeDictionaryPairList = spellCheckManager->spellCheckWrtHighlightingRanges(m_view->doc(),
                                                                                languageSubRange,
                                                                                dictionary,
                                                                                false, true);
    Q_ASSERT(rangeDictionaryPairList.size() <= 1);
    if(rangeDictionaryPairList.size() == 0) {
      ++m_currentLanguageRangeIterator;
      if ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
      {
        nextRangeBegin = (*m_currentLanguageRangeIterator).first.start();
      }
    }
    else {
      break;
    }
  }
  if ( m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
  {
    spellCheckDone();
    return;
  }

  const KTextEditor::Range& range = rangeDictionaryPairList.first().first;
  const QString& dictionary = rangeDictionaryPairList.first().second;

  m_spellPosCursor = range.start();
  m_spellLastPos = 0;

  if(m_speller->language() != dictionary) {
    m_speller->setLanguage(dictionary);
    m_backgroundChecker->setSpeller(*m_speller);
  }

  KateDocument *kateDocument = m_view->doc();
  m_currentSpellCheckRange = range;
  m_currentDecToEncOffsetList.clear();
  KateDocument::OffsetList encToDecOffsetList;
  QString text = kateDocument->decodeCharacters(m_currentSpellCheckRange, m_currentDecToEncOffsetList,
                                                encToDecOffsetList);
  m_sonnetDialog->setBuffer(text);
}

void KateSpellCheckDialog::cancelClicked()
{
  m_spellCheckCancelledByUser = true;
}

void KateSpellCheckDialog::spellCheckDone()
{
  m_view->clearSelection();
}

void KateSpellCheckDialog::objectDestroyed(QObject *object)
{
  Q_UNUSED(object);
  m_sonnetDialog = NULL;
}

//END

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>Ensure that no empty string is passed on to Sonnet as this can lead to a crash.<commit_after>/*  This file is part of the KDE libraries and the Kate part.
 *
 *  Copyright (C) 2009-2010 by Michel Ludwig <michel.ludwig@kdemail.net>
 *  Copyright (C) 2008 Mirko Stocker <me@misto.ch>
 *  Copyright (C) 2004-2005 Anders Lund <anders@alweb.dk>
 *  Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
 *  Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
 *  Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
 *  Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "spellcheckdialog.h"
#include "spellcheckdialog.moc"

#include "katedocument.h"
#include "kateglobal.h"
#include "kateview.h"
#include "spellcheck/spellcheck.h"

#include <kaction.h>
#include <kactioncollection.h>
#include <kicon.h>
#include <kstandardaction.h>
#include <sonnet/dialog.h>
#include <sonnet/backgroundchecker.h>
#include <sonnet/speller.h>

#include <QMutexLocker>

#include <kdebug.h>

KateSpellCheckDialog::KateSpellCheckDialog( KateView* view )
  : QObject( view )
  , m_view (view)
  , m_speller (NULL)
  , m_backgroundChecker(NULL)
  , m_sonnetDialog(NULL)
  , m_globalSpellCheckRange(NULL)
  , m_spellCheckCancelledByUser(false)
{
}

KateSpellCheckDialog::~KateSpellCheckDialog()
{
    delete m_globalSpellCheckRange;
    delete m_sonnetDialog;
    delete m_backgroundChecker;
    delete m_speller;
}

void KateSpellCheckDialog::createActions( KActionCollection* ac )
{
    ac->addAction( KStandardAction::Spelling, this, SLOT(spellcheck()) );

    KAction *a = new KAction( i18n("Spelling (from cursor)..."), this);
    ac->addAction("tools_spelling_from_cursor", a );
    a->setIcon( KIcon( "tools-check-spelling" ) );
    a->setWhatsThis(i18n("Check the document's spelling from the cursor and forward"));
    connect( a, SIGNAL( triggered() ), this, SLOT(spellcheckFromCursor()) );

    m_spellcheckSelection = new KAction( i18n("Spellcheck Selection..."), this );
    ac->addAction("tools_spelling_selection", m_spellcheckSelection);
    m_spellcheckSelection->setIcon( KIcon( "tools-check-spelling" ) );
    m_spellcheckSelection->setWhatsThis(i18n("Check spelling of the selected text"));
    connect( m_spellcheckSelection, SIGNAL( triggered() ), this, SLOT(spellcheckSelection()) );
}

void KateSpellCheckDialog::updateActions ()
{
  m_spellcheckSelection->setEnabled (m_view->selection ());
}

void KateSpellCheckDialog::spellcheckFromCursor()
{
  spellcheck( m_view->cursorPosition() );
}

void KateSpellCheckDialog::spellcheckSelection()
{
  spellcheck( m_view->selectionRange().start(), m_view->selectionRange().end() );
}

void KateSpellCheckDialog::spellcheck()
{
  spellcheck( KTextEditor::Cursor( 0, 0 ) );
}

void KateSpellCheckDialog::spellcheck( const KTextEditor::Cursor &from, const KTextEditor::Cursor &to )
{
  KTextEditor::Cursor start = from;
  KTextEditor::Cursor end = to;

  if ( end.line() == 0 && end.column() == 0 )
  {
    end = m_view->doc()->documentEnd();
  }

  if ( !m_speller )
  {
    m_speller = new Sonnet::Speller();
  }
  else
  {
    m_speller->restore(KGlobal::config().data());
  }

  if ( !m_backgroundChecker )
  {
    m_backgroundChecker = new Sonnet::BackgroundChecker(*m_speller);
  }

  if ( !m_sonnetDialog )
  {
    m_sonnetDialog = new Sonnet::Dialog(m_backgroundChecker, m_view);
    m_sonnetDialog->showProgressDialog(200);
    m_sonnetDialog->showSpellCheckCompletionMessage();
    m_sonnetDialog->setSpellCheckContinuedAfterReplacement(false);

    connect(m_sonnetDialog,SIGNAL(done(const QString&)),this,SLOT(installNextSpellCheckRange()));

    connect(m_sonnetDialog,SIGNAL(replace(const QString&,int,const QString&)),
        this,SLOT(corrected(const QString&,int,const QString&)));

    connect(m_sonnetDialog,SIGNAL(misspelling(const QString&,int)),
        this,SLOT(misspelling(const QString&,int)));

    connect(m_sonnetDialog,SIGNAL(cancel()),
        this,SLOT(cancelClicked()));

    connect(m_sonnetDialog,SIGNAL(destroyed(QObject*)),
            this,SLOT(objectDestroyed(QObject*)));
  }

  QMutexLocker(m_view->doc()->smartMutex());
  delete m_globalSpellCheckRange;
  // we expand to handle the situation when the last word in the range is replace by a new one
  m_globalSpellCheckRange = m_view->doc()->newSmartRange( KTextEditor::Range( start, end ),
                                                          NULL,
                                                          KTextEditor::SmartRange::ExpandLeft | KTextEditor::SmartRange::ExpandRight);
  m_spellCheckCancelledByUser = false;
  performSpellCheck( *m_globalSpellCheckRange );
}

KTextEditor::Cursor KateSpellCheckDialog::locatePosition( int pos )
{
  uint remains;

  while ( m_spellLastPos < (uint)pos )
  {
    remains = pos - m_spellLastPos;
    uint l = m_view->doc()->lineLength( m_spellPosCursor.line() ) - m_spellPosCursor.column();
    if ( l > remains )
    {
      m_spellPosCursor.setColumn( m_spellPosCursor.column() + remains );
      m_spellLastPos = pos;
    }
    else
    {
      m_spellPosCursor.setLine( m_spellPosCursor.line() + 1 );
      m_spellPosCursor.setColumn(0);
      m_spellLastPos += l + 1;
    }
  }

  return m_spellPosCursor;
}

void KateSpellCheckDialog::misspelling( const QString& word, int pos )
{
  KTextEditor::Cursor cursor;
  int length;
  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );
  cursor = locatePosition( origPos );
  length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
            - origPos;

  m_view->setCursorPositionInternal (cursor, 1);
  m_view->setSelection( KTextEditor::Range(cursor, length) );
}

void KateSpellCheckDialog::corrected( const QString& word, int pos, const QString& newWord )
{
  int origPos = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos );

  int length = m_view->doc()->computePositionWrtOffsets( m_currentDecToEncOffsetList, pos + word.length() )
                - origPos;

  KTextEditor::Cursor replacementStartCursor = locatePosition( origPos );
  KTextEditor::Range replacementRange = KTextEditor::Range( replacementStartCursor, length );
  KateDocument *doc = m_view->doc();
  KateGlobal::self()->spellCheckManager()->replaceCharactersEncodedIfNecessary( newWord, doc, replacementRange );

  m_currentSpellCheckRange.setRange( KTextEditor::Range( replacementStartCursor, m_currentSpellCheckRange.end() ) );
  // we have to be careful here: due to static word wrapping the text might change in addition to simply
  // the misspelled word being replaced, i.e. new line breaks might be inserted as well. As such, the text
  // in the 'Sonnet::Dialog' might be eventually out of sync with the visible text. Therefore, we 'restart'
  // spell checking from the current position.
  QMutexLocker( doc->smartMutex() );
  performSpellCheck( KTextEditor::Range( replacementStartCursor, m_globalSpellCheckRange->end() ) );
}

void KateSpellCheckDialog::performSpellCheck(const KTextEditor::Range& range)
{
  if(range.isEmpty()) {
    spellCheckDone();
  }
  m_languagesInSpellCheckRange = KateGlobal::self()->spellCheckManager()->spellCheckLanguageRanges(m_view->doc(), range);
  m_currentLanguageRangeIterator = m_languagesInSpellCheckRange.begin();
  m_currentSpellCheckRange = KTextEditor::Range::invalid();
  installNextSpellCheckRange();
  // first check if there is really something to spell check
  if(m_currentSpellCheckRange.isValid()) {
    m_sonnetDialog->show();
  }
}

void KateSpellCheckDialog::installNextSpellCheckRange()
{
  if ( m_spellCheckCancelledByUser
       || m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
  {
    spellCheckDone();
    return;
  }
  KateSpellCheckManager *spellCheckManager = KateGlobal::self()->spellCheckManager();
  KTextEditor::Cursor nextRangeBegin = (m_currentSpellCheckRange.isValid() ? m_currentSpellCheckRange.end()
                                                                           : KTextEditor::Cursor::invalid());
  m_currentSpellCheckRange = KTextEditor::Range::invalid();
  m_currentDecToEncOffsetList.clear();
  QList<QPair<KTextEditor::Range, QString> > rangeDictionaryPairList;
  while ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
  {
    const KTextEditor::Range& currentLanguageRange = (*m_currentLanguageRangeIterator).first;
    const QString& dictionary = (*m_currentLanguageRangeIterator).second;
    KTextEditor::Range languageSubRange = (nextRangeBegin.isValid() ? KTextEditor::Range(nextRangeBegin, currentLanguageRange.end())
                                                                    : currentLanguageRange);
    rangeDictionaryPairList = spellCheckManager->spellCheckWrtHighlightingRanges(m_view->doc(),
                                                                                languageSubRange,
                                                                                dictionary,
                                                                                false, true);
    Q_ASSERT(rangeDictionaryPairList.size() <= 1);
    if(rangeDictionaryPairList.size() == 0) {
      ++m_currentLanguageRangeIterator;
      if ( m_currentLanguageRangeIterator != m_languagesInSpellCheckRange.end() )
      {
        nextRangeBegin = (*m_currentLanguageRangeIterator).first.start();
      }
    }
    else {
      m_currentSpellCheckRange = rangeDictionaryPairList.first().first;
      const QString& dictionary = rangeDictionaryPairList.first().second;

      m_spellPosCursor = m_currentSpellCheckRange.start();
      m_spellLastPos = 0;

      m_currentDecToEncOffsetList.clear();
      KateDocument::OffsetList encToDecOffsetList;
      QString text = m_view->doc()->decodeCharacters(m_currentSpellCheckRange,
                                                     m_currentDecToEncOffsetList,
                                                     encToDecOffsetList);
      // ensure that no empty string is passed on to Sonnet as this can lead to a crash
      // (bug 228789)
      if(text.isEmpty()) {
        nextRangeBegin = m_currentSpellCheckRange.end();
        continue;
      }

      if(m_speller->language() != dictionary) {
        m_speller->setLanguage(dictionary);
        m_backgroundChecker->setSpeller(*m_speller);
      }

      m_sonnetDialog->setBuffer(text);
      break;
    }
  }
  if ( m_currentLanguageRangeIterator == m_languagesInSpellCheckRange.end() )
  {
    spellCheckDone();
    return;
  }
}

void KateSpellCheckDialog::cancelClicked()
{
  m_spellCheckCancelledByUser = true;
}

void KateSpellCheckDialog::spellCheckDone()
{
  m_currentSpellCheckRange = KTextEditor::Range::invalid();
  m_currentDecToEncOffsetList.clear();
  m_view->clearSelection();
}

void KateSpellCheckDialog::objectDestroyed(QObject *object)
{
  Q_UNUSED(object);
  m_sonnetDialog = NULL;
}

//END

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "stdafx.h"

#include <cerrno>
#include <cstdlib>

#include "util/cxx_util.h"
#include "util/string_util.h"

#include "integer.h"
#include "decimal.h"
#include "floatimpl.h"
#include "numconversions.h"

using namespace std;

#ifdef WIN32
namespace std {
  inline long long strtoll( char const *s, char **end, int base ) {
    return ::_strtoi64( s, end, base );
  }

  inline long long strtoull( char const *s, char **end, int base ) {
    return ::_strtoui64( s, end, base );
  }
}
#endif /* WIN32 */

namespace zorba {

///////////////////////////////////////////////////////////////////////////////

void Integer::parse( char const *s ) {
#ifdef ZORBA_WITH_BIG_INTEGER
  Decimal::parse( s, &value_, Decimal::parse_integer );
#else
  value_ = ztd::atoll( s );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

////////// constructors ///////////////////////////////////////////////////////

#ifdef ZORBA_WITH_BIG_INTEGER
Integer::Integer( long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}

Integer::Integer( unsigned long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}

Integer::Integer( unsigned long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer::Integer( Decimal const &d ) {
  value_ = ftoi( d.value_ );
}

Integer::Integer( Double const &d ) {
  if ( !d.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( d.getNumber() );
}

Integer::Integer( Float const &f ) {
  if ( !f.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( f.getNumber() );
}

////////// assignment operators ///////////////////////////////////////////////

#ifdef ZORBA_WITH_BIG_INTEGER
Integer& Integer::operator=( long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}

Integer& Integer::operator=( unsigned long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}

Integer& Integer::operator=( unsigned long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer& Integer::operator=( Decimal const &d ) {
  value_ = ftoi( d.value_ );
  return *this;
}

Integer& Integer::operator=( Double const &d ) {
  if ( !d.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( d.getNumber() );
  return *this;
}

Integer& Integer::operator=( Float const &f ) {
  if ( !f.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( f.getNumber() );
  return *this;
}

////////// arithmetic operators ///////////////////////////////////////////////

Decimal operator+( Integer const &i, Decimal const &d ) {
  return i.itod() + d.value_;
}

Decimal operator-( Integer const &i, Decimal const &d ) {
  return i.itod() - d.value_;
}

Decimal operator*( Integer const &i, Decimal const &d ) {
  return i.itod() * d.value_;
}

Decimal operator/( Integer const &i, Decimal const &d ) {
  return i.itod() / d.value_;
}

Decimal operator%( Integer const &i, Decimal const &d ) {
  return i.itod() % d.value_;
}

////////// relational operators ///////////////////////////////////////////////

bool operator==( Integer const &i, Decimal const &d ) {
  return d.is_integer() && i.itod() == d.value_;
}

bool operator!=( Integer const &i, Decimal const &d ) {
  return i.itod() != d.value_;
}

bool operator<( Integer const &i, Decimal const &d ) {
  return i.itod() < d.value_;
}

bool operator<=( Integer const &i, Decimal const &d ) {
  return i.itod() <= d.value_;
}

bool operator>( Integer const &i, Decimal const &d ) {
  return i.itod() > d.value_;
}

bool operator>=( Integer const &i, Decimal const &d ) {
  return i.itod() >= d.value_;
}

////////// math functions /////////////////////////////////////////////////////

Double Integer::pow( Integer const &power ) const {
#ifdef ZORBA_WITH_BIG_INTEGER
  value_type const result( value_.pow( power.value_, 15 ) );
  char buf[300];
  result.toFixPtString( buf, 15 );
  xs_double double_result;
  xs_double::parseString( buf, double_result );
  return double_result;
#else
  return Double(
    // The casts are needed for disambiguation with MSVC++.
    ::pow( static_cast<double>( value_ ), static_cast<double>( power.value_ ) )
  );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

Integer Integer::round( Integer const &precision ) const {
  return Integer( Decimal::round( itod(), precision.itod() ) );
}

Integer Integer::roundHalfToEven( Integer const &precision ) const {
  return Integer( Decimal::roundHalfToEven( itod(), precision.itod() ) );
}

////////// miscellaneous //////////////////////////////////////////////////////

#ifndef ZORBA_WITH_BIG_INTEGER
Integer::value_type Integer::ftoi( MAPM const &d ) {
  MAPM const temp( d.sign() >= 0 ? d.floor() : d.ceil() );
  char *const buf = new char[ temp.exponent() + 3 ];
  temp.toIntegerString( buf );
  value_type const result( std::strtoll( buf, nullptr, 10 ) );
  delete[] buf;
  return result;
}

MAPM Integer::itod() const {
  if ( is_long() )
    return static_cast<long>( value_ );
  ztd::itoa_buf_type buf;
  return ztd::itoa( value_, buf );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

#ifdef ZORBA_WITH_BIG_INTEGER
uint32_t Integer::hash() const {
  return Decimal::hash( value_ );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer const& Integer::one() {
  static Integer const i(1);
  return i;
}

zstring Integer::toString() const {
#ifdef ZORBA_WITH_BIG_INTEGER
  char *const buf = new char[ value_.exponent() + 3 ];
  value_.toIntegerString( buf );
  zstring const result( buf );
  delete[] buf;
  return result;
#else
  ztd::itoa_buf_type buf;
  return ztd::itoa( value_, buf );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

Integer const& Integer::zero() {
  static Integer const i(0);
  return i;
}

///////////////////////////////////////////////////////////////////////////////

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<commit_msg>fix the build with big nums<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "stdafx.h"

#include <cerrno>
#include <cstdlib>

#include "util/cxx_util.h"
#include "util/string_util.h"

#include "integer.h"
#include "decimal.h"
#include "floatimpl.h"
#include "numconversions.h"

using namespace std;

#ifdef WIN32
namespace std {
  inline long long strtoll( char const *s, char **end, int base ) {
    return ::_strtoi64( s, end, base );
  }

  inline long long strtoull( char const *s, char **end, int base ) {
    return ::_strtoui64( s, end, base );
  }
}
#endif /* WIN32 */

namespace zorba {

///////////////////////////////////////////////////////////////////////////////

void Integer::parse( char const *s ) {
#ifdef ZORBA_WITH_BIG_INTEGER
  Decimal::parse( s, &value_, Decimal::parse_integer );
#else
  value_ = ztd::atoll( s );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

////////// constructors ///////////////////////////////////////////////////////

#ifdef ZORBA_WITH_BIG_INTEGER
Integer::Integer( long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}

Integer::Integer( unsigned long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}

Integer::Integer( unsigned long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer::Integer( Decimal const &d ) {
  value_ = ftoi( d.value_ );
}

Integer::Integer( Double const &d ) {
  if ( !d.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( d.getNumber() );
}

Integer::Integer( Float const &f ) {
  if ( !f.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( f.getNumber() );
}

////////// assignment operators ///////////////////////////////////////////////

#ifdef ZORBA_WITH_BIG_INTEGER
Integer& Integer::operator=( long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}

Integer& Integer::operator=( unsigned long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}

Integer& Integer::operator=( unsigned long long n ) {
  ztd::itoa_buf_type buf;
  value_ = ztd::itoa( n, buf );
  return *this;
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer& Integer::operator=( Decimal const &d ) {
  value_ = ftoi( d.value_ );
  return *this;
}

Integer& Integer::operator=( Double const &d ) {
  if ( !d.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( d.getNumber() );
  return *this;
}

Integer& Integer::operator=( Float const &f ) {
  if ( !f.isFinite() )
    throw std::invalid_argument( "not finite" );
  value_ = ftoi( f.getNumber() );
  return *this;
}

////////// arithmetic operators ///////////////////////////////////////////////

Decimal operator+( Integer const &i, Decimal const &d ) {
  return i.itod() + d.value_;
}

Decimal operator-( Integer const &i, Decimal const &d ) {
  return i.itod() - d.value_;
}

Decimal operator*( Integer const &i, Decimal const &d ) {
  return i.itod() * d.value_;
}

Decimal operator/( Integer const &i, Decimal const &d ) {
  return i.itod() / d.value_;
}

Decimal operator%( Integer const &i, Decimal const &d ) {
  return i.itod() % d.value_;
}

////////// relational operators ///////////////////////////////////////////////

bool operator==( Integer const &i, Decimal const &d ) {
  return d.is_integer() && i.itod() == d.value_;
}

bool operator!=( Integer const &i, Decimal const &d ) {
  return i.itod() != d.value_;
}

bool operator<( Integer const &i, Decimal const &d ) {
  return i.itod() < d.value_;
}

bool operator<=( Integer const &i, Decimal const &d ) {
  return i.itod() <= d.value_;
}

bool operator>( Integer const &i, Decimal const &d ) {
  return i.itod() > d.value_;
}

bool operator>=( Integer const &i, Decimal const &d ) {
  return i.itod() >= d.value_;
}

////////// math functions /////////////////////////////////////////////////////

Double Integer::pow( Integer const &power ) const {
#ifdef ZORBA_WITH_BIG_INTEGER
  value_type const result( value_.pow( power.value_, 15 ) );
  char buf[300];
  result.toFixPtString( buf, 15 );
  return Double( buf );
#else
  return Double(
    // The casts are needed for disambiguation with MSVC++.
    ::pow( static_cast<double>( value_ ), static_cast<double>( power.value_ ) )
  );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

Integer Integer::round( Integer const &precision ) const {
  return Integer( Decimal::round( itod(), precision.itod() ) );
}

Integer Integer::roundHalfToEven( Integer const &precision ) const {
  return Integer( Decimal::roundHalfToEven( itod(), precision.itod() ) );
}

////////// miscellaneous //////////////////////////////////////////////////////

#ifndef ZORBA_WITH_BIG_INTEGER
Integer::value_type Integer::ftoi( MAPM const &d ) {
  MAPM const temp( d.sign() >= 0 ? d.floor() : d.ceil() );
  char *const buf = new char[ temp.exponent() + 3 ];
  temp.toIntegerString( buf );
  value_type const result( std::strtoll( buf, nullptr, 10 ) );
  delete[] buf;
  return result;
}

MAPM Integer::itod() const {
  if ( is_long() )
    return static_cast<long>( value_ );
  ztd::itoa_buf_type buf;
  return ztd::itoa( value_, buf );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

#ifdef ZORBA_WITH_BIG_INTEGER
uint32_t Integer::hash() const {
  return Decimal::hash( value_ );
}
#endif /* ZORBA_WITH_BIG_INTEGER */

Integer const& Integer::one() {
  static Integer const i(1);
  return i;
}

zstring Integer::toString() const {
#ifdef ZORBA_WITH_BIG_INTEGER
  char *const buf = new char[ value_.exponent() + 3 ];
  value_.toIntegerString( buf );
  zstring const result( buf );
  delete[] buf;
  return result;
#else
  ztd::itoa_buf_type buf;
  return ztd::itoa( value_, buf );
#endif /* ZORBA_WITH_BIG_INTEGER */
}

Integer const& Integer::zero() {
  static Integer const i(0);
  return i;
}

///////////////////////////////////////////////////////////////////////////////

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(TARGET_ARCH_ARM)

#include "vm/cpu.h"
#include "vm/cpu_arm.h"

#include "vm/compiler/assembler/assembler.h"
#include "vm/cpuinfo.h"
#include "vm/heap/heap.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/simulator.h"

#if defined(HOST_OS_IOS)
#include <libkern/OSCacheControl.h>
#endif

#if !defined(TARGET_HOST_MISMATCH)
#include <sys/syscall.h> /* NOLINT */
#include <unistd.h>      /* NOLINT */
#endif

// ARM version differences.
// We support two major 32-bit ARM ISA versions: ARMv6 and variants,
// and ARMv7 and variants. For each of these we detect the presence of vfp,
// neon, and integer division instructions. Considering ARMv5TE as the baseline,
// later versions add the following features/instructions that we use:
//
// ARMv6:
// - PC read offset in store instructions is 8 rather than 12, matching the
//   offset in read instructions,
// - strex, ldrex, and clrex load/store/clear exclusive instructions,
// - umaal multiplication instruction,
// ARMv7:
// - movw, movt 16-bit immediate load instructions,
// - mls multiplication instruction,
// - vmovs, vmovd floating point immediate load instructions.
//
// If an aarch64 CPU is detected, we generate ARMv7 code.
//
// If an instruction is missing on ARMv6, we emulate it, if possible.
// Where we are missing vfp, we do not unbox doubles, or generate intrinsics for
// floating point operations. Where we are missing neon, we do not unbox SIMD
// values, or inline operations on SIMD values. Where we are missing integer
// division, we do not inline division operations, and we do not generate
// intrinsics that do division. See the feature tests in flow_graph_optimizer.cc
// for details.
//
// Alignment:
//
// On ARMv6 and on, we assume that the kernel is set up to fixup unaligned
// accesses. This can be verified by checking /proc/cpu/alignment on modern
// Linux systems.

namespace dart {

#if defined(TARGET_ARCH_ARM_6)
DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
DEFINE_FLAG(bool,
            use_integer_division,
            false,
            "Use integer division instruction if supported");
#else
DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, true, "Use neon instructions if supported");
DEFINE_FLAG(bool,
            use_integer_division,
            true,
            "Use integer division instruction if supported");
#endif

#if defined(TARGET_HOST_MISMATCH)
#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_IOS)
DEFINE_FLAG(bool, sim_use_hardfp, false, "Use the hardfp ABI.");
#else
DEFINE_FLAG(bool, sim_use_hardfp, true, "Use the hardfp ABI.");
#endif
#endif

void CPU::FlushICache(uword start, uword size) {
#if defined(DART_PRECOMPILED_RUNTIME)
  UNREACHABLE();
#elif !defined(TARGET_HOST_MISMATCH) && HOST_ARCH_ARM
  // Nothing to do. Flushing no instructions.
  if (size == 0) {
    return;
  }

// ARM recommends using the gcc intrinsic __clear_cache on Linux, and the
// library call cacheflush from unistd.h on Android:
//
// https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/caches-and-self-modifying-code
//
// On iOS we use sys_icache_invalidate from Darwin. See:
//
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html
#if defined(HOST_OS_IOS)
  sys_icache_invalidate(reinterpret_cast<void*>(start), size);
#elif defined(__linux__) && !defined(ANDROID)
  extern void __clear_cache(char*, char*);
  char* beg = reinterpret_cast<char*>(start);
  char* end = reinterpret_cast<char*>(start + size);
  ::__clear_cache(beg, end);
#elif defined(ANDROID)
  cacheflush(start, start + size, 0);
#else
#error FlushICache only tested/supported on Linux, Android and iOS
#endif
#endif
}

const char* CPU::Id() {
  return
#if defined(TARGET_HOST_MISMATCH)
      "sim"
#endif  // defined(TARGET_HOST_MISMATCH)
      "arm";
}

bool HostCPUFeatures::integer_division_supported_ = false;
bool HostCPUFeatures::vfp_supported_ = false;
bool HostCPUFeatures::neon_supported_ = false;
bool HostCPUFeatures::hardfp_supported_ = false;
const char* HostCPUFeatures::hardware_ = NULL;
ARMVersion HostCPUFeatures::arm_version_ = ARMvUnknown;
intptr_t HostCPUFeatures::store_pc_read_offset_ = 8;
#if defined(DEBUG)
bool HostCPUFeatures::initialized_ = false;
#endif

#if !defined(TARGET_HOST_MISMATCH)
#if HOST_OS_IOS
void HostCPUFeatures::Init() {
  // TODO(24743): Actually check the CPU features and fail if we're missing
  // something assumed in a precompiled snapshot.
  hardware_ = "";
  // When the VM is targetted to ARMv7, pretend that the CPU is ARMv7 even if
  // the CPU is actually AArch64.
  arm_version_ = ARMv7;
  // Always assume we have floating point unit since we don't support ARMv6 in
  // this path.
  vfp_supported_ = FLAG_use_vfp;
  integer_division_supported_ = FLAG_use_integer_division;
  neon_supported_ = FLAG_use_neon;
  hardfp_supported_ = false;
#if defined(DEBUG)
  initialized_ = true;
#endif
}
#else  // HOST_OS_IOS
void HostCPUFeatures::Init() {
  bool is_arm64 = false;
  CpuInfo::Init();
  hardware_ = CpuInfo::GetCpuModel();

  // Check for ARMv6, ARMv7, or aarch64.
  // It can be in either the Processor or Model information fields.
  if (CpuInfo::FieldContains(kCpuInfoProcessor, "aarch64") ||
      CpuInfo::FieldContains(kCpuInfoModel, "aarch64") ||
      CpuInfo::FieldContains(kCpuInfoArchitecture, "8") ||
      CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64")) {
    // pretend that this arm64 cpu is really an ARMv7
    arm_version_ = ARMv7;
    is_arm64 = true;
  } else if (CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv6") ||
             CpuInfo::FieldContains(kCpuInfoModel, "ARMv6")) {
    // Raspberry Pi, etc.
    arm_version_ = ARMv6;
  } else if (CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv7") ||
             CpuInfo::FieldContains(kCpuInfoModel, "ARMv7")) {
    arm_version_ = ARMv7;
  } else {
#if defined(DART_RUN_IN_QEMU_ARMv7)
    arm_version_ = ARMv7;
#else
    FATAL("Unrecognized ARM CPU architecture.");
#endif
  }

  // Has floating point unit.
  vfp_supported_ =
      (CpuInfo::FieldContains(kCpuInfoFeatures, "vfp") || is_arm64) &&
      FLAG_use_vfp;

  // Has integer division.
  // Special cases:
  // - Qualcomm Krait CPUs (QCT APQ8064) in Nexus 4 and 7 incorrectly report
  //   that they lack integer division.
  // - Marvell Armada 370/XP incorrectly reports that it has integer division.
  bool is_krait = CpuInfo::FieldContains(kCpuInfoHardware, "QCT APQ8064");
  bool is_armada_370xp =
      CpuInfo::FieldContains(kCpuInfoHardware, "Marvell Armada 370/XP");
#if defined(HOST_OS_ANDROID)
  bool is_android = true;
#else
  bool is_android = false;
#endif
  if (is_krait) {
    integer_division_supported_ = FLAG_use_integer_division;
  } else if (is_android && is_arm64) {
    // Various Android ARM64 devices, including the Qualcomm Snapdragon 820/821
    // CPUs (MSM 8996 and MSM8996pro) in Xiaomi MI5 and Pixel lack integer
    // division even though ARMv8 requires it in A32. Instead of attempting to
    // track all of these devices, we conservatively disable use of integer
    // division on Android ARM64 devices.
    // TODO(29270): /proc/self/auxv might be more reliable here.
    integer_division_supported_ = false;
  } else if (is_armada_370xp) {
    integer_division_supported_ = false;
  } else {
    integer_division_supported_ =
        (CpuInfo::FieldContains(kCpuInfoFeatures, "idiva") || is_arm64) &&
        FLAG_use_integer_division;
  }
  neon_supported_ =
      (CpuInfo::FieldContains(kCpuInfoFeatures, "neon") || is_arm64) &&
      FLAG_use_vfp && FLAG_use_neon;

// Use the cross-compiler's predefined macros to determine whether we should
// use the hard or soft float ABI.
#if defined(__ARM_PCS_VFP)
  hardfp_supported_ = true;
#else
  hardfp_supported_ = false;
#endif

#if defined(DEBUG)
  initialized_ = true;
#endif
}
#endif  // HOST_OS_IOS

void HostCPUFeatures::Cleanup() {
  DEBUG_ASSERT(initialized_);
#if defined(DEBUG)
  initialized_ = false;
#endif
  ASSERT(hardware_ != NULL);
  free(const_cast<char*>(hardware_));
  hardware_ = NULL;
  CpuInfo::Cleanup();
}

#else

void HostCPUFeatures::Init() {
  CpuInfo::Init();
  hardware_ = CpuInfo::GetCpuModel();

#if defined(TARGET_ARCH_ARM_6)
  arm_version_ = ARMv6;
#else
  arm_version_ = ARMv7;
#endif

  integer_division_supported_ = FLAG_use_integer_division;
  vfp_supported_ = FLAG_use_vfp;
  neon_supported_ = FLAG_use_vfp && FLAG_use_neon;
  hardfp_supported_ = FLAG_sim_use_hardfp;
#if defined(DEBUG)
  initialized_ = true;
#endif
}

void HostCPUFeatures::Cleanup() {
  DEBUG_ASSERT(initialized_);
#if defined(DEBUG)
  initialized_ = false;
#endif
  ASSERT(hardware_ != NULL);
  free(const_cast<char*>(hardware_));
  hardware_ = NULL;
  CpuInfo::Cleanup();
}
#endif  // !defined(TARGET_HOST_MISMATCH)

}  // namespace dart

#endif  // defined TARGET_ARCH_ARM
<commit_msg>[vm] Extend cpu_arm.cc to support devices using ARMv8 in "Processor" field<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(TARGET_ARCH_ARM)

#include "vm/cpu.h"
#include "vm/cpu_arm.h"

#include "vm/compiler/assembler/assembler.h"
#include "vm/cpuinfo.h"
#include "vm/heap/heap.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/simulator.h"

#if defined(HOST_OS_IOS)
#include <libkern/OSCacheControl.h>
#endif

#if !defined(TARGET_HOST_MISMATCH)
#include <sys/syscall.h> /* NOLINT */
#include <unistd.h>      /* NOLINT */
#endif

// ARM version differences.
// We support two major 32-bit ARM ISA versions: ARMv6 and variants,
// and ARMv7 and variants. For each of these we detect the presence of vfp,
// neon, and integer division instructions. Considering ARMv5TE as the baseline,
// later versions add the following features/instructions that we use:
//
// ARMv6:
// - PC read offset in store instructions is 8 rather than 12, matching the
//   offset in read instructions,
// - strex, ldrex, and clrex load/store/clear exclusive instructions,
// - umaal multiplication instruction,
// ARMv7:
// - movw, movt 16-bit immediate load instructions,
// - mls multiplication instruction,
// - vmovs, vmovd floating point immediate load instructions.
//
// If an aarch64 CPU is detected, we generate ARMv7 code.
//
// If an instruction is missing on ARMv6, we emulate it, if possible.
// Where we are missing vfp, we do not unbox doubles, or generate intrinsics for
// floating point operations. Where we are missing neon, we do not unbox SIMD
// values, or inline operations on SIMD values. Where we are missing integer
// division, we do not inline division operations, and we do not generate
// intrinsics that do division. See the feature tests in flow_graph_optimizer.cc
// for details.
//
// Alignment:
//
// On ARMv6 and on, we assume that the kernel is set up to fixup unaligned
// accesses. This can be verified by checking /proc/cpu/alignment on modern
// Linux systems.

namespace dart {

#if defined(TARGET_ARCH_ARM_6)
DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
DEFINE_FLAG(bool,
            use_integer_division,
            false,
            "Use integer division instruction if supported");
#else
DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
DEFINE_FLAG(bool, use_neon, true, "Use neon instructions if supported");
DEFINE_FLAG(bool,
            use_integer_division,
            true,
            "Use integer division instruction if supported");
#endif

#if defined(TARGET_HOST_MISMATCH)
#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_IOS)
DEFINE_FLAG(bool, sim_use_hardfp, false, "Use the hardfp ABI.");
#else
DEFINE_FLAG(bool, sim_use_hardfp, true, "Use the hardfp ABI.");
#endif
#endif

void CPU::FlushICache(uword start, uword size) {
#if defined(DART_PRECOMPILED_RUNTIME)
  UNREACHABLE();
#elif !defined(TARGET_HOST_MISMATCH) && HOST_ARCH_ARM
  // Nothing to do. Flushing no instructions.
  if (size == 0) {
    return;
  }

// ARM recommends using the gcc intrinsic __clear_cache on Linux, and the
// library call cacheflush from unistd.h on Android:
//
// https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/caches-and-self-modifying-code
//
// On iOS we use sys_icache_invalidate from Darwin. See:
//
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html
#if defined(HOST_OS_IOS)
  sys_icache_invalidate(reinterpret_cast<void*>(start), size);
#elif defined(__linux__) && !defined(ANDROID)
  extern void __clear_cache(char*, char*);
  char* beg = reinterpret_cast<char*>(start);
  char* end = reinterpret_cast<char*>(start + size);
  ::__clear_cache(beg, end);
#elif defined(ANDROID)
  cacheflush(start, start + size, 0);
#else
#error FlushICache only tested/supported on Linux, Android and iOS
#endif
#endif
}

const char* CPU::Id() {
  return
#if defined(TARGET_HOST_MISMATCH)
      "sim"
#endif  // defined(TARGET_HOST_MISMATCH)
      "arm";
}

bool HostCPUFeatures::integer_division_supported_ = false;
bool HostCPUFeatures::vfp_supported_ = false;
bool HostCPUFeatures::neon_supported_ = false;
bool HostCPUFeatures::hardfp_supported_ = false;
const char* HostCPUFeatures::hardware_ = NULL;
ARMVersion HostCPUFeatures::arm_version_ = ARMvUnknown;
intptr_t HostCPUFeatures::store_pc_read_offset_ = 8;
#if defined(DEBUG)
bool HostCPUFeatures::initialized_ = false;
#endif

#if !defined(TARGET_HOST_MISMATCH)
#if HOST_OS_IOS
void HostCPUFeatures::Init() {
  // TODO(24743): Actually check the CPU features and fail if we're missing
  // something assumed in a precompiled snapshot.
  hardware_ = "";
  // When the VM is targetted to ARMv7, pretend that the CPU is ARMv7 even if
  // the CPU is actually AArch64.
  arm_version_ = ARMv7;
  // Always assume we have floating point unit since we don't support ARMv6 in
  // this path.
  vfp_supported_ = FLAG_use_vfp;
  integer_division_supported_ = FLAG_use_integer_division;
  neon_supported_ = FLAG_use_neon;
  hardfp_supported_ = false;
#if defined(DEBUG)
  initialized_ = true;
#endif
}
#else  // HOST_OS_IOS
void HostCPUFeatures::Init() {
  bool is_arm64 = false;
  CpuInfo::Init();
  hardware_ = CpuInfo::GetCpuModel();

  // Check for ARMv6, ARMv7, or aarch64.
  // It can be in either the Processor or Model information fields.
  if (CpuInfo::FieldContains(kCpuInfoProcessor, "aarch64") ||
      CpuInfo::FieldContains(kCpuInfoModel, "aarch64") ||
      CpuInfo::FieldContains(kCpuInfoArchitecture, "8") ||
      CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64")) {
    // pretend that this arm64 cpu is really an ARMv7
    arm_version_ = ARMv7;
    is_arm64 = true;
  } else if (CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv6") ||
             CpuInfo::FieldContains(kCpuInfoModel, "ARMv6")) {
    // Raspberry Pi, etc.
    arm_version_ = ARMv6;
  } else if (CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv7") ||
             CpuInfo::FieldContains(kCpuInfoModel, "ARMv7") ||
             CpuInfo::FieldContains(kCpuInfoArchitecture, "7")) {
    arm_version_ = ARMv7;
  } else {
#if defined(DART_RUN_IN_QEMU_ARMv7)
    arm_version_ = ARMv7;
#else
    FATAL("Unrecognized ARM CPU architecture.");
#endif
  }

  // Has floating point unit.
  vfp_supported_ =
      (CpuInfo::FieldContains(kCpuInfoFeatures, "vfp") || is_arm64) &&
      FLAG_use_vfp;

  // Has integer division.
  // Special cases:
  // - Qualcomm Krait CPUs (QCT APQ8064) in Nexus 4 and 7 incorrectly report
  //   that they lack integer division.
  // - Marvell Armada 370/XP incorrectly reports that it has integer division.
  bool is_krait = CpuInfo::FieldContains(kCpuInfoHardware, "QCT APQ8064");
  bool is_armada_370xp =
      CpuInfo::FieldContains(kCpuInfoHardware, "Marvell Armada 370/XP");
#if defined(HOST_OS_ANDROID)
  bool is_android = true;
#else
  bool is_android = false;
#endif
  if (is_krait) {
    integer_division_supported_ = FLAG_use_integer_division;
  } else if (is_android && is_arm64) {
    // Various Android ARM64 devices, including the Qualcomm Snapdragon 820/821
    // CPUs (MSM 8996 and MSM8996pro) in Xiaomi MI5 and Pixel lack integer
    // division even though ARMv8 requires it in A32. Instead of attempting to
    // track all of these devices, we conservatively disable use of integer
    // division on Android ARM64 devices.
    // TODO(29270): /proc/self/auxv might be more reliable here.
    integer_division_supported_ = false;
  } else if (is_armada_370xp) {
    integer_division_supported_ = false;
  } else {
    integer_division_supported_ =
        (CpuInfo::FieldContains(kCpuInfoFeatures, "idiva") || is_arm64) &&
        FLAG_use_integer_division;
  }
  neon_supported_ =
      (CpuInfo::FieldContains(kCpuInfoFeatures, "neon") || is_arm64) &&
      FLAG_use_vfp && FLAG_use_neon;

// Use the cross-compiler's predefined macros to determine whether we should
// use the hard or soft float ABI.
#if defined(__ARM_PCS_VFP)
  hardfp_supported_ = true;
#else
  hardfp_supported_ = false;
#endif

#if defined(DEBUG)
  initialized_ = true;
#endif
}
#endif  // HOST_OS_IOS

void HostCPUFeatures::Cleanup() {
  DEBUG_ASSERT(initialized_);
#if defined(DEBUG)
  initialized_ = false;
#endif
  ASSERT(hardware_ != NULL);
  free(const_cast<char*>(hardware_));
  hardware_ = NULL;
  CpuInfo::Cleanup();
}

#else

void HostCPUFeatures::Init() {
  CpuInfo::Init();
  hardware_ = CpuInfo::GetCpuModel();

#if defined(TARGET_ARCH_ARM_6)
  arm_version_ = ARMv6;
#else
  arm_version_ = ARMv7;
#endif

  integer_division_supported_ = FLAG_use_integer_division;
  vfp_supported_ = FLAG_use_vfp;
  neon_supported_ = FLAG_use_vfp && FLAG_use_neon;
  hardfp_supported_ = FLAG_sim_use_hardfp;
#if defined(DEBUG)
  initialized_ = true;
#endif
}

void HostCPUFeatures::Cleanup() {
  DEBUG_ASSERT(initialized_);
#if defined(DEBUG)
  initialized_ = false;
#endif
  ASSERT(hardware_ != NULL);
  free(const_cast<char*>(hardware_));
  hardware_ = NULL;
  CpuInfo::Cleanup();
}
#endif  // !defined(TARGET_HOST_MISMATCH)

}  // namespace dart

#endif  // defined TARGET_ARCH_ARM
<|endoftext|>


<commit_before><commit_msg>add capabilities initialization in GlDevice<commit_after><|endoftext|>