text:
using namespace llvm;

#define DEBUG_TYPE "si-load-store-opt"

namespace {
enum InstClassEnum {
  UNKNOWN,
  DS_READ,
  DS_WRITE,
  S_BUFFER_LOAD_IMM,
  BUFFER_LOAD,
  BUFFER_STORE,
  MIMG,
};

enum RegisterEnum {
  SBASE = 0x1,
  SRSRC = 0x2,
  SOFFSET = 0x4,
  VADDR = 0x8,
  ADDR = 0x10,
  SSAMP = 0x20,
};

class SILoadStoreOptimizer : public MachineFunctionPass {
  struct CombineInfo {
    MachineBasicBlock::iterator I;
    MachineBasicBlock::iterator Paired;
    unsigned EltSize;
    unsigned Offset0;
    unsigned Offset1;
    unsigned Width0;
    unsigned Width1;
    unsigned BaseOff;
    unsigned DMask0;
    unsigned DMask1;
    InstClassEnum InstClass;
    bool GLC0;
    bool GLC1;
    bool SLC0;
    bool SLC1;
    bool DLC0;
    bool DLC1;
    bool UseST64;
    SmallVector<MachineInstr *, 8> InstsToMove;
    int AddrIdx[5];
    const MachineOperand *AddrReg[5];
    unsigned NumAddresses;

    bool hasSameBaseAddress(const MachineInstr &MI) {
      for (unsigned i = 0; i < NumAddresses; i++) {
        const MachineOperand &AddrRegNext = MI.getOperand(AddrIdx[i]);

        if (AddrReg[i]->isImm() || AddrRegNext.isImm()) {
          if (AddrReg[i]->isImm() != AddrRegNext.isImm() ||
              AddrReg[i]->getImm() != AddrRegNext.getImm()) {
            return false;
          }
          continue;
        }

        // Check same base pointer. Be careful of subregisters, which can occur
        // with vectors of pointers.
        if (AddrReg[i]->getReg() != AddrRegNext.getReg() ||
            AddrReg[i]->getSubReg() != AddrRegNext.getSubReg()) {
         return false;
        }
      }
      return true;
    }

    void setMI(MachineBasicBlock::iterator MI, const SIInstrInfo &TII,
               const GCNSubtarget &STM);
    void setPaired(MachineBasicBlock::iterator MI, const SIInstrInfo &TII);
  };

  struct BaseRegisters {
    unsigned LoReg = 0;
    unsigned HiReg = 0;

    unsigned LoSubReg = 0;
    unsigned HiSubReg = 0;
  };

  struct MemAddress {
    BaseRegisters Base;
    int64_t Offset = 0;
  };

  using MemInfoMap = DenseMap<MachineInstr *, MemAddress>;

private:
  const GCNSubtarget *STM = nullptr;
  const SIInstrInfo *TII = nullptr;
  const SIRegisterInfo *TRI = nullptr;
  MachineRegisterInfo *MRI = nullptr;
  AliasAnalysis *AA = nullptr;
  bool OptimizeAgain;

  bool dmasksCanBeCombined(const CombineInfo &CI);
  static bool offsetsCanBeCombined(CombineInfo &CI);
  static bool widthsFit(const GCNSubtarget &STM, const CombineInfo &CI);
  static unsigned getNewOpcode(const CombineInfo &CI);
  static std::pair<unsigned, unsigned> getSubRegIdxs(const CombineInfo &CI);
  const TargetRegisterClass *getTargetRegisterClass(const CombineInfo &CI);

  bool findMatchingInst(CombineInfo &CI);

  unsigned read2Opcode(unsigned EltSize) const;
  unsigned read2ST64Opcode(unsigned EltSize) const;
  MachineBasicBlock::iterator mergeRead2Pair(CombineInfo &CI);

  unsigned write2Opcode(unsigned EltSize) const;
  unsigned write2ST64Opcode(unsigned EltSize) const;
  MachineBasicBlock::iterator mergeWrite2Pair(CombineInfo &CI);
  MachineBasicBlock::iterator mergeImageSamplePair(CombineInfo &CI);
  MachineBasicBlock::iterator mergeSBufferLoadImmPair(CombineInfo &CI);
  MachineBasicBlock::iterator mergeBufferLoadPair(CombineInfo &CI);
  MachineBasicBlock::iterator mergeBufferStorePair(CombineInfo &CI);

  void updateBaseAndOffset(MachineInstr &I, unsigned NewBase,
                           int32_t NewOffset) const;
  unsigned computeBase(MachineInstr &MI, const MemAddress &Addr) const;
  MachineOperand createRegOrImm(int32_t Val, MachineInstr &MI) const;
  Optional<int32_t> extractConstOffset(const MachineOperand &Op) const;
  void processBaseWithConstOffset(const MachineOperand &Base, MemAddress &Addr) const;
  /// Promotes constant offset to the immediate by adjusting the base. It
  /// tries to use a base from the nearby instructions that allows it to have
  /// a 13bit constant offset which gets promoted to the immediate.
  bool promoteConstantOffsetToImm(MachineInstr &CI,
                                  MemInfoMap &Visited,
                                  SmallPtrSet<MachineInstr *, 4> &Promoted) const;

public:
  static char ID;

  SILoadStoreOptimizer() : MachineFunctionPass(ID) {
    initializeSILoadStoreOptimizerPass(*PassRegistry::getPassRegistry());
  }

  bool optimizeBlock(MachineBasicBlock &MBB);

  bool runOnMachineFunction(MachineFunction &MF) override;

  StringRef getPassName() const override { return "SI Load Store Optimizer"; }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    AU.addRequired<AAResultsWrapperPass>();

    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

static unsigned getOpcodeWidth(const MachineInstr &MI, const SIInstrInfo &TII) {
  const unsigned Opc = MI.getOpcode();

  if (TII.isMUBUF(Opc)) {
    // FIXME: Handle d16 correctly
    return AMDGPU::getMUBUFElements(Opc);
  }

  if (TII.isMIMG(MI)) {
    uint64_t DMaskImm =
        TII.getNamedOperand(MI, AMDGPU::OpName::dmask)->getImm();
    return countPopulation(DMaskImm);
  }

  switch (Opc) {
  case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
    return 1;
  case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
    return 2;
  case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
    return 4;
  default:
    return 0;
  }
}

/// Maps instruction opcode to enum InstClassEnum.
static InstClassEnum getInstClass(unsigned Opc, const SIInstrInfo &TII) {
  switch (Opc) {
  default:
    if (TII.isMUBUF(Opc)) {
      switch (AMDGPU::getMUBUFBaseOpcode(Opc)) {
      default:
        return UNKNOWN;
      case AMDGPU::BUFFER_LOAD_DWORD_OFFEN:
      case AMDGPU::BUFFER_LOAD_DWORD_OFFEN_exact:
      case AMDGPU::BUFFER_LOAD_DWORD_OFFSET:
      case AMDGPU::BUFFER_LOAD_DWORD_OFFSET_exact:
        return BUFFER_LOAD;
      case AMDGPU::BUFFER_STORE_DWORD_OFFEN:
      case AMDGPU::BUFFER_STORE_DWORD_OFFEN_exact:
      case AMDGPU::BUFFER_STORE_DWORD_OFFSET:
      case AMDGPU::BUFFER_STORE_DWORD_OFFSET_exact:
        return BUFFER_STORE;
      }
    } else if (TII.isMIMG(Opc)) {
      // Ignore instructions encoded without vaddr.
      if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vaddr) == -1)
        return UNKNOWN;
      if (!TII.get(Opc).mayLoad() || TII.isGather4(Opc))
        return UNKNOWN;
      return MIMG;
    }
    return UNKNOWN;
  case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
    return S_BUFFER_LOAD_IMM;
  case AMDGPU::DS_READ_B32:
  case AMDGPU::DS_READ_B32_gfx9:
  case AMDGPU::DS_READ_B64:
  case AMDGPU::DS_READ_B64_gfx9:
    return DS_READ;
  case AMDGPU::DS_WRITE_B32:
  case AMDGPU::DS_WRITE_B32_gfx9:
  case AMDGPU::DS_WRITE_B64:
  case AMDGPU::DS_WRITE_B64_gfx9:
    return DS_WRITE;
  }
}

/// Determines instruction subclass from opcode. Only instructions
/// of the same subclass can be merged together.
static unsigned getInstSubclass(unsigned Opc, const SIInstrInfo &TII) {
  switch (Opc) {
  default:
    if (TII.isMUBUF(Opc))
      return AMDGPU::getMUBUFBaseOpcode(Opc);
    if (TII.isMIMG(Opc)) {
      const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opc);
      assert(Info);
      return Info->BaseOpcode;
    }
    return -1;
  case AMDGPU::DS_READ_B32:
  case AMDGPU::DS_READ_B32_gfx9:
  case AMDGPU::DS_READ_B64:
  case AMDGPU::DS_READ_B64_gfx9:
  case AMDGPU::DS_WRITE_B32:
  case AMDGPU::DS_WRITE_B32_gfx9:
  case AMDGPU::DS_WRITE_B64:
  case AMDGPU::DS_WRITE_B64_gfx9:
    return Opc;
  case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
    return AMDGPU::S_BUFFER_LOAD_DWORD_IMM;
  }
}

static unsigned getRegs(unsigned Opc, const SIInstrInfo &TII) {
  if (TII.isMUBUF(Opc)) {
    unsigned result = 0;

    if (AMDGPU::getMUBUFHasVAddr(Opc)) {
      result |= VADDR;
    }

    if (AMDGPU::getMUBUFHasSrsrc(Opc)) {
      result |= SRSRC;
    }

    if (AMDGPU::getMUBUFHasSoffset(Opc)) {
      result |= SOFFSET;
    }

    return result;
  }

  if (TII.isMIMG(Opc)) {
    unsigned result = VADDR | SRSRC;
    const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(Opc);
    if (Info && AMDGPU::getMIMGBaseOpcodeInfo(Info->BaseOpcode)->Sampler)
      result |= SSAMP;
    return result;
  }

  switch (Opc) {
  default:
    return 0;
  case AMDGPU::S_BUFFER_LOAD_DWORD_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM:
  case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM:
    return SBASE;
  case AMDGPU::DS_READ_B32:
  case AMDGPU::DS_READ_B64:
  case AMDGPU::DS_READ_B32_gfx9:
  case AMDGPU::DS_READ_B64_gfx9:
  case AMDGPU::DS_WRITE_B32:
  case AMDGPU::DS_WRITE_B64:
  case AMDGPU::DS_WRITE_B32_gfx9:
  case AMDGPU::DS_WRITE_B64_gfx9:
    return ADDR;
  }
}

void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI,
                                              const SIInstrInfo &TII,
                                              const GCNSubtarget &STM) {
  I = MI;
  unsigned Opc = MI->getOpcode();
  InstClass = getInstClass(Opc, TII);

  if (InstClass == UNKNOWN)
    return;

  switch (InstClass) {
  case DS_READ:
   EltSize =
          (Opc == AMDGPU::DS_READ_B64 || Opc == AMDGPU::DS_READ_B64_gfx9) ? 8
                                                                          : 4;
   break;
  case DS_WRITE:
    EltSize =
          (Opc == AMDGPU::DS_WRITE_B64 || Opc == AMDGPU::DS_WRITE_B64_gfx9) ? 8
                                                                            : 4;
    break;
  case S_BUFFER_LOAD_IMM:
    EltSize = AMDGPU::getSMRDEncodedOffset(STM, 4);
    break;
  default:
    EltSize = 4;
    break;
  }

  if (InstClass == MIMG) {
    DMask0 = TII.getNamedOperand(*I, AMDGPU::OpName::dmask)->getImm();
  } else {
    int OffsetIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::offset);
    Offset0 = I->getOperand(OffsetIdx).getImm();
  }

  Width0 = getOpcodeWidth(*I, TII);

  if ((InstClass == DS_READ) || (InstClass == DS_WRITE)) {
    Offset0 &= 0xffff;
  } else if (InstClass != MIMG) {
    GLC0 = TII.getNamedOperand(*I, AMDGPU::OpName::glc)->getImm();
    if (InstClass != S_BUFFER_LOAD_IMM) {
      SLC0 = TII.getNamedOperand(*I, AMDGPU::OpName::slc)->getImm();
    }
    DLC0 = TII.getNamedOperand(*I, AMDGPU::OpName::dlc)->getImm();
  }

  unsigned AddrOpName[5] = {0};
  NumAddresses = 0;
  const unsigned Regs = getRegs(I->getOpcode(), TII);

  if (Regs & ADDR) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::addr;
  }

  if (Regs & SBASE) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::sbase;
  }

  if (Regs & SRSRC) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::srsrc;
  }

  if (Regs & SOFFSET) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::soffset;
  }

  if (Regs & VADDR) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::vaddr;
  }

  if (Regs & SSAMP) {
    AddrOpName[NumAddresses++] = AMDGPU::OpName::ssamp;
  }

  for (unsigned i = 0; i < NumAddresses; i++) {
    AddrIdx[i] = AMDGPU::getNamedOperandIdx(I->getOpcode(), AddrOpName[i]);
    AddrReg[i] = &I->getOperand(AddrIdx[i]);
  }
}

void SILoadStoreOptimizer::CombineInfo::setPaired(MachineBasicBlock::iterator MI,
                                                  const SIInstrInfo &TII) {
  Paired = MI;
  assert(InstClass == getInstClass(Paired->getOpcode(), TII));

  if (InstClass == MIMG) {
    DMask1 = TII.getNamedOperand(*Paired, AMDGPU::OpName::dmask)->getImm();
  } else {
    int OffsetIdx =
        AMDGPU::getNamedOperandIdx(I->getOpcode(), AMDGPU::OpName::offset);
    Offset1 = Paired->getOperand(OffsetIdx).getImm();
  }

  Width1 = getOpcodeWidth(*Paired, TII);
  if ((InstClass == DS_READ) || (InstClass == DS_WRITE)) {
    Offset1 &= 0xffff;
  } else if (InstClass != MIMG) {
    GLC1 = TII.getNamedOperand(*Paired, AMDGPU::OpName::glc)->getImm();
    if (InstClass != S_BUFFER_LOAD_IMM) {
      SLC1 = TII.getNamedOperand(*Paired, AMDGPU::OpName::slc)->getImm();
    }
    DLC1 = TII.getNamedOperand(*Paired, AMDGPU::OpName::dlc)->getImm();
  }
}

} // end anonymous namespace.

INITIALIZE_PASS_BEGIN(SILoadStoreOptimizer, DEBUG_TYPE,
                      "SI Load Store Optimizer", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(SILoadStoreOptimizer, DEBUG_TYPE, "SI Load Store Optimizer",
                    false, false)

char SILoadStoreOptimizer::ID = 0;

char &llvm::SILoadStoreOptimizerID = SILoadStoreOptimizer::ID;

FunctionPass *llvm::createSILoadStoreOptimizerPass() {
  return new SILoadStoreOptimizer();
}

static void moveInstsAfter(MachineBasicBlock::iterator I,
                           ArrayRef<MachineInstr *> InstsToMove) {
  MachineBasicBlock *MBB = I->getParent();
  ++I;
  for (MachineInstr *MI : InstsToMove) {
    MI->removeFromParent();
    MBB->insert(I, MI);
  }
}

static void addDefsUsesToList(const MachineInstr &MI,
                              DenseSet<unsigned> &RegDefs,
                              DenseSet<unsigned> &PhysRegUses) {
  for (const MachineOperand &Op : MI.operands()) {
    if (Op.isReg()) {
      if (Op.isDef())
        RegDefs.insert(Op.getReg());
      else if (Op.readsReg() && Register::isPhysicalRegister(Op.getReg()))
        PhysRegUses.insert(Op.getReg());
    }
  }
}

static bool memAccessesCanBeReordered(MachineBasicBlock::iterator A,
                                      MachineBasicBlock::iterator B,
                                      AliasAnalysis *AA) {
  // RAW or WAR - cannot reorder
  // WAW - cannot reorder
  // RAR - safe to reorder
  return !(A->mayStore() || B->mayStore()) || !A->mayAlias(AA, *B, true);
}

// Add MI and its defs to the lists if MI reads one of the defs that are
// already in the list. Returns true in that case.
static bool addToListsIfDependent(MachineInstr &MI, DenseSet<unsigned> &RegDefs,
                                  DenseSet<unsigned> &PhysRegUses,
                                  SmallVectorImpl<MachineInstr *> &Insts) {
  for (MachineOperand &Use : MI.operands()) {
    // If one of the defs is read, then there is a use of Def between I and the
    // instruction that I will potentially be merged with. We will need to move
    // this instruction after the merged instructions.
    //
    // Similarly, if there is a def which is read by an instruction that is to
    // be moved for merging, then we need to move the def-instruction as well.
    // This can only happen for physical registers such as M0; virtual
    // registers are in SSA form.
    if (Use.isReg() &&
        ((Use.readsReg() && RegDefs.count(Use.getReg())) ||
         (Use.isDef() && RegDefs.count(Use.getReg())) ||
         (Use.isDef() && Register::isPhysicalRegister(Use.getReg()) &&
          PhysRegUses.count(Use.getReg())))) {
      Insts.push_back(&MI);
      addDefsUsesToList(MI, RegDefs, PhysRegUses);
      return true;
    }
  }

  return false;
}

static bool canMoveInstsAcrossMemOp(MachineInstr &MemOp,
                                    ArrayRef<MachineInstr *> InstsToMove,
                                    AliasAnalysis *AA) {
  assert(MemOp.mayLoadOrStore());

  for (MachineInstr *InstToMove : InstsToMove) {
    if (!InstToMove->mayLoadOrStore())
      continue;
    if (!memAccessesCanBeReordered(MemOp, *InstToMove, AA))
      return false;
  }
  return true;
}

// This function assumes that \p A and \p B have are identical except for
// size and offset, and they referecne adjacent memory.
static MachineMemOperand *combineKnownAdjacentMMOs(MachineFunction &MF,
                                                   const MachineMemOperand *A,
                                                   const MachineMemOperand *B) {
  unsigned MinOffset = std::min(A->getOffset(), B->getOffset());
  unsigned Size = A->getSize() + B->getSize();
  // This function adds the offset parameter to the existing offset for A,
  // so we pass 0 here as the offset and then manually set it to the correct
  // value after the call.
  MachineMemOperand *MMO = MF.getMachineMemOperand(A, 0, Size);
  MMO->setOffset(MinOffset);
  return MMO;
}

bool SILoadStoreOptimizer::dmasksCanBeCombined(const CombineInfo &CI) {
  assert(CI.InstClass == MIMG);

  // Ignore instructions with tfe/lwe set.
  const auto *TFEOp = TII->getNamedOperand(*CI.I, AMDGPU::OpName::tfe);
  const auto *LWEOp = TII->getNamedOperand(*CI.I, AMDGPU::OpName::lwe);

  if ((TFEOp && TFEOp->getImm()) || (LWEOp && LWEOp->getImm()))
    return false;

  // Check other optional immediate operands for equality.
  unsigned OperandsToMatch[] = {AMDGPU::OpName::glc, AMDGPU::OpName::slc,
                                AMDGPU::OpName::d16, AMDGPU::OpName::unorm,
                                AMDGPU::OpName::da,  AMDGPU::OpName::r128};

  for (auto op : OperandsToMatch) {
    int Idx = AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), op);
    if (AMDGPU::getNamedOperandIdx(CI.Paired->getOpcode(), op) != Idx)
      return false;
    if (Idx != -1 &&
        CI.I->getOperand(Idx).getImm() != CI.Paired->getOperand(Idx).getImm())
      return false;
  }

  // Check DMask for overlaps.
  unsigned MaxMask = std::max(CI.DMask0, CI.DMask1);
  unsigned MinMask = std::min(CI.DMask0, CI.DMask1);

  unsigned AllowedBitsForMin = llvm::countTrailingZeros(MaxMask);
  if ((1u << AllowedBitsForMin) <= MinMask)
    return false;

  return true;
}

bool SILoadStoreOptimizer::offsetsCanBeCombined(CombineInfo &CI) {
  assert(CI.InstClass != MIMG);

  // XXX - Would the same offset be OK? Is there any reason this would happen or
  // be useful?
  if (CI.Offset0 == CI.Offset1)
    return false;

  // This won't be valid if the offset isn't aligned.
  if ((CI.Offset0 % CI.EltSize != 0) || (CI.Offset1 % CI.EltSize != 0))
    return false;

  unsigned EltOffset0 = CI.Offset0 / CI.EltSize;
  unsigned EltOffset1 = CI.Offset1 / CI.EltSize;
  CI.UseST64 = false;
  CI.BaseOff = 0;

  // Handle SMEM and VMEM instructions.
  if ((CI.InstClass != DS_READ) && (CI.InstClass != DS_WRITE)) {
    return (EltOffset0 + CI.Width0 == EltOffset1 ||
            EltOffset1 + CI.Width1 == EltOffset0) &&
           CI.GLC0 == CI.GLC1 && CI.DLC0 == CI.DLC1 &&
           (CI.InstClass == S_BUFFER_LOAD_IMM || CI.SLC0 == CI.SLC1);
  }

  // If the offset in elements doesn't fit in 8-bits, we might be able to use
  // the stride 64 versions.
  if ((EltOffset0 % 64 == 0) && (EltOffset1 % 64) == 0 &&
      isUInt<8>(EltOffset0 / 64) && isUInt<8>(EltOffset1 / 64)) {
    CI.Offset0 = EltOffset0 / 64;
    CI.Offset1 = EltOffset1 / 64;
    CI.UseST64 = true;
    return true;
  }

  // Check if the new offsets fit in the reduced 8-bit range.
  if (isUInt<8>(EltOffset0) && isUInt<8>(EltOffset1)) {
    CI.Offset0 = EltOffset0;
    CI.Offset1 = EltOffset1;
    return true;
  }

  // Try to shift base address to decrease offsets.
  unsigned OffsetDiff = std::abs((int)EltOffset1 - (int)EltOffset0);
  CI.BaseOff = std::min(CI.Offset0, CI.Offset1);

  if ((OffsetDiff % 64 == 0) && isUInt<8>(OffsetDiff / 64)) {
    CI.Offset0 = (EltOffset0 - CI.BaseOff / CI.EltSize) / 64;
    CI.Offset1 = (EltOffset1 - CI.BaseOff / CI.EltSize) / 64;
    CI.UseST64 = true;
    return true;
  }

  if (isUInt<8>(OffsetDiff)) {
    CI.Offset0 = EltOffset0 - CI.BaseOff / CI.EltSize;
    CI.Offset1 = EltOffset1 - CI.BaseOff / CI.EltSize;
    return true;
  }

  return false;
}

bool SILoadStoreOptimizer::widthsFit(const GCNSubtarget &STM,
                                     const CombineInfo &CI) {
  const unsigned Width = (CI.Width0 + CI.Width1);
  switch (CI.InstClass) {
  default:
    return (Width <= 4) && (STM.hasDwordx3LoadStores() || (Width != 3));
  case S_BUFFER_LOAD_IMM:
    switch (Width) {
    default:
      return false;
    case 2:
    case 4:
      return true;
    }
  }
}

bool SILoadStoreOptimizer::findMatchingInst(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();
  MachineBasicBlock::iterator E = MBB->end();
  MachineBasicBlock::iterator MBBI = CI.I;

  const unsigned Opc = CI.I->getOpcode();
  const InstClassEnum InstClass = getInstClass(Opc, *TII);

  if (InstClass == UNKNOWN) {
    return false;
  }
  const unsigned InstSubclass = getInstSubclass(Opc, *TII);

  for (unsigned i = 0; i < CI.NumAddresses; i++) {
    // We only ever merge operations with the same base address register, so
    // don't bother scanning forward if there are no other uses.
    if (CI.AddrReg[i]->isReg() &&
        (Register::isPhysicalRegister(CI.AddrReg[i]->getReg()) ||
         MRI->hasOneNonDBGUse(CI.AddrReg[i]->getReg())))
      return false;
  }

  ++MBBI;

  DenseSet<unsigned> RegDefsToMove;
  DenseSet<unsigned> PhysRegUsesToMove;
  addDefsUsesToList(*CI.I, RegDefsToMove, PhysRegUsesToMove);

  for (; MBBI != E; ++MBBI) {

    if ((getInstClass(MBBI->getOpcode(), *TII) != InstClass) ||
        (getInstSubclass(MBBI->getOpcode(), *TII) != InstSubclass)) {
      // This is not a matching DS instruction, but we can keep looking as
      // long as one of these conditions are met:
      // 1. It is safe to move I down past MBBI.
      // 2. It is safe to move MBBI down past the instruction that I will
      //    be merged into.

      if (MBBI->hasUnmodeledSideEffects()) {
        // We can't re-order this instruction with respect to other memory
        // operations, so we fail both conditions mentioned above.
        return false;
      }

      if (MBBI->mayLoadOrStore() &&
          (!memAccessesCanBeReordered(*CI.I, *MBBI, AA) ||
           !canMoveInstsAcrossMemOp(*MBBI, CI.InstsToMove, AA))) {
        // We fail condition #1, but we may still be able to satisfy condition
        // #2.  Add this instruction to the move list and then we will check
        // if condition #2 holds once we have selected the matching instruction.
        CI.InstsToMove.push_back(&*MBBI);
        addDefsUsesToList(*MBBI, RegDefsToMove, PhysRegUsesToMove);
        continue;
      }

      // When we match I with another DS instruction we will be moving I down
      // to the location of the matched instruction any uses of I will need to
      // be moved down as well.
      addToListsIfDependent(*MBBI, RegDefsToMove, PhysRegUsesToMove,
                            CI.InstsToMove);
      continue;
    }

    // Don't merge volatiles.
    if (MBBI->hasOrderedMemoryRef())
      return false;

    // Handle a case like
    //   DS_WRITE_B32 addr, v, idx0
    //   w = DS_READ_B32 addr, idx0
    //   DS_WRITE_B32 addr, f(w), idx1
    // where the DS_READ_B32 ends up in InstsToMove and therefore prevents
    // merging of the two writes.
    if (addToListsIfDependent(*MBBI, RegDefsToMove, PhysRegUsesToMove,
                              CI.InstsToMove))
      continue;

    bool Match = CI.hasSameBaseAddress(*MBBI);

    if (Match) {
      CI.setPaired(MBBI, *TII);

      // Check both offsets (or masks for MIMG) fit in the reduced
      // range.
      bool canBeCombined =
          CI.InstClass == MIMG
              ? dmasksCanBeCombined(CI)
              : widthsFit(*STM, CI) && offsetsCanBeCombined(CI);

      // Check both offsets fit in the reduced range.
      // We also need to go through the list of instructions that we plan to
      // move and make sure they are all safe to move down past the merged
      // instruction.
      if (canBeCombined && canMoveInstsAcrossMemOp(*MBBI, CI.InstsToMove, AA))
        return true;
    }

    // We've found a load/store that we couldn't merge for some reason.
    // We could potentially keep looking, but we'd need to make sure that
    // it was safe to move I and also all the instruction in InstsToMove
    // down past this instruction.
    // check if we can move I across MBBI and if we can move all I's users
    if (!memAccessesCanBeReordered(*CI.I, *MBBI, AA) ||
        !canMoveInstsAcrossMemOp(*MBBI, CI.InstsToMove, AA))
      break;
  }
  return false;
}

unsigned SILoadStoreOptimizer::read2Opcode(unsigned EltSize) const {
  if (STM->ldsRequiresM0Init())
    return (EltSize == 4) ? AMDGPU::DS_READ2_B32 : AMDGPU::DS_READ2_B64;
  return (EltSize == 4) ? AMDGPU::DS_READ2_B32_gfx9 : AMDGPU::DS_READ2_B64_gfx9;
}

unsigned SILoadStoreOptimizer::read2ST64Opcode(unsigned EltSize) const {
  if (STM->ldsRequiresM0Init())
    return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32 : AMDGPU::DS_READ2ST64_B64;

  return (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32_gfx9
                        : AMDGPU::DS_READ2ST64_B64_gfx9;
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeRead2Pair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();

  // Be careful, since the addresses could be subregisters themselves in weird
  // cases, like vectors of pointers.
  const auto *AddrReg = TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);

  const auto *Dest0 = TII->getNamedOperand(*CI.I, AMDGPU::OpName::vdst);
  const auto *Dest1 = TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::vdst);

  unsigned NewOffset0 = CI.Offset0;
  unsigned NewOffset1 = CI.Offset1;
  unsigned Opc =
      CI.UseST64 ? read2ST64Opcode(CI.EltSize) : read2Opcode(CI.EltSize);

  unsigned SubRegIdx0 = (CI.EltSize == 4) ? AMDGPU::sub0 : AMDGPU::sub0_sub1;
  unsigned SubRegIdx1 = (CI.EltSize == 4) ? AMDGPU::sub1 : AMDGPU::sub2_sub3;

  if (NewOffset0 > NewOffset1) {
    // Canonicalize the merged instruction so the smaller offset comes first.
    std::swap(NewOffset0, NewOffset1);
    std::swap(SubRegIdx0, SubRegIdx1);
  }

  assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
         (NewOffset0 != NewOffset1) && "Computed offset doesn't fit");

  const MCInstrDesc &Read2Desc = TII->get(Opc);

  const TargetRegisterClass *SuperRC =
      (CI.EltSize == 4) ? &AMDGPU::VReg_64RegClass : &AMDGPU::VReg_128RegClass;
  Register DestReg = MRI->createVirtualRegister(SuperRC);

  DebugLoc DL = CI.I->getDebugLoc();

  Register BaseReg = AddrReg->getReg();
  unsigned BaseSubReg = AddrReg->getSubReg();
  unsigned BaseRegFlags = 0;
  if (CI.BaseOff) {
    Register ImmReg = MRI->createVirtualRegister(&AMDGPU::SGPR_32RegClass);
    BuildMI(*MBB, CI.Paired, DL, TII->get(AMDGPU::S_MOV_B32), ImmReg)
        .addImm(CI.BaseOff);

    BaseReg = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
    BaseRegFlags = RegState::Kill;

    TII->getAddNoCarry(*MBB, CI.Paired, DL, BaseReg)
        .addReg(ImmReg)
        .addReg(AddrReg->getReg(), 0, BaseSubReg)
        .addImm(0); // clamp bit
    BaseSubReg = 0;
  }

  MachineInstrBuilder Read2 =
      BuildMI(*MBB, CI.Paired, DL, Read2Desc, DestReg)
          .addReg(BaseReg, BaseRegFlags, BaseSubReg) // addr
          .addImm(NewOffset0)                        // offset0
          .addImm(NewOffset1)                        // offset1
          .addImm(0)                                 // gds
          .cloneMergedMemRefs({&*CI.I, &*CI.Paired});

  (void)Read2;

  const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);

  // Copy to the old destination registers.
  BuildMI(*MBB, CI.Paired, DL, CopyDesc)
      .add(*Dest0) // Copy to same destination including flags and sub reg.
      .addReg(DestReg, 0, SubRegIdx0);
  MachineInstr *Copy1 = BuildMI(*MBB, CI.Paired, DL, CopyDesc)
                            .add(*Dest1)
                            .addReg(DestReg, RegState::Kill, SubRegIdx1);

  moveInstsAfter(Copy1, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();

  LLVM_DEBUG(dbgs() << "Inserted read2: " << *Read2 << '\n');
  return Next;
}

unsigned SILoadStoreOptimizer::write2Opcode(unsigned EltSize) const {
  if (STM->ldsRequiresM0Init())
    return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32 : AMDGPU::DS_WRITE2_B64;
  return (EltSize == 4) ? AMDGPU::DS_WRITE2_B32_gfx9
                        : AMDGPU::DS_WRITE2_B64_gfx9;
}

unsigned SILoadStoreOptimizer::write2ST64Opcode(unsigned EltSize) const {
  if (STM->ldsRequiresM0Init())
    return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32
                          : AMDGPU::DS_WRITE2ST64_B64;

  return (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32_gfx9
                        : AMDGPU::DS_WRITE2ST64_B64_gfx9;
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeWrite2Pair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();

  // Be sure to use .addOperand(), and not .addReg() with these. We want to be
  // sure we preserve the subregister index and any register flags set on them.
  const MachineOperand *AddrReg =
      TII->getNamedOperand(*CI.I, AMDGPU::OpName::addr);
  const MachineOperand *Data0 =
      TII->getNamedOperand(*CI.I, AMDGPU::OpName::data0);
  const MachineOperand *Data1 =
      TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::data0);

  unsigned NewOffset0 = CI.Offset0;
  unsigned NewOffset1 = CI.Offset1;
  unsigned Opc =
      CI.UseST64 ? write2ST64Opcode(CI.EltSize) : write2Opcode(CI.EltSize);

  if (NewOffset0 > NewOffset1) {
    // Canonicalize the merged instruction so the smaller offset comes first.
    std::swap(NewOffset0, NewOffset1);
    std::swap(Data0, Data1);
  }

  assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
         (NewOffset0 != NewOffset1) && "Computed offset doesn't fit");

  const MCInstrDesc &Write2Desc = TII->get(Opc);
  DebugLoc DL = CI.I->getDebugLoc();

  Register BaseReg = AddrReg->getReg();
  unsigned BaseSubReg = AddrReg->getSubReg();
  unsigned BaseRegFlags = 0;
  if (CI.BaseOff) {
    Register ImmReg = MRI->createVirtualRegister(&AMDGPU::SGPR_32RegClass);
    BuildMI(*MBB, CI.Paired, DL, TII->get(AMDGPU::S_MOV_B32), ImmReg)
        .addImm(CI.BaseOff);

    BaseReg = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
    BaseRegFlags = RegState::Kill;

    TII->getAddNoCarry(*MBB, CI.Paired, DL, BaseReg)
        .addReg(ImmReg)
        .addReg(AddrReg->getReg(), 0, BaseSubReg)
        .addImm(0); // clamp bit
    BaseSubReg = 0;
  }

  MachineInstrBuilder Write2 =
      BuildMI(*MBB, CI.Paired, DL, Write2Desc)
          .addReg(BaseReg, BaseRegFlags, BaseSubReg) // addr
          .add(*Data0)                               // data0
          .add(*Data1)                               // data1
          .addImm(NewOffset0)                        // offset0
          .addImm(NewOffset1)                        // offset1
          .addImm(0)                                 // gds
          .cloneMergedMemRefs({&*CI.I, &*CI.Paired});

  moveInstsAfter(Write2, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();

  LLVM_DEBUG(dbgs() << "Inserted write2 inst: " << *Write2 << '\n');
  return Next;
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeImageSamplePair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();
  DebugLoc DL = CI.I->getDebugLoc();
  const unsigned Opcode = getNewOpcode(CI);

  const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI);

  unsigned DestReg = MRI->createVirtualRegister(SuperRC);
  unsigned MergedDMask = CI.DMask0 | CI.DMask1;
  unsigned DMaskIdx =
      AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), AMDGPU::OpName::dmask);

  auto MIB = BuildMI(*MBB, CI.Paired, DL, TII->get(Opcode), DestReg);
  for (unsigned I = 1, E = (*CI.I).getNumOperands(); I != E; ++I) {
    (I == DMaskIdx) ? MIB.addImm(MergedDMask) : MIB.add((*CI.I).getOperand(I));
  }
  MIB.cloneMergedMemRefs({&*CI.I, &*CI.Paired});

  std::pair<unsigned, unsigned> SubRegIdx = getSubRegIdxs(CI);
  const unsigned SubRegIdx0 = std::get<0>(SubRegIdx);
  const unsigned SubRegIdx1 = std::get<1>(SubRegIdx);

  // Copy to the old destination registers.
  const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);
  const auto *Dest0 = TII->getNamedOperand(*CI.I, AMDGPU::OpName::vdata);
  const auto *Dest1 = TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::vdata);

  BuildMI(*MBB, CI.Paired, DL, CopyDesc)
      .add(*Dest0) // Copy to same destination including flags and sub reg.
      .addReg(DestReg, 0, SubRegIdx0);
  MachineInstr *Copy1 = BuildMI(*MBB, CI.Paired, DL, CopyDesc)
                            .add(*Dest1)
                            .addReg(DestReg, RegState::Kill, SubRegIdx1);

  moveInstsAfter(Copy1, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();
  return Next;
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeSBufferLoadImmPair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();
  DebugLoc DL = CI.I->getDebugLoc();
  const unsigned Opcode = getNewOpcode(CI);

  const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI);

  Register DestReg = MRI->createVirtualRegister(SuperRC);
  unsigned MergedOffset = std::min(CI.Offset0, CI.Offset1);

  // It shouldn't be possible to get this far if the two instructions
  // don't have a single memoperand, because MachineInstr::mayAlias()
  // will return true if this is the case.
  assert(CI.I->hasOneMemOperand() && CI.Paired->hasOneMemOperand());

  const MachineMemOperand *MMOa = *CI.I->memoperands_begin();
  const MachineMemOperand *MMOb = *CI.Paired->memoperands_begin();

  BuildMI(*MBB, CI.Paired, DL, TII->get(Opcode), DestReg)
      .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::sbase))
      .addImm(MergedOffset) // offset
      .addImm(CI.GLC0)      // glc
      .addImm(CI.DLC0)      // dlc
      .addMemOperand(combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb));

  std::pair<unsigned, unsigned> SubRegIdx = getSubRegIdxs(CI);
  const unsigned SubRegIdx0 = std::get<0>(SubRegIdx);
  const unsigned SubRegIdx1 = std::get<1>(SubRegIdx);

  // Copy to the old destination registers.
  const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);
  const auto *Dest0 = TII->getNamedOperand(*CI.I, AMDGPU::OpName::sdst);
  const auto *Dest1 = TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::sdst);

  BuildMI(*MBB, CI.Paired, DL, CopyDesc)
      .add(*Dest0) // Copy to same destination including flags and sub reg.
      .addReg(DestReg, 0, SubRegIdx0);
  MachineInstr *Copy1 = BuildMI(*MBB, CI.Paired, DL, CopyDesc)
                            .add(*Dest1)
                            .addReg(DestReg, RegState::Kill, SubRegIdx1);

  moveInstsAfter(Copy1, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();
  return Next;
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeBufferLoadPair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();
  DebugLoc DL = CI.I->getDebugLoc();

  const unsigned Opcode = getNewOpcode(CI);

  const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI);

  // Copy to the new source register.
  Register DestReg = MRI->createVirtualRegister(SuperRC);
  unsigned MergedOffset = std::min(CI.Offset0, CI.Offset1);

  auto MIB = BuildMI(*MBB, CI.Paired, DL, TII->get(Opcode), DestReg);

  const unsigned Regs = getRegs(Opcode, *TII);

  if (Regs & VADDR)
    MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));

  // It shouldn't be possible to get this far if the two instructions
  // don't have a single memoperand, because MachineInstr::mayAlias()
  // will return true if this is the case.
  assert(CI.I->hasOneMemOperand() && CI.Paired->hasOneMemOperand());

  const MachineMemOperand *MMOa = *CI.I->memoperands_begin();
  const MachineMemOperand *MMOb = *CI.Paired->memoperands_begin();

  MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
      .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
      .addImm(MergedOffset) // offset
      .addImm(CI.GLC0)      // glc
      .addImm(CI.SLC0)      // slc
      .addImm(0)            // tfe
      .addImm(CI.DLC0)      // dlc
      .addMemOperand(combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb));

  std::pair<unsigned, unsigned> SubRegIdx = getSubRegIdxs(CI);
  const unsigned SubRegIdx0 = std::get<0>(SubRegIdx);
  const unsigned SubRegIdx1 = std::get<1>(SubRegIdx);

  // Copy to the old destination registers.
  const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);
  const auto *Dest0 = TII->getNamedOperand(*CI.I, AMDGPU::OpName::vdata);
  const auto *Dest1 = TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::vdata);

  BuildMI(*MBB, CI.Paired, DL, CopyDesc)
      .add(*Dest0) // Copy to same destination including flags and sub reg.
      .addReg(DestReg, 0, SubRegIdx0);
  MachineInstr *Copy1 = BuildMI(*MBB, CI.Paired, DL, CopyDesc)
                            .add(*Dest1)
                            .addReg(DestReg, RegState::Kill, SubRegIdx1);

  moveInstsAfter(Copy1, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();
  return Next;
}

unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI) {
  const unsigned Width = CI.Width0 + CI.Width1;

  switch (CI.InstClass) {
  default:
    assert(CI.InstClass == BUFFER_LOAD || CI.InstClass == BUFFER_STORE);
    // FIXME: Handle d16 correctly
    return AMDGPU::getMUBUFOpcode(AMDGPU::getMUBUFBaseOpcode(CI.I->getOpcode()),
                                  Width);
  case UNKNOWN:
    llvm_unreachable("Unknown instruction class");
  case S_BUFFER_LOAD_IMM:
    switch (Width) {
    default:
      return 0;
    case 2:
      return AMDGPU::S_BUFFER_LOAD_DWORDX2_IMM;
    case 4:
      return AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM;
    }
  case MIMG:
    assert("No overlaps" && (countPopulation(CI.DMask0 | CI.DMask1) == Width));
    return AMDGPU::getMaskedMIMGOp(CI.I->getOpcode(), Width);
  }
}

std::pair<unsigned, unsigned>
SILoadStoreOptimizer::getSubRegIdxs(const CombineInfo &CI) {

  if (CI.Width0 == 0 || CI.Width0 == 0 || CI.Width0 + CI.Width1 > 4)
    return std::make_pair(0, 0);

  bool ReverseOrder;
  if (CI.InstClass == MIMG) {
    assert((countPopulation(CI.DMask0 | CI.DMask1) == CI.Width0 + CI.Width1) &&
           "No overlaps");
    ReverseOrder = CI.DMask0 > CI.DMask1;
  } else
    ReverseOrder = CI.Offset0 > CI.Offset1;

  static const unsigned Idxs[4][4] = {
      {AMDGPU::sub0, AMDGPU::sub0_sub1, AMDGPU::sub0_sub1_sub2, AMDGPU::sub0_sub1_sub2_sub3},
      {AMDGPU::sub1, AMDGPU::sub1_sub2, AMDGPU::sub1_sub2_sub3, 0},
      {AMDGPU::sub2, AMDGPU::sub2_sub3, 0, 0},
      {AMDGPU::sub3, 0, 0, 0},
  };
  unsigned Idx0;
  unsigned Idx1;

  assert(CI.Width0 >= 1 && CI.Width0 <= 3);
  assert(CI.Width1 >= 1 && CI.Width1 <= 3);

  if (ReverseOrder) {
    Idx1 = Idxs[0][CI.Width1 - 1];
    Idx0 = Idxs[CI.Width1][CI.Width0 - 1];
  } else {
    Idx0 = Idxs[0][CI.Width0 - 1];
    Idx1 = Idxs[CI.Width0][CI.Width1 - 1];
  }

  return std::make_pair(Idx0, Idx1);
}

const TargetRegisterClass *
SILoadStoreOptimizer::getTargetRegisterClass(const CombineInfo &CI) {
  if (CI.InstClass == S_BUFFER_LOAD_IMM) {
    switch (CI.Width0 + CI.Width1) {
    default:
      return nullptr;
    case 2:
      return &AMDGPU::SReg_64_XEXECRegClass;
    case 4:
      return &AMDGPU::SReg_128RegClass;
    case 8:
      return &AMDGPU::SReg_256RegClass;
    case 16:
      return &AMDGPU::SReg_512RegClass;
    }
  } else {
    switch (CI.Width0 + CI.Width1) {
    default:
      return nullptr;
    case 2:
      return &AMDGPU::VReg_64RegClass;
    case 3:
      return &AMDGPU::VReg_96RegClass;
    case 4:
      return &AMDGPU::VReg_128RegClass;
    }
  }
}

MachineBasicBlock::iterator
SILoadStoreOptimizer::mergeBufferStorePair(CombineInfo &CI) {
  MachineBasicBlock *MBB = CI.I->getParent();
  DebugLoc DL = CI.I->getDebugLoc();

  const unsigned Opcode = getNewOpcode(CI);

  std::pair<unsigned, unsigned> SubRegIdx = getSubRegIdxs(CI);
  const unsigned SubRegIdx0 = std::get<0>(SubRegIdx);
  const unsigned SubRegIdx1 = std::get<1>(SubRegIdx);

  // Copy to the new source register.
  const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI);
  Register SrcReg = MRI->createVirtualRegister(SuperRC);

  const auto *Src0 = TII->getNamedOperand(*CI.I, AMDGPU::OpName::vdata);
  const auto *Src1 = TII->getNamedOperand(*CI.Paired, AMDGPU::OpName::vdata);

  BuildMI(*MBB, CI.Paired, DL, TII->get(AMDGPU::REG_SEQUENCE), SrcReg)
      .add(*Src0)
      .addImm(SubRegIdx0)
      .add(*Src1)
      .addImm(SubRegIdx1);

  auto MIB = BuildMI(*MBB, CI.Paired, DL, TII->get(Opcode))
                 .addReg(SrcReg, RegState::Kill);

  const unsigned Regs = getRegs(Opcode, *TII);

  if (Regs & VADDR)
    MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::vaddr));

  // It shouldn't be possible to get this far if the two instructions
  // don't have a single memoperand, because MachineInstr::mayAlias()
  // will return true if this is the case.
  assert(CI.I->hasOneMemOperand() && CI.Paired->hasOneMemOperand());

  const MachineMemOperand *MMOa = *CI.I->memoperands_begin();
  const MachineMemOperand *MMOb = *CI.Paired->memoperands_begin();

  MIB.add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::srsrc))
      .add(*TII->getNamedOperand(*CI.I, AMDGPU::OpName::soffset))
      .addImm(std::min(CI.Offset0, CI.Offset1)) // offset
      .addImm(CI.GLC0)      // glc
      .addImm(CI.SLC0)      // slc
      .addImm(0)            // tfe
      .addImm(CI.DLC0)      // dlc
      .addMemOperand(combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb));

  moveInstsAfter(MIB, CI.InstsToMove);

  MachineBasicBlock::iterator Next = std::next(CI.I);
  CI.I->eraseFromParent();
  CI.Paired->eraseFromParent();
  return Next;
}

MachineOperand
SILoadStoreOptimizer::createRegOrImm(int32_t Val, MachineInstr &MI) const {
  APInt V(32, Val, true);
  if (TII->isInlineConstant(V))
    return MachineOperand::CreateImm(Val);

  Register Reg = MRI->createVirtualRegister(&AMDGPU::SReg_32RegClass);
  MachineInstr *Mov =
  BuildMI(*MI.getParent(), MI.getIterator(), MI.getDebugLoc(),
          TII->get(AMDGPU::S_MOV_B32), Reg)
    .addImm(Val);
  (void)Mov;
  LLVM_DEBUG(dbgs() << "    "; Mov->dump());
  return MachineOperand::CreateReg(Reg, false);
}

// Compute base address using Addr and return the final register.
unsigned SILoadStoreOptimizer::computeBase(MachineInstr &MI,
                                           const MemAddress &Addr) const {
  MachineBasicBlock *MBB = MI.getParent();
  MachineBasicBlock::iterator MBBI = MI.getIterator();
  DebugLoc DL = MI.getDebugLoc();

  assert((TRI->getRegSizeInBits(Addr.Base.LoReg, *MRI) == 32 ||
          Addr.Base.LoSubReg) &&
         "Expected 32-bit Base-Register-Low!!");

  assert((TRI->getRegSizeInBits(Addr.Base.HiReg, *MRI) == 32 ||
          Addr.Base.HiSubReg) &&
         "Expected 32-bit Base-Register-Hi!!");

  LLVM_DEBUG(dbgs() << "  Re-Computed Anchor-Base:\n");
  MachineOperand OffsetLo = createRegOrImm(static_cast<int32_t>(Addr.Offset), MI);
  MachineOperand OffsetHi =
    createRegOrImm(static_cast<int32_t>(Addr.Offset >> 32), MI);

  const auto *CarryRC = TRI->getRegClass(AMDGPU::SReg_1_XEXECRegClassID);
  Register CarryReg = MRI->createVirtualRegister(CarryRC);
  Register DeadCarryReg = MRI->createVirtualRegister(CarryRC);

  Register DestSub0 = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
  Register DestSub1 = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
  MachineInstr *LoHalf =
    BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::V_ADD_I32_e64), DestSub0)
      .addReg(CarryReg, RegState::Define)
      .addReg(Addr.Base.LoReg, 0, Addr.Base.LoSubReg)
      .add(OffsetLo)
      .addImm(0); // clamp bit
  (void)LoHalf;
  LLVM_DEBUG(dbgs() << "    "; LoHalf->dump(););

  MachineInstr *HiHalf =
  BuildMI(*MBB, MBBI, DL, TII->get(AMDGPU::V_ADDC_U32_e64), DestSub1)
    .addReg(DeadCarryReg, RegState::Define | RegState::Dead)
    .addReg(Addr.Base.HiReg, 0, Addr.Base.HiSubReg)
    .add(OffsetHi)
    .addReg(CarryReg, RegState::Kill)
    .addImm(0); // clamp bit
  (void)HiHalf;
  LLVM_DEBUG(dbgs() << "    "; HiHalf->dump(););

  Register FullDestReg = MRI->createVirtualRegister(&AMDGPU::VReg_64RegClass);
  MachineInstr *FullBase =
    BuildMI(*MBB, MBBI, DL, TII->get(TargetOpcode::REG_SEQUENCE), FullDestReg)
      .addReg(DestSub0)
      .addImm(AMDGPU::sub0)
      .addReg(DestSub1)
      .addImm(AMDGPU::sub1);
  (void)FullBase;
  LLVM_DEBUG(dbgs() << "    "; FullBase->dump(); dbgs() << "\n";);

  return FullDestReg;
}

// Update base and offset with the NewBase and NewOffset in MI.
void SILoadStoreOptimizer::updateBaseAndOffset(MachineInstr &MI,
                                               unsigned NewBase,
                                               int32_t NewOffset) const {
  TII->getNamedOperand(MI, AMDGPU::OpName::vaddr)->setReg(NewBase);
  TII->getNamedOperand(MI, AMDGPU::OpName::offset)->setImm(NewOffset);
}

Optional<int32_t>
SILoadStoreOptimizer::extractConstOffset(const MachineOperand &Op) const {
  if (Op.isImm())
    return Op.getImm();

  if (!Op.isReg())
    return None;

  MachineInstr *Def = MRI->getUniqueVRegDef(Op.getReg());
  if (!Def || Def->getOpcode() != AMDGPU::S_MOV_B32 ||
      !Def->getOperand(1).isImm())
    return None;

  return Def->getOperand(1).getImm();
}

// Analyze Base and extracts:
//  - 32bit base registers, subregisters
//  - 64bit constant offset
// Expecting base computation as:
//   %OFFSET0:sgpr_32 = S_MOV_B32 8000
//   %LO:vgpr_32, %c:sreg_64_xexec =
//       V_ADD_I32_e64 %BASE_LO:vgpr_32, %103:sgpr_32,
//   %HI:vgpr_32, = V_ADDC_U32_e64 %BASE_HI:vgpr_32, 0, killed %c:sreg_64_xexec
//   %Base:vreg_64 =
//       REG_SEQUENCE %LO:vgpr_32, %subreg.sub0, %HI:vgpr_32, %subreg.sub1
void SILoadStoreOptimizer::processBaseWithConstOffset(const MachineOperand &Base,
                                                      MemAddress &Addr) const {
  if (!Base.isReg())
    return;

  MachineInstr *Def = MRI->getUniqueVRegDef(Base.getReg());
  if (!Def || Def->getOpcode() != AMDGPU::REG_SEQUENCE
      || Def->getNumOperands() != 5)
    return;

  MachineOperand BaseLo = Def->getOperand(1);
  MachineOperand BaseHi = Def->getOperand(3);
  if (!BaseLo.isReg() || !BaseHi.isReg())
    return;

  MachineInstr *BaseLoDef = MRI->getUniqueVRegDef(BaseLo.getReg());
  MachineInstr *BaseHiDef = MRI->getUniqueVRegDef(BaseHi.getReg());

  if (!BaseLoDef || BaseLoDef->getOpcode() != AMDGPU::V_ADD_I32_e64 ||
      !BaseHiDef || BaseHiDef->getOpcode() != AMDGPU::V_ADDC_U32_e64)
    return;

  const auto *Src0 = TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src0);
  const auto *Src1 = TII->getNamedOperand(*BaseLoDef, AMDGPU::OpName::src1);

  auto Offset0P = extractConstOffset(*Src0);
  if (Offset0P)
    BaseLo = *Src1;
  else {
    if (!(Offset0P = extractConstOffset(*Src1)))
      return;
    BaseLo = *Src0;
  }

  Src0 = TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src0);
  Src1 = TII->getNamedOperand(*BaseHiDef, AMDGPU::OpName::src1);

  if (Src0->isImm())
    std::swap(Src0, Src1);

  if (!Src1->isImm())
    return;

  uint64_t Offset1 = Src1->getImm();
  BaseHi = *Src0;

  Addr.Base.LoReg = BaseLo.getReg();
  Addr.Base.HiReg = BaseHi.getReg();
  Addr.Base.LoSubReg = BaseLo.getSubReg();
  Addr.Base.HiSubReg = BaseHi.getSubReg();
  Addr.Offset = (*Offset0P & 0x00000000ffffffff) | (Offset1 << 32);
}

bool SILoadStoreOptimizer::promoteConstantOffsetToImm(
    MachineInstr &MI,
    MemInfoMap &Visited,
    SmallPtrSet<MachineInstr *, 4> &AnchorList) const {

  if (!(MI.mayLoad() ^ MI.mayStore()))
    return false;

  // TODO: Support flat and scratch.
  if (AMDGPU::getGlobalSaddrOp(MI.getOpcode()) < 0)
    return false;

  if (MI.mayLoad() && TII->getNamedOperand(MI, AMDGPU::OpName::vdata) != NULL)
    return false;

  if (AnchorList.count(&MI))
    return false;

  LLVM_DEBUG(dbgs() << "\nTryToPromoteConstantOffsetToImmFor "; MI.dump());

  if (TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm()) {
    LLVM_DEBUG(dbgs() << "  Const-offset is already promoted.\n";);
    return false;
  }

  // Step1: Find the base-registers and a 64bit constant offset.
  MachineOperand &Base = *TII->getNamedOperand(MI, AMDGPU::OpName::vaddr);
  MemAddress MAddr;
  if (Visited.find(&MI) == Visited.end()) {
    processBaseWithConstOffset(Base, MAddr);
    Visited[&MI] = MAddr;
  } else
    MAddr = Visited[&MI];

  if (MAddr.Offset == 0) {
    LLVM_DEBUG(dbgs() << "  Failed to extract constant-offset or there are no"
                         " constant offsets that can be promoted.\n";);
    return false;
  }

  LLVM_DEBUG(dbgs() << "  BASE: {" << MAddr.Base.HiReg << ", "
             << MAddr.Base.LoReg << "} Offset: " << MAddr.Offset << "\n\n";);

  // Step2: Traverse through MI's basic block and find an anchor(that has the
  // same base-registers) with the highest 13bit distance from MI's offset.
  // E.g. (64bit loads)
  // bb:
  //   addr1 = &a + 4096;   load1 = load(addr1,  0)
  //   addr2 = &a + 6144;   load2 = load(addr2,  0)
  //   addr3 = &a + 8192;   load3 = load(addr3,  0)
  //   addr4 = &a + 10240;  load4 = load(addr4,  0)
  //   addr5 = &a + 12288;  load5 = load(addr5,  0)
  //
  // Starting from the first load, the optimization will try to find a new base
  // from which (&a + 4096) has 13 bit distance. Both &a + 6144 and &a + 8192
  // has 13bit distance from &a + 4096. The heuristic considers &a + 8192
  // as the new-base(anchor) because of the maximum distance which can
  // accomodate more intermediate bases presumeably.
  //
  // Step3: move (&a + 8192) above load1. Compute and promote offsets from
  // (&a + 8192) for load1, load2, load4.
  //   addr = &a + 8192
  //   load1 = load(addr,       -4096)
  //   load2 = load(addr,       -2048)
  //   load3 = load(addr,       0)
  //   load4 = load(addr,       2048)
  //   addr5 = &a + 12288;  load5 = load(addr5,  0)
  //
  MachineInstr *AnchorInst = nullptr;
  MemAddress AnchorAddr;
  uint32_t MaxDist = std::numeric_limits<uint32_t>::min();
  SmallVector<std::pair<MachineInstr *, int64_t>, 4> InstsWCommonBase;

  MachineBasicBlock *MBB = MI.getParent();
  MachineBasicBlock::iterator E = MBB->end();
  MachineBasicBlock::iterator MBBI = MI.getIterator();
  ++MBBI;
  const SITargetLowering *TLI =
    static_cast<const SITargetLowering *>(STM->getTargetLowering());

  for ( ; MBBI != E; ++MBBI) {
    MachineInstr &MINext = *MBBI;
    // TODO: Support finding an anchor(with same base) from store addresses or
    // any other load addresses where the opcodes are different.
    if (MINext.getOpcode() != MI.getOpcode() ||
        TII->getNamedOperand(MINext, AMDGPU::OpName::offset)->getImm())
      continue;

    const MachineOperand &BaseNext =
      *TII->getNamedOperand(MINext, AMDGPU::OpName::vaddr);
    MemAddress MAddrNext;
    if (Visited.find(&MINext) == Visited.end()) {
      processBaseWithConstOffset(BaseNext, MAddrNext);
      Visited[&MINext] = MAddrNext;
    } else
      MAddrNext = Visited[&MINext];

    if (MAddrNext.Base.LoReg != MAddr.Base.LoReg ||
        MAddrNext.Base.HiReg != MAddr.Base.HiReg ||
        MAddrNext.Base.LoSubReg != MAddr.Base.LoSubReg ||
        MAddrNext.Base.HiSubReg != MAddr.Base.HiSubReg)
      continue;

    InstsWCommonBase.push_back(std::make_pair(&MINext, MAddrNext.Offset));

    int64_t Dist = MAddr.Offset - MAddrNext.Offset;
    TargetLoweringBase::AddrMode AM;
    AM.HasBaseReg = true;
    AM.BaseOffs = Dist;
    if (TLI->isLegalGlobalAddressingMode(AM) &&
        (uint32_t)std::abs(Dist) > MaxDist) {
      MaxDist = std::abs(Dist);

      AnchorAddr = MAddrNext;
      AnchorInst = &MINext;
    }
  }

  if (AnchorInst) {
    LLVM_DEBUG(dbgs() << "  Anchor-Inst(with max-distance from Offset): ";
               AnchorInst->dump());
    LLVM_DEBUG(dbgs() << "  Anchor-Offset from BASE: "
               <<  AnchorAddr.Offset << "\n\n");

    // Instead of moving up, just re-compute anchor-instruction's base address.
    unsigned Base = computeBase(MI, AnchorAddr);

    updateBaseAndOffset(MI, Base, MAddr.Offset - AnchorAddr.Offset);
    LLVM_DEBUG(dbgs() << "  After promotion: "; MI.dump(););

    for (auto P : InstsWCommonBase) {
      TargetLoweringBase::AddrMode AM;
      AM.HasBaseReg = true;
      AM.BaseOffs = P.second - AnchorAddr.Offset;

      if (TLI->isLegalGlobalAddressingMode(AM)) {
        LLVM_DEBUG(dbgs() << "  Promote Offset(" << P.second;
                   dbgs() << ")"; P.first->dump());
        updateBaseAndOffset(*P.first, Base, P.second - AnchorAddr.Offset);
        LLVM_DEBUG(dbgs() << "     After promotion: "; P.first->dump());
      }
    }
    AnchorList.insert(AnchorInst);
    return true;
  }

  return false;
}

// Scan through looking for adjacent LDS operations with constant offsets from
// the same base register. We rely on the scheduler to do the hard work of
// clustering nearby loads, and assume these are all adjacent.
bool SILoadStoreOptimizer::optimizeBlock(MachineBasicBlock &MBB) {
  bool Modified = false;

  // Contain the list
  MemInfoMap Visited;
  // Contains the list of instructions for which constant offsets are being
  // promoted to the IMM.
  SmallPtrSet<MachineInstr *, 4> AnchorList;

  for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
    MachineInstr &MI = *I;

    if (promoteConstantOffsetToImm(MI, Visited, AnchorList))
      Modified = true;

    // Don't combine if volatile.
    if (MI.hasOrderedMemoryRef()) {
      ++I;
      continue;
    }

    CombineInfo CI;
    CI.setMI(I, *TII, *STM);

    switch (CI.InstClass) {
    default:
      break;
    case DS_READ:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeRead2Pair(CI);
      } else {
        ++I;
      }
      continue;
    case DS_WRITE:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeWrite2Pair(CI);
      } else {
        ++I;
      }
      continue;
    case S_BUFFER_LOAD_IMM:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeSBufferLoadImmPair(CI);
        OptimizeAgain |= (CI.Width0 + CI.Width1) < 16;
      } else {
        ++I;
      }
      continue;
    case BUFFER_LOAD:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeBufferLoadPair(CI);
        OptimizeAgain |= (CI.Width0 + CI.Width1) < 4;
      } else {
        ++I;
      }
      continue;
    case BUFFER_STORE:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeBufferStorePair(CI);
        OptimizeAgain |= (CI.Width0 + CI.Width1) < 4;
      } else {
        ++I;
      }
      continue;
    case MIMG:
      if (findMatchingInst(CI)) {
        Modified = true;
        I = mergeImageSamplePair(CI);
      } else {
        ++I;
      }
      continue;
    }

    ++I;
  }

  return Modified;
}

bool SILoadStoreOptimizer::runOnMachineFunction(MachineFunction &MF) {
  if (skipFunction(MF.getFunction()))
    return false;

  STM = &MF.getSubtarget<GCNSubtarget>();
  if (!STM->loadStoreOptEnabled())
    return false;

  TII = STM->getInstrInfo();
  TRI = &TII->getRegisterInfo();

  MRI = &MF.getRegInfo();
  AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();

  assert(MRI->isSSA() && "Must be run on SSA");

  LLVM_DEBUG(dbgs() << "Running SILoadStoreOptimizer\n");

  bool Modified = false;

  for (MachineBasicBlock &MBB : MF) {
    do {
      OptimizeAgain = false;
      Modified |= optimizeBlock(MBB);
    } while (OptimizeAgain);
  }

  return Modified;
}


text:
#ifndef ___DGL_FONT_H
#define ___DGL_FONT_H

#include "DGL_Color.h"

namespace DGL {

	class Texture;

	/*
	=================================================================

	FONTS

	=================================================================
	*/

	class Font {
		public:
			//
			// Interface
			//
			void Create(const char *name);
			void Print(int x, int y, const char *fmt, ...) const;
			void Print3D( Vector pos, const char *fmt, ...) const;
			void SetColor(Color &color) { this->color = color; }
			void SetSize(float size) { this->size = size; }
			enum EStyle {
				STYLE_LEFT		= 0x00000001,
				STYLE_RIGHT		= 0x00000002,
				STYLE_CENTER	= 0x00000004,
				STYLE_SHADOWS	= 0x00000008
			};
			void SetStyle(int style) { this->style = style; }

			inline Font& operator = (Font& f)
			{
				this->size = f.size;
				this->style = f.style;
				this->color = f.color;
				this->font = f.font;
				return *this;
			}

			Font() :
				size(1),
				style(STYLE_LEFT|STYLE_SHADOWS),
				color(1.0f,1.0f,1.0f),
				font(0) { }

		private:
			float			size;
			int				style;
			Color			color;
			int				font;

		public:
			static void Init(void);
			static void Kill(void);
			static int	CreateFont(const char *name);
			static void Print2D( int x, int y, const char *fmt, float size, int attribs, const float* color, int font, ...);
			static void Print3D( float x, float y, float z, const char *fmt, float size, int attribs, const float* color, int font,	...);
			static float CharWidth();
			static float CharHeight();
		private:
			static bool			valid;
			static GLuint		charList;
			static const int	MAX_FONTS	= 0x0100;
			static Texture		fontTexture[MAX_FONTS];
			static char			fontTextureName[MAX_FONTS][64];
			static int			currentFree;
			static float		orthoMatrix[16];
			static bool			orthoMatrixValid;
			static float		shadowColor[4];

			static void GenerateFontLists(GLuint& ListID, float char_width,float char_height, float xspacing);
			static void PrintToOrtho(int x,int y, const char *fmt, int fmtMax, int charindex, const float *color, float scale);
			static void PrintToScene(float x,float y,float z, const char *fmt, int fmtMax, int charindex, const float *color, float scale);
	};
}

#endif // ___DGL_FONT_H

redpajama_set_name: RedPajamaGithub


text:
layout: post
category: day-by-day
date: 2019-07-29
title: Preparando la ruta post-boda
image:
  thumbnail: /images/blog/thumbnails/2019-07-29-preparando-la-ruta-post-boda.jpg
  path: /images/blog/2019-07-29-preparando-la-ruta-post-boda.jpg
---


text:
CKEDITOR.plugins.setLang( 'basicstyles', 'is', {
	bold: 'Feitletrað',
	italic: 'Skáletrað',
	strike: 'Yfirstrikað',
	subscript: 'Niðurskrifað',
	superscript: 'Uppskrifað',
	underline: 'Undirstrikað'
} );


text:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!--

        Licensed to the Apache Software Foundation (ASF) under one or more
        contributor license agreements.  See the NOTICE file distributed with
        this work for additional information regarding copyright ownership.
        The ASF licenses this file to You 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.
    -->

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.apache.karaf.examples</groupId>
        <artifactId>karaf-mbean-example</artifactId>
        <version>4.2.3-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>karaf-mbean-example-api</artifactId>
    <name>Apache Karaf :: Examples :: MBean :: API</name>
    <packaging>bundle</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <configuration>
                    <instructions>
                        <Export-Package>
                            org.apache.karaf.examples.mbean.api
                        </Export-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


text:
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Webpack Examples | Basic With HTML Plugin (and Hashes)</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <noscript>Um, something's not right here...</noscript>
    {% for (var chunk in o.htmlWebpackPlugin.files.chunks) { %}
    <script src="{%=o.htmlWebpackPlugin.files.chunks[chunk].entry %}"></script>
    {% } %}
  </body>
</html>


text:
<?php
namespace Behoma\Web;

use Hoimi\Request;
use Hoimi\Session;

class ActionFormTest extends \PHPUnit_Framework_TestCase
{
    private $target;
    private $request;
    private $session;

    protected function setUp()
    {
        $_SESSION = array();
        $this->request = new Request(array(),array());
        $this->session = new Session($this->request, array());
        $this->target = new ActionForm($this->request, $this->session);
    }

    public function testGetActionFormValue () {
        /** @var ActionForm $actionForm */
        $actionForm = $this->target;
        $actionForm->setContainer(array (
            'HOGE' => 'xyzzy',
            'array' => array (
                array (
                    'named' => array (
                        'array' => array ( 1, 2, 3 )
                    )
                ),
                array (
                    'named' => array (
                        'fizz' => 'buzz',
                        'hoge' => 'fuga',
                    )
                ),
            ),
            'named' => array(
                'array' => array ( 1000, 2000, 3000 ),
                'named' => array (
                    'array' => array( 100,200, 300 ),
                ),
            )
        ));
        $this->assertEquals ( 'xyzzy', $actionForm->getActionFormValue ( 'HOGE' ) );
        $this->assertEquals ( 1, $actionForm->getActionFormValue ( 'array[0][named][array][0]' ) );
        $this->assertEquals ( 'buzz', $actionForm->getActionFormValue ( 'array[1][named][fizz]' ) );
        $this->assertEquals ( 'fuga', $actionForm->getActionFormValue ( 'array[1][named][hoge]' ) );
        $this->assertEquals ( 1000, $actionForm->getActionFormValue ( 'named[array][0]' ) );
        $this->assertEquals ( 2000, $actionForm->getActionFormValue ( 'named[array][1]' ) );
        $this->assertEquals ( 3000, $actionForm->getActionFormValue ( 'named[array][2]' ) );
        $this->assertEquals ( 100, $actionForm->getActionFormValue ( 'named[named][array][0]' ) );
        $this->assertEquals ( 200, $actionForm->getActionFormValue ( 'named[named][array][1]' ) );
        $this->assertEquals ( 300, $actionForm->getActionFormValue ( 'named [named]
      [array]
      [2]' ) );
        $this->assertEquals ( null, $actionForm->getActionFormValue ( 'そんなものは無い' ) );

        try {
            $actionForm->getActionFormValue ( 'named[array]a[bc]d' );
        } catch ( \Exception $e ) {
            $this->assertEquals ( 'Syntax Error', $e->getMessage () );
        }
    }

    function testFormText()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<input type="text" name="hoge" value="value"  />');
        $target->formText('hoge');
    }

    function testFormPassword()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<input type="password" name="hoge" value="value"  />');
        $target->formPassword('hoge');
    }

    function testFormNumber()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('1'));
        $this->expectOutputString('<input type="number" name="hoge" value="1"  min="0" max="100" />');
        $target->formNumber('hoge', array('min' => "0", 'max' => "100"));
    }

    function testFormEmail()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<input type="email" name="hoge" value="value"  />');
        $target->formEmail('hoge');
    }

    function testFormTel()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<input type="tel" name="hoge" value="value"  />');
        $target->formTel('hoge');
    }

    function testFormTextArea()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<textarea name="hoge">value</textarea>');
        $target->formTextArea('hoge');
    }

    function testFormHidden()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('value'));
        $this->expectOutputString('<input type="hidden" name="hoge" value="value"  />');
        $target->formHidden('hoge');
    }

    function testFormRadio()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('piyo'));

        $attribute = array('class' => 'class1 class2');
        $options = array('foo' => 'bar', 'piyo' => 'fuga');
        $attributeLabel = array('style' => 'color: #888;');

        $html  = '<input type="radio" id="hoge_foo" name="hoge" value="foo"  class="class1 class2"  />';
        $html .= 'bar ';
        $html .= '<input type="radio" id="hoge_piyo" name="hoge" value="piyo"  class="class1 class2" checked="checked" />';
        $html .= 'fuga ';
        $this->expectOutputString($html);
        $target->formRadio('hoge', $attribute, $options, $attributeLabel);
    }

    function testFormCheckbox()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue(array('piyo')));

        $attribute = array('class' => 'class1 class2');
        $options = array('foo' => 'bar', 'piyo' => 'fuga');
        $attributeLabel = array('style' => 'color: #888;');

        $html  = '<input type="checkbox" id="hoge_foo" name="hoge[]" value="foo"  class="class1 class2"  />';
        $html .= 'bar ';
        $html .= '<input type="checkbox" id="hoge_piyo" name="hoge[]" value="piyo"  class="class1 class2" checked="checked" />';
        $html .= 'fuga ';
        $this->expectOutputString($html);
        $target->formCheckBox('hoge', $attribute, $options, $attributeLabel);
    }

    function testFormSelect()
    {
        $target = $this->createMock(array('getActionFormValue'));
        $target->expects($this->once())->method('getActionFormValue')->will($this->returnValue('piyo'));

        $attributes = array('class' => 'class1 class2');
        $options = array('foo' => 'bar', 'piyo' => 'fuga');

        $html  = '<select name="hoge"  class="class1 class2">';
        $html .= '<option value="foo">bar</option>';
        $html .= '<option value="piyo" selected="selected">fuga</option>';
        $html .= '</select>';

        $this->expectOutputString($html);
        $target->formSelect('hoge', $attributes, $options);
    }

    function testFormSubmit()
    {
        $target = $this->createMock(array(''));
        $attributes = array('class' => 'class1 class2');

        $html = '<input type="submit" name="xyzzy" value="送信"  class="class1 class2" />';
        $this->expectOutputString($html);
        $target->formSubmit('xyzzy', '送信', $attributes);
    }

    function createMock($method = array())
    {
        return $this->getMockForAbstractClass(
            '\Behoma\Web\ActionForm',
            array(),
            'ActionForm',
            false,
            false,
            false,
            $method
        );
    }
}


text:
package io.xdevs23.cornowser.browser.browser.xwalk;

import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.webkit.ValueCallback;

import org.xdevs23.android.app.XquidCompatActivity;
import org.xdevs23.android.content.res.AssetHelper;
import org.xdevs23.debugutils.Logging;
import org.xdevs23.debugutils.StackTraceParser;
import org.xdevs23.net.DownloadUtils;
import org.xdevs23.ui.dialog.EditTextDialog;
import org.xdevs23.ui.dialog.templates.DismissDialogButton;
import org.xwalk.core.XWalkJavascriptResult;
import org.xwalk.core.XWalkUIClient;
import org.xwalk.core.XWalkView;

import java.io.InputStream;

import io.xdevs23.cornowser.browser.CornBrowser;
import io.xdevs23.cornowser.browser.R;
import io.xdevs23.cornowser.browser.browser.modules.CornHandler;
import io.xdevs23.cornowser.browser.browser.modules.WebThemeHelper;
import io.xdevs23.cornowser.browser.browser.modules.tabs.Tab;

/**
 * A custom UIClient for our crunchy view
 */
public class CornUIClient extends XWalkUIClient {

    public boolean skipDCheck = false;

    // This is for controlling errors on start-up loading
    protected boolean readyForBugfreeBrowsing = false;

    public CornUIClient(XWalkView view) {
        super(view);
    }

    @Override
    public void onReceivedTitle(XWalkView view, String title) {
        Logging.logd("Web received title: " + title);
        super.onReceivedTitle(view, title);
        WebThemeHelper.tintNow(CrunchyWalkView.fromXWalkView(view));
        CornBrowser.getTabSwitcher().getCurrentTab().setTitle(title);
    }

    @Override
    public void onIconAvailable(XWalkView view, String url, Message startDownload) {
        final CrunchyWalkView fView = CrunchyWalkView.fromXWalkView(view);
        final String fUrl = url;
        Thread downIcon = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    InputStream inputStream = DownloadUtils.getInputStreamForConnection(fUrl);
                    fView.favicon = BitmapFactory.decodeStream(inputStream);
                } catch(Exception ex) {
                    StackTraceParser.logStackTrace(ex);
                }
            }
        });
        downIcon.start();

        WebThemeHelper.tintNow(CrunchyWalkView.fromXWalkView(view));
    }

    @Override
    public void onReceivedIcon(XWalkView view, String url, Bitmap icon) {
        // Do nothing
    }

    @Override
    public void onRequestFocus(XWalkView view) {
        super.onRequestFocus(view);
    }

    @Override
    public void onJavascriptCloseWindow(XWalkView view) {
        if(CornBrowser.getTabSwitcher().getTabStorage().getTabCount() > 1)
            CornBrowser.getTabSwitcher().removeTab(CornBrowser.getTabSwitcher().getCurrentTab());
        else
            CornBrowser.getWebEngine().load(CornBrowser.getBrowserStorage().getUserHomePage());
    }

    @Override
    public boolean onCreateWindowRequested(XWalkView view, InitiateBy initiator, ValueCallback<XWalkView> callback) {
        CornBrowser.getTabSwitcher().addTab(new Tab());
        return super.onCreateWindowRequested(CornBrowser.publicWebRender, initiator, callback);
    }

    @Override
    public boolean onConsoleMessage(XWalkView view, String message, int lineNumber, String sourceId, ConsoleMessageType messageType) {
        if(message.toLowerCase().contains("cornhandler://"))
            CornHandler.handleRequest(message,
                    CornBrowser.getActivity(),
                    CrunchyWalkView.fromXWalkView(view),
                    view.getUrl(),
                    CornBrowser.getWebEngine().getResourceClient());
        return super.onConsoleMessage(view, message, lineNumber, sourceId, messageType);
    }

    @Override
    public boolean onJavascriptModalDialog(XWalkView view, XWalkUIClient.JavascriptMessageType type,
                                           String url, String message, String defaultValue, XWalkJavascriptResult result) {
        return super.onJavascriptModalDialog(view, type, url, message, defaultValue, result);
    }

    @Override
    public boolean onJsAlert(XWalkView view, String url, String message, XWalkJavascriptResult result) {
        AlertDialog.Builder b = new AlertDialog.Builder(CornBrowser.getActivity());
        b
                .setCancelable(true)
                .setTitle(view.getTitle())
                .setMessage(message)
                .setPositiveButton(CornBrowser.getContext().getString(R.string.answer_ok), new DismissDialogButton())
                .create()
                .show()
        ;
        result.confirm();
        return true;
    }

    @Override
    public boolean onJsConfirm(XWalkView view, String url, String message, XWalkJavascriptResult result) {
        final XWalkJavascriptResult fResult = result;
        AlertDialog.Builder b = new AlertDialog.Builder(CornBrowser.getActivity());
        b
                .setCancelable(true)
                .setTitle(view.getTitle())
                .setMessage(message)
                .setPositiveButton(CornBrowser.getContext().getString(R.string.answer_ok),
                        new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        fResult.confirm();
                    }
                })
                .setNegativeButton(CornBrowser.getContext().getString(R.string.answer_cancel),
                        new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        fResult.cancel();
                    }
                })
                .create()
                .show()
        ;
        return true;
    }

    @Override
    public boolean onJsPrompt(XWalkView view, String url, String message, String defaultValue, XWalkJavascriptResult result) {
        final XWalkJavascriptResult fResult = result;
        final EditTextDialog d = new EditTextDialog(CornBrowser.getContext(),
                (XquidCompatActivity) CornBrowser.getActivity(),
                message,
                defaultValue);
        d.setOnClickListener(new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                fResult.confirmWithResult(d.getEnteredText());
                dialog.dismiss();
            }
        });
        d.showDialog();

        return true;
    }

    protected boolean isDangerousPage(String url) {
        String matchUrl = url.substring(
                url.indexOf("//") + 2,
                url.indexOf("/", url.indexOf("//") + 2));
        String[] dUrls = AssetHelper.getAssetString("list/badPages.txt", CornBrowser.getContext())
                .split("\n");
        for ( String s : dUrls ) {
            Logging.logd(matchUrl + " checking...");
            if (matchUrl.contains(s))
                return true;
        }
        return false;
    }

    @Override
    public void onPageLoadStarted(XWalkView view, String url) {
        CrunchyWalkView.fromXWalkView(view).favicon = null;
        CornBrowser.resetOmniPositionState(true);
        Logging.logd("Page load started for: " + url);
        CrunchyWalkView.fromXWalkView(view).currentProgress = 0;
        final XWalkView fView = view;
        final String fUrl = url;
        if(skipDCheck || (!isDangerousPage(url))) {
            Logging.logd("Web page not detected as dangerous.");
            skipDCheck = false;
            super.onPageLoadStarted(view, url);
        } else {
            Logging.logd("Dangerous website detected: " + url);
            fView.stopLoading();
            AlertDialog.Builder b = new AlertDialog.Builder(CornBrowser.getActivity());
            b
                    .setTitle(CornBrowser.getContext().getString(R.string.webrender_dangerous_site_title))
                    .setMessage(CornBrowser.getContext().getString(R.string.webrender_dangerous_site_message))
                    .setPositiveButton(CornBrowser.getContext().getString(R.string.answer_yes),
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    skipDCheck = true;
                                    CornBrowser.publicWebRender.load(fUrl);
                                    dialog.dismiss();
                                }
                            })
                    .setNegativeButton(CornBrowser.getContext().getString(R.string.answer_no),
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    fView.stopLoading();
                                    dialog.dismiss();
                                }
                            })
                    .create().show();
            CornBrowser.initOmniboxPosition();
            CornBrowser.getWebEngine().loadWorkingUrl();
            return;
        }
        CornBrowser.handleGoForwardControlVisibility();
    }

    @Override
    public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) {
        if( (status == LoadStatus.CANCELLED || status == LoadStatus.FAILED)
                && (!readyForBugfreeBrowsing) && (!url.isEmpty()) )
            view.load(url, null);
        else readyForBugfreeBrowsing = true;

        Logging.logd("Page load stopped");
        super.onPageLoadStopped(view, url, status);

        CornBrowser.handleGoForwardControlVisibility();

        CornBrowser.getOmniPtrLayout().setRefreshing(false);

        CornBrowser.getWebProgressBar().setProgress(1.0f);
        CornBrowser.getWebProgressBar().setVisibility(View.INVISIBLE);

        CornBrowser.publicWebRender.drawWithColorMode();

        CrunchyWalkView.fromXWalkView(view).currentProgress = 100;
    }

}


text:
"""Contains methods used by the paasta client to generate a Jenkins build
pipeline."""
import re

from paasta_tools.cli.utils import guess_service_name
from paasta_tools.cli.utils import lazy_choices_completer
from paasta_tools.cli.utils import list_services
from paasta_tools.cli.utils import NoSuchService
from paasta_tools.cli.utils import validate_service_name
from paasta_tools.monitoring_tools import get_team
from paasta_tools.monitoring_tools import get_team_email_address
from paasta_tools.utils import _run
from paasta_tools.utils import DEFAULT_SOA_DIR
from paasta_tools.utils import get_git_url
from paasta_tools.utils import paasta_print

def add_subparser(subparsers):
    list_parser = subparsers.add_parser(
        'generate-pipeline',
        help="Configures a Yelp-specific Jenkins build pipeline to match the 'deploy.yaml'",
        description=(
            "'paasta generate-pipeline' is a Yelp-specific tool to interact with Jenkins "
            "to build a build pipeline that matches what is declared in the 'deploy.yaml' "
            "for a service."
        ),
        epilog="Warning: Due to the Yelpisms in this tool, it is not currently useful to other organizations.",
    )
    list_parser.add_argument(
        '-s', '--service',
        help='Name of service for which you wish to generate a Jenkins pipeline',
    ).completer = lazy_choices_completer(list_services)
    list_parser.set_defaults(command=paasta_generate_pipeline)

def paasta_generate_pipeline(args):
    """Generate a Jenkins build pipeline.
    :param args: argparse.Namespace obj created from sys.args by cli"""
    service = args.service or guess_service_name()
    soa_dir = DEFAULT_SOA_DIR
    try:
        validate_service_name(service, soa_dir=soa_dir)
    except NoSuchService as service_not_found:
        paasta_print(service_not_found)
        return 1

    generate_pipeline(service=service, soa_dir=soa_dir)

def get_git_repo_for_fab_repo(service, soa_dir):
    """Returns the 'repo' in fab_repo terms. fab_repo just wants the trailing
    section of the git_url, after the colon.
    """
    git_url = get_git_url(service, soa_dir=soa_dir)
    repo = git_url.split(':')[1]
    return repo

def print_warning():
    paasta_print("Warning: paasta generate-pipeline is a Yelp-specific tool and will")
    paasta_print("not work outside Yelp.")
    paasta_print()
    paasta_print("paasta generate-pipeline is designed only to give a starting Jenkins")
    paasta_print("configuration that can be customized later")
    paasta_print()
    paasta_print("Warning: running this tool on an existing pipeline will remove any")
    paasta_print("hand-made customizations and will leave behind orphaned Jenkins jobs")
    paasta_print("that need to be manually cleaned up.")
    paasta_print()
    input("Press enter to continue or ctrl-c to cancel")

def generate_pipeline(service, soa_dir):
    email_address = get_team_email_address(service=service, soa_dir=soa_dir)
    repo = get_git_repo_for_fab_repo(service, soa_dir)
    if not email_address:
        owner = get_team(overrides={}, service=service, soa_dir=soa_dir)
    else:
        # fab_repo tacks on the domain, so we only want the first
        # part of the email.
        owner = re.sub('@.*', '', email_address)
    cmds = [
        'fab_repo setup_jenkins:services/%s,'
        'profile=paasta,job_disabled=False,owner=%s,repo=%s' % (service, owner, repo),
        'fab_repo setup_jenkins:services/%s,'
        'profile=paasta_boilerplate,owner=%s,repo=%s' % (service, owner, repo),
    ]
    print_warning()
    for cmd in cmds:
        paasta_print("INFO: Executing %s" % cmd)
        returncode, output = _run(cmd, timeout=90)
        if returncode != 0:
            paasta_print("ERROR: Failed to generate Jenkins pipeline")
            paasta_print(output)
            return returncode


text:
lychee.define('lychee.ui.element.Viewport').requires([
	'lychee.Renderer',
	'lychee.Viewport',
	'lychee.ui.Input',
	'lychee.ui.Select'
]).includes([
	'lychee.ui.Element'
]).exports(function(lychee, global, attachments) {

	/*
	 * HELPERS
	 */

	var _read = function() {

		var main = global.MAIN || null;
		if (main !== null) {

			var renderer = main.renderer || null;
			var viewport = main.viewport || null;

			if (renderer !== null && viewport !== null) {

				var background = renderer.background;
				var fullscreen = viewport.fullscreen;
				var width      = renderer.width;
				var height     = renderer.height;

				if (width  === viewport.width)  width  = null;
				if (height === viewport.height) height = null;

				this.getEntity('background').setValue(background);

				if (fullscreen === true) {

					this.getEntity('mode').setValue('fullscreen');

				} else if (width === null && height === null) {

					this.getEntity('mode').setValue('dynamic');

				} else {

					this.getEntity('mode').setValue('static');
					this.getEntity('width').setValue(width);
					this.getEntity('height').setValue(height);

				}

			}

		}

	};

	var _save = function() {

		var main = global.MAIN || null;
		if (main !== null) {

			var renderer = main.renderer || null;
			var viewport = main.viewport || null;

			if (renderer !== null && viewport !== null) {

				var background = this.getEntity('background').value;
				var mode       = this.getEntity('mode').value;
				var width      = this.getEntity('width').value;
				var height     = this.getEntity('height').value;

				if (mode === 'fullscreen') {

					renderer.setBackground(background);
					renderer.setWidth(null);
					renderer.setHeight(null);

					viewport.setFullscreen(true);

				} else if (mode === 'dynamic') {

					renderer.setBackground(background);
					renderer.setWidth(null);
					renderer.setHeight(null);

					viewport.setFullscreen(false);

				} else if (mode === 'static') {

					renderer.setBackground(background);
					renderer.setWidth(width);
					renderer.setHeight(height);

					viewport.setFullscreen(false);

				}

			}

		}

	};

	/*
	 * IMPLEMENTATION
	 */

	var Class = function(data) {

		var settings = lychee.extend({}, data);

		settings.label   = 'Viewport';
		settings.options = [ 'Save' ];

		lychee.ui.Element.call(this, settings);

		/*
		 * INITIALIZATION
		 */

		this.setEntity('mode', new lychee.ui.Select({
			options: [ 'fullscreen', 'dynamic', 'static' ],
			value:   'dynamic'
		}));

		this.setEntity('width', new lychee.ui.Input({
			type:    lychee.ui.Input.TYPE.number,
			value:   1024,
			visible: false
		}));

		this.setEntity('height', new lychee.ui.Input({
			type:    lychee.ui.Input.TYPE.number,
			value:   768,
			visible: false
		}));

		this.setEntity('background', new lychee.ui.Input({
			type:  lychee.ui.Input.TYPE.text,
			value: '#404844'
		}));

		this.getEntity('mode').bind('change', function(value) {

			if (value === 'fullscreen') {

				this.getEntity('width').visible  = false;
				this.getEntity('height').visible = false;

			} else if (value === 'dynamic') {

				this.getEntity('width').visible  = false;
				this.getEntity('height').visible = false;

			} else if (value === 'static') {

				this.getEntity('width').visible  = true;
				this.getEntity('height').visible = true;

			}

			this.trigger('relayout', []);

		}, this);

		this.bind('change', function(action) {

			if (action === 'save') {
				_save.call(this);
			}

		}, this);

		_read.call(this);

		settings = null;

	};

	Class.prototype = {

	};

	return Class;

});


text:
namespace Google.Analytics.Admin.V1Alpha.Snippets
{
    // [START analyticsadmin_v1alpha_generated_AnalyticsAdminService_GetDataSharingSettings_async]
    using Google.Analytics.Admin.V1Alpha;
    using System.Threading.Tasks;

    public sealed partial class GeneratedAnalyticsAdminServiceClientSnippets
    {
        /// <summary>Snippet for GetDataSharingSettingsAsync</summary>
        /// <remarks>
        /// This snippet has been automatically generated for illustrative purposes only.
        /// It may require modifications to work in your environment.
        /// </remarks>
        public async Task GetDataSharingSettingsRequestObjectAsync()
        {
            // Create client
            AnalyticsAdminServiceClient analyticsAdminServiceClient = await AnalyticsAdminServiceClient.CreateAsync();
            // Initialize request argument(s)
            GetDataSharingSettingsRequest request = new GetDataSharingSettingsRequest
            {
                DataSharingSettingsName = DataSharingSettingsName.FromAccount("[ACCOUNT]"),
            };
            // Make the request
            DataSharingSettings response = await analyticsAdminServiceClient.GetDataSharingSettingsAsync(request);
        }
    }
    // [END analyticsadmin_v1alpha_generated_AnalyticsAdminService_GetDataSharingSettings_async]
}


text:
import threading
import time

def print_i(num):
    time.sleep(1)
    for i in range(0, num):
        print("thread #: ", threading.active_count())
        print(num)

for i in range(0, 100):
    thread = threading.Thread(target=print_i(i))
    thread.setDaemon(True)
    thread.start()


text:
from ._permutation import Permutation
from ._partition import Partition
from ._tree import Tree
from ._gpu_tree import GPUTree
from ._exact import Exact
from ._additive import Additive
from ._linear import Linear
from ._sampling import Sampling
from ._deep import Deep


text:
package com.jessieamorris.httpserver.handlers;

import com.jessieamorris.httpserver.server.HttpRequest;
import com.jessieamorris.httpserver.server.HttpResponse;

/**
 * A blank implementation of a HttpHandler. This allows you to overwrite a single method only
 *
 * @see         HttpRequest
 * @see         HttpResponse
 * @see         IHttpHandler
 */
public abstract class SimpleHttpHandler implements IHttpHandler {
	@Override
	public void onGet(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onHead(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onPost(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onPut(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onDelete(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onTrace(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onOptions(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onConnect(HttpRequest request, HttpResponse response) throws Exception {
	}

	@Override
	public void onPatch(HttpRequest request, HttpResponse response) throws Exception {
	}
}


text:
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "pthread.h"
#include "implement.h"
#include <stdio.h>

#if defined(__CLEANUP_C)
# include <setjmp.h>
#endif

#if defined(__CLEANUP_SEH)

static DWORD
ExceptionFilter (EXCEPTION_POINTERS * ep, ULONG_PTR * ei)
{
  switch (ep->ExceptionRecord->ExceptionCode)
    {
    case EXCEPTION_PTW32_SERVICES:
      {
	DWORD param;
	DWORD numParams = ep->ExceptionRecord->NumberParameters;

	numParams = (numParams > 3) ? 3 : numParams;

	for (param = 0; param < numParams; param++)
	  {
	    ei[param] = (DWORD) ep->ExceptionRecord->ExceptionInformation[param];
	  }

	return EXCEPTION_EXECUTE_HANDLER;
	break;
      }
    default:
      {
	/*
	 * A system unexpected exception has occurred running the user's
	 * routine. We need to cleanup before letting the exception
	 * out of thread scope.
	 */
	pthread_t self = pthread_self ();

	ptw32_callUserDestroyRoutines (self);

	return EXCEPTION_CONTINUE_SEARCH;
	break;
      }
    }
}

#elif defined(__CLEANUP_CXX)

#if defined(_MSC_VER)
# include <eh.h>
#elif defined(__WATCOMC__)
# include <eh.h>
# include <exceptio.h>
#else
# if defined(__GNUC__) && __GNUC__ < 3
#   include <new.h>
# else
#   include <new>
using
  std::terminate;
using
  std::set_terminate;
# endif
#endif

#endif /* __CLEANUP_CXX */

/*
 * MSVC6 does not optimize ptw32_threadStart() safely
 * (i.e. tests/context1.c fails with "abnormal program
 * termination" in some configurations), and there's no
 * point to optimizing this routine anyway
 */
#ifdef _MSC_VER
# pragma optimize("g", off)
# pragma warning( disable : 4748 )
#endif

#if ! defined (PTW32_CONFIG_MINGW) || (defined (__MSVCRT__) && ! defined (__DMC__))
unsigned
  __stdcall
#else
void
#endif
ptw32_threadStart (void *vthreadParms)
{
  ThreadParms * threadParms = (ThreadParms *) vthreadParms;
  pthread_t self;
  ptw32_thread_t * sp;
  void * (PTW32_CDECL *start) (void *);
  void * arg;

#if defined(__CLEANUP_SEH)
  ULONG_PTR
  ei[] = { 0, 0, 0 };
#endif

#if defined(__CLEANUP_C)
  int setjmp_rc;
#endif

  ptw32_mcs_local_node_t stateLock;
  void * status = (void *) 0;

  self = threadParms->tid;
  sp = (ptw32_thread_t *) self.p;
  start = threadParms->start;
  arg = threadParms->arg;

  free (threadParms);

#if defined (PTW32_CONFIG_MINGW) && ! defined (__MSVCRT__)
  /*
   * beginthread does not return the thread id and is running
   * before it returns us the thread handle, and so we do it here.
   */
  sp->thread = GetCurrentThreadId ();
  /*
   * Here we're using stateLock as a general-purpose lock
   * to make the new thread wait until the creating thread
   * has the new handle.
   */
  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
  pthread_setspecific (ptw32_selfThreadKey, sp);
#else
  pthread_setspecific (ptw32_selfThreadKey, sp);
  ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
#endif

  sp->state = PThreadStateRunning;
  ptw32_mcs_lock_release (&stateLock);

#if defined(__CLEANUP_SEH)

  __try
  {
    /*
     * Run the caller's routine;
     */
    status = sp->exitStatus = (*start) (arg);
    sp->state = PThreadStateExiting;

#if defined(_UWIN)
    if (--pthread_count <= 0)
      exit (0);
#endif

  }
  __except (ExceptionFilter (GetExceptionInformation (), ei))
  {
    switch (ei[0])
      {
        case PTW32_EPS_CANCEL:
          status = sp->exitStatus = PTHREAD_CANCELED;
#if defined(_UWIN)
          if (--pthread_count <= 0)
        	exit (0);
#endif
          break;
        case PTW32_EPS_EXIT:
          status = sp->exitStatus;
          break;
        default:
          status = sp->exitStatus = PTHREAD_CANCELED;
          break;
      }
  }

#else /* __CLEANUP_SEH */

#if defined(__CLEANUP_C)

  setjmp_rc = setjmp (sp->start_mark);

  if (0 == setjmp_rc)
    {
      /*
       * Run the caller's routine;
       */
      status = sp->exitStatus = (*start) (arg);
      sp->state = PThreadStateExiting;
    }
  else
    {
      switch (setjmp_rc)
        {
      	  case PTW32_EPS_CANCEL:
      		status = sp->exitStatus = PTHREAD_CANCELED;
      		break;
      	  case PTW32_EPS_EXIT:
      		status = sp->exitStatus;
      		break;
      	  default:
      		status = sp->exitStatus = PTHREAD_CANCELED;
      		break;
        }
    }

#else /* __CLEANUP_C */

#if defined(__CLEANUP_CXX)

  try
  {
    status = sp->exitStatus = (*start) (arg);
    sp->state = PThreadStateExiting;
  }
  catch (ptw32_exception_cancel &)
  {
    /*
     * Thread was canceled.
     */
    status = sp->exitStatus = PTHREAD_CANCELED;
  }
  catch (ptw32_exception_exit &)
  {
    /*
     * Thread was exited via pthread_exit().
     */
    status = sp->exitStatus;
  }
  catch (...)
  {
    /*
     * Some other exception occurred. Clean up while we have
     * the opportunity, and call the terminate handler.
     */
    (void) pthread_win32_thread_detach_np ();
    terminate ();
  }

#else

#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.

#endif /* __CLEANUP_CXX */
#endif /* __CLEANUP_C */
#endif /* __CLEANUP_SEH */

#if defined(PTW32_STATIC_LIB)
  /*
   * We need to cleanup the pthread now if we have
   * been statically linked, in which case the cleanup
   * in DllMain won't get done. Joinable threads will
   * only be partially cleaned up and must be fully cleaned
   * up by pthread_join() or pthread_detach().
   *
   * Note: if this library has been statically linked,
   * implicitly created pthreads (those created
   * for Win32 threads which have called pthreads routines)
   * must be cleaned up explicitly by the application
   * by calling pthread_exit().
   * For the dll, DllMain will do the cleanup automatically.
   */
  (void) pthread_win32_thread_detach_np ();
#endif

#if ! defined (PTW32_CONFIG_MINGW) || defined (__MSVCRT__) || defined (__DMC__)
  _endthreadex ((unsigned)(size_t) status);
#else
  _endthread ();
#endif

  /*
   * Never reached.
   */

#if ! defined (PTW32_CONFIG_MINGW) || defined (__MSVCRT__) || defined (__DMC__)
  return (unsigned)(size_t) status;
#endif

}				/* ptw32_threadStart */

/*
 * Reset optimization
 */
#ifdef _MSC_VER
# pragma optimize("", on)
#endif

#if defined (PTW32_USES_SEPARATE_CRT) && defined (__cplusplus)
ptw32_terminate_handler
pthread_win32_set_terminate_np(ptw32_terminate_handler termFunction)
{
  return set_terminate(termFunction);
}
#endif


text:
import { Annotation } from "../editor/Annotation";
import { Delta, Document } from "editor-document";
import { delayedCall } from "../lib/delayedCall";
import { DelayedFunctionCall } from "../lib/DelayedFunctionCall";
import { WorkerCallback } from "./WorkerCallback";

/**
 * A wrapper around the standard worker thread callback interface for use with Language Worker implementations.
 * Language Wroker implementations will use this as a base class.
 */
export class Mirror {

    /**
     *
     */
    protected host: WorkerCallback;

    /**
     * The doc(ument) property mirrors the value in the main (UI) thread.
     * The synchronization is performed by the Mirror base class.
     */
    protected doc: Document;

    /**
     * The mirror will schedule calls to the derived class onUpdate method
     * approx 500ms after each 'change' event where deltas are received and
     * applied to the mirror document.
     *
     * The derived class may also schedule updates when options change.
     */
    protected deferredUpdate: DelayedFunctionCall;

    /**
     * This timeout is used to control the delay between editor changes
     * and the begin of a validation process. It is typically set to 500ms.
     */
    private $timeout: number;

    /**
     *
     */
    constructor(host: WorkerCallback, timeout = 500) {
        if (typeof host !== 'object') {
            throw new TypeError("host must be a WorkerCallback.");
        }
        this.host = host;
        this.$timeout = timeout;
        this.doc = new Document("");

        const deferredUpdate = this.deferredUpdate = delayedCall(this.onUpdate.bind(this));

        host.on('change', (e: { data: Delta[] }) => {
            this.doc.applyDeltas(e.data);
            if (this.$timeout) {
                return deferredUpdate.schedule(this.$timeout);
            }
            else {
                // I'm not sure that we need to special-case this code.
                this.onUpdate();
            }
        });
    }

    /**
     * @param timeout
     */
    setTimeout(timeout: number): void {
        this.$timeout = timeout;
    }

    /**
     * @param value The string value to set into the mirror document.
     * @param scheduleUpdate Determines whether a call to onUpdate() method will be scheduled.
     *
     * By default, calls to onUpdate are scheduled. However, for testing, it is convenient not
     * to schedule the onUpdate() method call and instead to call onUpdate() synchronously
     * in a separate call.
     */
    setValue(value: string, scheduleUpdate = true): void {
        this.doc.setValue(value);
        if (scheduleUpdate) {
            this.deferredUpdate.schedule(this.$timeout);
        }
    }

    /**
     * Handles a request from the main thread for the value (string) of the Document in the mirror.
     */
    getValue(callbackId: number): void {
        this.host.callback(this.doc.getValue(), callbackId);
    }

    /**
     * Used to send annotations from the worker to the main thread.
     */
    emitAnnotations(annotations: Annotation[]): void {
        this.host.emit("annotations", annotations);
    }

    /**
     * Called after the timeout period. Derived classes will normally perform
     * a computationally expensive analysis then report annotations to the
     * host.
     */
    protected onUpdate() {
        // abstract method
    }

    /**
     *
     */
    isPending(): boolean {
        return this.deferredUpdate.isPending();
    }
}