Beispiel #1
0
void BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB, BasicBlock *CopyBB,
                            ValueMapT &BBMap, ValueMapT &GlobalMap,
                            LoopToScevMapT &LTS) {
  Builder.SetInsertPoint(CopyBB->begin());
  EntryBB = &CopyBB->getParent()->getEntryBlock();

  for (Instruction &Inst : *BB)
    copyInstruction(Stmt, &Inst, BBMap, GlobalMap, LTS);

  // After a basic block was copied store all scalars that escape this block
  // in their alloca. First the scalars that have dependences inside the SCoP,
  // then the ones that might escape the SCoP.
  generateScalarStores(Stmt, BB, BBMap, GlobalMap);

  const Region &R = Stmt.getParent()->getRegion();
  for (Instruction &Inst : *BB)
    handleOutsideUsers(R, &Inst, BBMap[&Inst]);
}
Beispiel #2
0
void VectorBlockGenerator::copyInstruction(ScopStmt &Stmt,
                                           const Instruction *Inst,
                                           ValueMapT &VectorMap,
                                           VectorValueMapT &ScalarMaps) {
  // Terminator instructions control the control flow. They are explicitly
  // expressed in the clast and do not need to be copied.
  if (Inst->isTerminator())
    return;

  if (canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion()))
    return;

  if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
    generateLoad(Stmt, Load, VectorMap, ScalarMaps);
    return;
  }

  if (hasVectorOperands(Inst, VectorMap)) {
    if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
      copyStore(Stmt, Store, VectorMap, ScalarMaps);
      return;
    }

    if (const UnaryInstruction *Unary = dyn_cast<UnaryInstruction>(Inst)) {
      copyUnaryInst(Stmt, Unary, VectorMap, ScalarMaps);
      return;
    }

    if (const BinaryOperator *Binary = dyn_cast<BinaryOperator>(Inst)) {
      copyBinaryInst(Stmt, Binary, VectorMap, ScalarMaps);
      return;
    }

    // Falltrough: We generate scalar instructions, if we don't know how to
    // generate vector code.
  }

  copyInstScalarized(Stmt, Inst, VectorMap, ScalarMaps);
}
Beispiel #3
0
void BlockGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
                                          ValueMapT &BBMap,
                                          ValueMapT &GlobalMap) {
  const Region &R = Stmt.getParent()->getRegion();

  assert(Stmt.isBlockStmt() && BB == Stmt.getBasicBlock() &&
         "Region statements need to use the generateScalarStores() "
         "function in the RegionGenerator");

  // Set to remember a store to the phiops alloca of a PHINode. It is needed as
  // we might have multiple write accesses to the same PHI and while one is the
  // self write of the PHI (to the ScalarMap alloca) the other is the write to
  // the operand alloca (PHIOpMap).
  SmallPtrSet<PHINode *, 4> SeenPHIs;

  // Iterate over all accesses in the given statement.
  for (MemoryAccess *MA : Stmt) {

    // Skip non-scalar and read accesses.
    if (!MA->isScalar() || MA->isRead())
      continue;

    Instruction *ScalarBase = cast<Instruction>(MA->getBaseAddr());
    Instruction *ScalarInst = MA->getAccessInstruction();
    PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase);

    // Get the alloca node for the base instruction and the value we want to
    // store. In total there are 4 options:
    //  (1) The base is no PHI, hence it is a simple scalar def-use chain.
    //  (2) The base is a PHI,
    //      (a) and the write is caused by an operand in the block.
    //      (b) and it is the PHI self write (same as case (1)).
    //      (c) (2a) and (2b) are not distinguishable.
    // For case (1) and (2b) we get the alloca from the scalar map and the value
    // we want to store is initialized with the instruction attached to the
    // memory access. For case (2a) we get the alloca from the PHI operand map
    // and the value we want to store is initialized with the incoming value for
    // this block. The tricky case (2c) is when both (2a) and (2b) match. This
    // happens if the PHI operand is in the same block as the PHI. To handle
    // that we choose the alloca of (2a) first and (2b) for the next write
    // access to that PHI (there must be 2).
    Value *ScalarValue = nullptr;
    AllocaInst *ScalarAddr = nullptr;

    if (!ScalarBasePHI) {
      // Case (1)
      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
      ScalarValue = ScalarInst;
    } else {
      int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB);
      if (ScalarBasePHI != ScalarInst) {
        // Case (2a)
        assert(PHIIdx >= 0 && "Bad scalar write to PHI operand");
        SeenPHIs.insert(ScalarBasePHI);
        ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
        ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
      } else if (PHIIdx < 0) {
        // Case (2b)
        ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
        ScalarValue = ScalarInst;
      } else {
        // Case (2c)
        if (SeenPHIs.insert(ScalarBasePHI).second) {
          // First access ==> same as (2a)
          ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
          ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
        } else {
          // Second access ==> same as (2b)
          ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
          ScalarValue = ScalarInst;
        }
      }
    }

    ScalarValue =
        getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap);
    Builder.CreateStore(ScalarValue, ScalarAddr);
  }
}
Beispiel #4
0
void BlockGenerator::copyInstruction(ScopStmt &Stmt, const Instruction *Inst,
                                     ValueMapT &BBMap, ValueMapT &GlobalMap,
                                     LoopToScevMapT &LTS) {

  // First check for possible scalar dependences for this instruction.
  generateScalarLoads(Stmt, Inst, BBMap);

  // Terminator instructions control the control flow. They are explicitly
  // expressed in the clast and do not need to be copied.
  if (Inst->isTerminator())
    return;

  Loop *L = getLoopForInst(Inst);
  if ((Stmt.isBlockStmt() || !Stmt.getRegion()->contains(L)) &&
      canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion())) {
    Value *NewValue = getNewValue(Stmt, Inst, BBMap, GlobalMap, LTS, L);
    BBMap[Inst] = NewValue;
    return;
  }

  if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
    Value *NewLoad = generateScalarLoad(Stmt, Load, BBMap, GlobalMap, LTS);
    // Compute NewLoad before its insertion in BBMap to make the insertion
    // deterministic.
    BBMap[Load] = NewLoad;
    return;
  }

  if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
    Value *NewStore = generateScalarStore(Stmt, Store, BBMap, GlobalMap, LTS);
    // Compute NewStore before its insertion in BBMap to make the insertion
    // deterministic.
    BBMap[Store] = NewStore;
    return;
  }

  if (const PHINode *PHI = dyn_cast<PHINode>(Inst)) {
    copyPHIInstruction(Stmt, PHI, BBMap, GlobalMap, LTS);
    return;
  }

  // Skip some special intrinsics for which we do not adjust the semantics to
  // the new schedule. All others are handled like every other instruction.
  if (auto *IT = dyn_cast<IntrinsicInst>(Inst)) {
    switch (IT->getIntrinsicID()) {
    // Lifetime markers are ignored.
    case llvm::Intrinsic::lifetime_start:
    case llvm::Intrinsic::lifetime_end:
    // Invariant markers are ignored.
    case llvm::Intrinsic::invariant_start:
    case llvm::Intrinsic::invariant_end:
    // Some misc annotations are ignored.
    case llvm::Intrinsic::var_annotation:
    case llvm::Intrinsic::ptr_annotation:
    case llvm::Intrinsic::annotation:
    case llvm::Intrinsic::donothing:
    case llvm::Intrinsic::assume:
    case llvm::Intrinsic::expect:
      return;
    default:
      // Other intrinsics are copied.
      break;
    }
  }

  copyInstScalar(Stmt, Inst, BBMap, GlobalMap, LTS);
}
Beispiel #5
0
void RegionGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
                                           ValueMapT &BBMap,
                                           ValueMapT &GlobalMap) {
  const Region &R = Stmt.getParent()->getRegion();

  Region *StmtR = Stmt.getRegion();
  assert(StmtR && "Block statements need to use the generateScalarStores() "
                  "function in the BlockGenerator");

  BasicBlock *ExitBB = StmtR->getExit();

  // For region statements three kinds of scalar stores exists:
  //  (1) A definition used by a non-phi instruction outside the region.
  //  (2) A phi-instruction in the region entry.
  //  (3) A write to a phi instruction in the region exit.
  // The last case is the tricky one since we do not know anymore which
  // predecessor of the exit needs to store the operand value that doesn't
  // have a definition in the region. Therefore, we have to check in each
  // block in the region if we should store the value or not.

  // Iterate over all accesses in the given statement.
  for (MemoryAccess *MA : Stmt) {

    // Skip non-scalar and read accesses.
    if (!MA->isScalar() || MA->isRead())
      continue;

    Instruction *ScalarBase = cast<Instruction>(MA->getBaseAddr());
    Instruction *ScalarInst = MA->getAccessInstruction();
    PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase);

    Value *ScalarValue = nullptr;
    AllocaInst *ScalarAddr = nullptr;

    if (!ScalarBasePHI) {
      // Case (1)
      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
      ScalarValue = ScalarInst;
    } else if (ScalarBasePHI->getParent() != ExitBB) {
      // Case (2)
      assert(ScalarBasePHI->getParent() == StmtR->getEntry() &&
             "Bad PHI self write in non-affine region");
      assert(ScalarBase == ScalarInst &&
             "Bad PHI self write in non-affine region");
      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
      ScalarValue = ScalarInst;
    } else {
      int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB);
      // Skip accesses we will not handle in this basic block but in another one
      // in the statement region.
      if (PHIIdx < 0)
        continue;

      // Case (3)
      ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
      ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
    }

    ScalarValue =
        getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap);
    Builder.CreateStore(ScalarValue, ScalarAddr);
  }
}