<div dir="ltr">Looks like clang warns on some parts of this change. Can you fix?<div><br></div><div><div>[1278/3168] Building CXX object lib/Target/Hexagon/CMakeFiles/LLVMHexagonCodeGen.dir/HexagonConstExtenders.cpp.o</div><div>/ssd/llvm-project/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp:421:16: warning: unused function 'operator<<' [-Wunused-function]</div><div>  raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &P) {</div><div>               ^</div><div>/ssd/llvm-project/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp:459:16: warning: unused function 'operator<<' [-Wunused-function]</div><div>  raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtDesc &ED) {</div><div>               ^</div><div>/ssd/llvm-project/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp:520:16: warning: unused function 'operator<<' [-Wunused-function]</div><div>  raw_ostream &operator<< (raw_ostream &OS, const PrintIMap &P) {</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Oct 13, 2017 at 12:02 PM, Krzysztof Parzyszek via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: kparzysz<br>
Date: Fri Oct 13 12:02:59 2017<br>
New Revision: 315735<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=315735&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=315735&view=rev</a><br>
Log:<br>
[Hexagon] Minimize number of repeated constant extenders<br>
<br>
Each constant extender requires an extra instruction, which adds to the<br>
code size and also reduces the number of available slots in an instruction<br>
packet. In most cases, the value of a repeated constant extender could be<br>
loaded into a register, and the instructions using the extender could be<br>
replaced with their counterparts that use that register instead.<br>
<br>
This patch adds a pass that tries to reduce the number of constant<br>
extenders, including extenders which differ only in an immediate offset<br>
known at compile time, e.g. @global and @global+12.<br>
<br>
Added:<br>
    llvm/trunk/lib/Target/Hexagon/<wbr>HexagonConstExtenders.cpp<br>
    llvm/trunk/test/CodeGen/<wbr>Hexagon/cext-opt-basic.mir<br>
Modified:<br>
    llvm/trunk/lib/Target/Hexagon/<wbr>CMakeLists.txt<br>
    llvm/trunk/lib/Target/Hexagon/<wbr>HexagonTargetMachine.cpp<br>
    llvm/trunk/test/CodeGen/<wbr>Hexagon/zextloadi1.ll<br>
<br>
Modified: llvm/trunk/lib/Target/Hexagon/<wbr>CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/CMakeLists.txt?rev=315735&r1=315734&r2=315735&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/Target/<wbr>Hexagon/CMakeLists.txt?rev=<wbr>315735&r1=315734&r2=315735&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Target/Hexagon/<wbr>CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Target/Hexagon/<wbr>CMakeLists.txt Fri Oct 13 12:02:59 2017<br>
@@ -20,6 +20,7 @@ add_llvm_target(HexagonCodeGen<br>
   HexagonBranchRelaxation.cpp<br>
   HexagonCFGOptimizer.cpp<br>
   HexagonCommonGEP.cpp<br>
+  HexagonConstExtenders.cpp<br>
   HexagonConstPropagation.cpp<br>
   HexagonCopyToCombine.cpp<br>
   HexagonEarlyIfConv.cpp<br>
<br>
Added: llvm/trunk/lib/Target/Hexagon/<wbr>HexagonConstExtenders.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonConstExtenders.cpp?rev=315735&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/Target/<wbr>Hexagon/HexagonConstExtenders.<wbr>cpp?rev=315735&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Target/Hexagon/<wbr>HexagonConstExtenders.cpp (added)<br>
+++ llvm/trunk/lib/Target/Hexagon/<wbr>HexagonConstExtenders.cpp Fri Oct 13 12:02:59 2017<br>
@@ -0,0 +1,1854 @@<br>
+//===- HexagonConstExtenders.cpp ------------------------------<wbr>------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "HexagonInstrInfo.h"<br>
+#include "HexagonRegisterInfo.h"<br>
+#include "HexagonSubtarget.h"<br>
+#include "llvm/ADT/SmallVector.h"<br>
+#include "llvm/CodeGen/<wbr>MachineDominators.h"<br>
+#include "llvm/CodeGen/<wbr>MachineFunctionPass.h"<br>
+#include "llvm/CodeGen/<wbr>MachineInstrBuilder.h"<br>
+#include "llvm/CodeGen/<wbr>MachineRegisterInfo.h"<br>
+#include "llvm/Support/CommandLine.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+#include "llvm/Pass.h"<br>
+#include <map><br>
+#include <set><br>
+#include <utility><br>
+#include <vector><br>
+<br>
+#define DEBUG_TYPE "hexagon-cext-opt"<br>
+<br>
+using namespace llvm;<br>
+<br>
+static cl::opt<unsigned> CountThreshold("hexagon-cext-<wbr>threshold",<br>
+  cl::init(3), cl::Hidden, cl::ZeroOrMore,<br>
+  cl::desc("Minimum number of extenders to trigger replacement"));<br>
+<br>
+static cl::opt<unsigned> ReplaceLimit("hexagon-cext-<wbr>limit", cl::init(0),<br>
+  cl::Hidden, cl::ZeroOrMore, cl::desc("Maximum number of replacements"));<br>
+<br>
+namespace llvm {<br>
+  void initializeHexagonConstExtender<wbr>sPass(PassRegistry&);<br>
+  FunctionPass *createHexagonConstExtenders()<wbr>;<br>
+}<br>
+<br>
+namespace {<br>
+  struct OffsetRange {<br>
+    int32_t Min = INT_MIN, Max = INT_MAX;<br>
+    uint8_t Align = 1;<br>
+<br>
+    OffsetRange() = default;<br>
+    OffsetRange(int32_t L, int32_t H, uint8_t A)<br>
+      : Min(L), Max(H), Align(A) {}<br>
+    OffsetRange &intersect(OffsetRange A) {<br>
+      Align = std::max(Align, A.Align);<br>
+      Min = std::max(Min, A.Min);<br>
+      Max = std::min(Max, A.Max);<br>
+      // Canonicalize empty ranges.<br>
+      if (Min > Max)<br>
+        std::tie(Min, Max, Align) = std::make_tuple(0, -1, 1);<br>
+      return *this;<br>
+    }<br>
+    OffsetRange &shift(int32_t S) {<br>
+      assert(alignTo(std::abs(S), Align) == uint64_t(std::abs(S)));<br>
+      Min += S;<br>
+      Max += S;<br>
+      return *this;<br>
+    }<br>
+    OffsetRange &extendBy(int32_t D) {<br>
+      // If D < 0, extend Min, otherwise extend Max.<br>
+      if (D < 0)<br>
+        Min = (INT_MIN-D < Min) ? Min+D : INT_MIN;<br>
+      else<br>
+        Max = (INT_MAX-D > Max) ? Max+D : INT_MAX;<br>
+      return *this;<br>
+    }<br>
+    bool empty() const {<br>
+      return Min > Max;<br>
+    }<br>
+    bool contains(int32_t V) const {<br>
+      return Min <= V && V <= Max && (V % Align) == 0;<br>
+    }<br>
+    bool operator==(const OffsetRange &R) const {<br>
+      return Min == R.Min && Max == R.Max && Align == R.Align;<br>
+    }<br>
+    bool operator!=(const OffsetRange &R) const {<br>
+      return !operator==(R);<br>
+    }<br>
+    bool operator<(const OffsetRange &R) const {<br>
+      if (Min != R.Min)<br>
+        return Min < R.Min;<br>
+      if (Max != R.Max)<br>
+        return Max < R.Max;<br>
+      return Align < R.Align;<br>
+    }<br>
+    static OffsetRange zero() { return {0, 0, 1}; }<br>
+  };<br>
+<br>
+  struct RangeTree {<br>
+    struct Node {<br>
+      Node(const OffsetRange &R) : MaxEnd(R.Max), Range(R) {}<br>
+      unsigned Height = 1;<br>
+      unsigned Count = 1;<br>
+      int32_t MaxEnd;<br>
+      const OffsetRange &Range;<br>
+      Node *Left = nullptr, *Right = nullptr;<br>
+    };<br>
+<br>
+    Node *Root = nullptr;<br>
+<br>
+    void add(const OffsetRange &R) {<br>
+      Root = add(Root, R);<br>
+    }<br>
+    void erase(const Node *N) {<br>
+      Root = remove(Root, N);<br>
+      delete N;<br>
+    }<br>
+    void order(SmallVectorImpl<Node*> &Seq) const {<br>
+      order(Root, Seq);<br>
+    }<br>
+    SmallVector<Node*,8> nodesWith(int32_t P, bool CheckAlign = true) {<br>
+      SmallVector<Node*,8> Nodes;<br>
+      nodesWith(Root, P, CheckAlign, Nodes);<br>
+      return Nodes;<br>
+    }<br>
+    void dump() const;<br>
+    ~RangeTree() {<br>
+      SmallVector<Node*,8> Nodes;<br>
+      order(Nodes);<br>
+      for (Node *N : Nodes)<br>
+        delete N;<br>
+    }<br>
+<br>
+  private:<br>
+    void dump(const Node *N) const;<br>
+    void order(Node *N, SmallVectorImpl<Node*> &Seq) const;<br>
+    void nodesWith(Node *N, int32_t P, bool CheckA,<br>
+                   SmallVectorImpl<Node*> &Seq) const;<br>
+<br>
+    Node *add(Node *N, const OffsetRange &R);<br>
+    Node *remove(Node *N, const Node *D);<br>
+    Node *rotateLeft(Node *Lower, Node *Higher);<br>
+    Node *rotateRight(Node *Lower, Node *Higher);<br>
+    unsigned height(Node *N) {<br>
+      return N != nullptr ? N->Height : 0;<br>
+    }<br>
+    Node *update(Node *N) {<br>
+      assert(N != nullptr);<br>
+      N->Height = 1 + std::max(height(N->Left), height(N->Right));<br>
+      if (N->Left)<br>
+        N->MaxEnd = std::max(N->MaxEnd, N->Left->MaxEnd);<br>
+      if (N->Right)<br>
+        N->MaxEnd = std::max(N->MaxEnd, N->Right->MaxEnd);<br>
+      return N;<br>
+    }<br>
+    Node *rebalance(Node *N) {<br>
+      assert(N != nullptr);<br>
+      int32_t Balance = height(N->Right) - height(N->Left);<br>
+      if (Balance < -1)<br>
+        return rotateRight(N->Left, N);<br>
+      if (Balance > 1)<br>
+        return rotateLeft(N->Right, N);<br>
+      return N;<br>
+    }<br>
+  };<br>
+<br>
+  struct Loc {<br>
+    MachineBasicBlock *Block = nullptr;<br>
+    MachineBasicBlock::iterator At;<br>
+<br>
+    Loc(MachineBasicBlock *B, MachineBasicBlock::iterator It)<br>
+      : Block(B), At(It) {<br>
+      if (B->end() == It) {<br>
+        Pos = -1;<br>
+      } else {<br>
+        assert(It->getParent() == B);<br>
+        Pos = std::distance(B->begin(), It);<br>
+      }<br>
+    }<br>
+    bool operator<(Loc A) const {<br>
+      if (Block != A.Block)<br>
+        return Block->getNumber() < A.Block->getNumber();<br>
+      if (A.Pos == -1)<br>
+        return Pos != A.Pos;<br>
+      return Pos != -1 && Pos < A.Pos;<br>
+    }<br>
+  private:<br>
+    int Pos = 0;<br>
+  };<br>
+<br>
+  struct HexagonConstExtenders : public MachineFunctionPass {<br>
+    static char ID;<br>
+    HexagonConstExtenders() : MachineFunctionPass(ID) {}<br>
+<br>
+    void getAnalysisUsage(AnalysisUsage &AU) const override {<br>
+      AU.addRequired<<wbr>MachineDominatorTree>();<br>
+      AU.addPreserved<<wbr>MachineDominatorTree>();<br>
+      MachineFunctionPass::<wbr>getAnalysisUsage(AU);<br>
+    }<br>
+<br>
+    StringRef getPassName() const override {<br>
+      return "Hexagon constant-extender optimization";<br>
+    }<br>
+    bool runOnMachineFunction(<wbr>MachineFunction &MF) override;<br>
+<br>
+  private:<br>
+    struct Register {<br>
+      Register() = default;<br>
+      Register(unsigned R, unsigned S) : Reg(R), Sub(S) {}<br>
+      Register(const MachineOperand &Op)<br>
+        : Reg(Op.getReg()), Sub(Op.getSubReg()) {}<br>
+      Register &operator=(const MachineOperand &Op) {<br>
+        if (Op.isReg()) {<br>
+          Reg = Op.getReg();<br>
+          Sub = Op.getSubReg();<br>
+        } else if (Op.isFI()) {<br>
+          Reg = TargetRegisterInfo::<wbr>index2StackSlot(Op.getIndex())<wbr>;<br>
+        }<br>
+        return *this;<br>
+      }<br>
+      bool isVReg() const {<br>
+        return Reg != 0 && !TargetRegisterInfo::<wbr>isStackSlot(Reg) &&<br>
+               TargetRegisterInfo::<wbr>isVirtualRegister(Reg);<br>
+      }<br>
+      bool isSlot() const {<br>
+        return Reg != 0 && TargetRegisterInfo::<wbr>isStackSlot(Reg);<br>
+      }<br>
+      operator MachineOperand() const {<br>
+        if (isVReg())<br>
+          return MachineOperand::CreateReg(Reg, /*Def*/false, /*Imp*/false,<br>
+                          /*Kill*/false, /*Dead*/false, /*Undef*/false,<br>
+                          /*EarlyClobber*/false, Sub);<br>
+        if (TargetRegisterInfo::<wbr>isStackSlot(Reg)) {<br>
+          int FI = TargetRegisterInfo::<wbr>stackSlot2Index(Reg);<br>
+          return MachineOperand::CreateFI(FI);<br>
+        }<br>
+        llvm_unreachable("Cannot create MachineOperand");<br>
+      }<br>
+      bool operator==(Register R) const { return Reg == R.Reg && Sub == R.Sub; }<br>
+      bool operator!=(Register R) const { return !operator==(R); }<br>
+      bool operator<(Register R) const {<br>
+        // For std::map.<br>
+        return Reg < R.Reg || (Reg == R.Reg && Sub < R.Sub);<br>
+      }<br>
+      unsigned Reg = 0, Sub = 0;<br>
+    };<br>
+<br>
+    struct ExtExpr {<br>
+      // A subexpression in which the extender is used. In general, this<br>
+      // represents an expression where adding D to the extender will be<br>
+      // equivalent to adding D to the expression as a whole. In other<br>
+      // words, expr(add(##V,D) = add(expr(##V),D).<br>
+<br>
+      // The original motivation for this are the io/ur addressing modes,<br>
+      // where the offset is extended. Consider the io example:<br>
+      // In memw(Rs+##V), the ##V could be replaced by a register Rt to<br>
+      // form the rr mode: memw(Rt+Rs<<0). In such case, however, the<br>
+      // register Rt must have exactly the value of ##V. If there was<br>
+      // another instruction memw(Rs+##V+4), it would need a different Rt.<br>
+      // Now, if Rt was initialized as "##V+Rs<<0", both of these<br>
+      // instructions could use the same Rt, just with different offsets.<br>
+      // Here it's clear that "initializer+4" should be the same as if<br>
+      // the offset 4 was added to the ##V in the initializer.<br>
+<br>
+      // The only kinds of expressions that support the requirement of<br>
+      // commuting with addition are addition and subtraction from ##V.<br>
+      // Include shifting the Rs to account for the ur addressing mode:<br>
+      //   ##Val + Rs << S<br>
+      //   ##Val - Rs<br>
+      Register Rs;<br>
+      unsigned S = 0;<br>
+      bool Neg = false;<br>
+<br>
+      ExtExpr() = default;<br>
+      ExtExpr(Register RS, bool NG, unsigned SH) : Rs(RS), S(SH), Neg(NG) {}<br>
+      // Expression is trivial if it does not modify the extender.<br>
+      bool trivial() const {<br>
+        return Rs.Reg == 0;<br>
+      }<br>
+      bool operator==(const ExtExpr &Ex) const {<br>
+        return Rs == Ex.Rs && S == Ex.S && Neg == Ex.Neg;<br>
+      }<br>
+      bool operator!=(const ExtExpr &Ex) const {<br>
+        return !operator==(Ex);<br>
+      }<br>
+      bool operator<(const ExtExpr &Ex) const {<br>
+        if (Rs != Ex.Rs)<br>
+          return Rs < Ex.Rs;<br>
+        if (S != Ex.S)<br>
+          return S < Ex.S;<br>
+        return !Neg && Ex.Neg;<br>
+      }<br>
+    };<br>
+<br>
+    struct ExtDesc {<br>
+      MachineInstr *UseMI = nullptr;<br>
+      unsigned OpNum = -1u;<br>
+      // The subexpression in which the extender is used (e.g. address<br>
+      // computation).<br>
+      ExtExpr Expr;<br>
+      // Optional register that is assigned the value of Expr.<br>
+      Register Rd;<br>
+      // Def means that the output of the instruction may differ from the<br>
+      // original by a constant c, and that the difference can be corrected<br>
+      // by adding/subtracting c in all users of the defined register.<br>
+      bool IsDef = false;<br>
+<br>
+      MachineOperand &getOp() {<br>
+        return UseMI->getOperand(OpNum);<br>
+      }<br>
+      const MachineOperand &getOp() const {<br>
+        return UseMI->getOperand(OpNum);<br>
+      }<br>
+    };<br>
+<br>
+    struct ExtRoot {<br>
+      union {<br>
+        const ConstantFP *CFP;  // MO_FPImmediate<br>
+        const char *SymbolName; // MO_ExternalSymbol<br>
+        const GlobalValue *GV;  // MO_GlobalAddress<br>
+        const BlockAddress *BA; // MO_BlockAddress<br>
+        int64_t ImmVal;         // MO_Immediate, MO_TargetIndex,<br>
+                                // and MO_ConstantPoolIndex<br>
+      } V;<br>
+      unsigned Kind;            // Same as in MachineOperand.<br>
+      unsigned char TF;         // TargetFlags.<br>
+<br>
+      ExtRoot(const MachineOperand &Op);<br>
+      bool operator==(const ExtRoot &ER) const {<br>
+        return Kind == ER.Kind && V.ImmVal == ER.V.ImmVal;<br>
+      }<br>
+      bool operator!=(const ExtRoot &ER) const {<br>
+        return !operator==(ER);<br>
+      }<br>
+      bool operator<(const ExtRoot &ER) const;<br>
+    };<br>
+<br>
+    struct ExtValue : public ExtRoot {<br>
+      int32_t Offset;<br>
+<br>
+      ExtValue(const MachineOperand &Op);<br>
+      ExtValue(const ExtDesc &ED) : ExtValue(ED.getOp()) {}<br>
+      ExtValue(const ExtRoot &ER, int32_t Off) : ExtRoot(ER), Offset(Off) {}<br>
+      bool operator<(const ExtValue &EV) const;<br>
+      bool operator==(const ExtValue &EV) const {<br>
+        return ExtRoot(*this) == ExtRoot(EV) && Offset == EV.Offset;<br>
+      }<br>
+      bool operator!=(const ExtValue &EV) const {<br>
+        return !operator==(EV);<br>
+      }<br>
+      explicit operator MachineOperand() const;<br>
+    };<br>
+<br>
+    using IndexList = SetVector<unsigned>;<br>
+    using ExtenderInit = std::pair<ExtValue, ExtExpr>;<br>
+    using AssignmentMap = std::map<ExtenderInit, IndexList>;<br>
+    using LocDefMap = std::map<Loc, IndexList>;<br>
+<br>
+    const HexagonInstrInfo *HII = nullptr;<br>
+    const HexagonRegisterInfo *HRI = nullptr;<br>
+    MachineDominatorTree *MDT = nullptr;<br>
+    MachineRegisterInfo *MRI = nullptr;<br>
+    std::vector<ExtDesc> Extenders;<br>
+    std::vector<unsigned> NewRegs;<br>
+<br>
+    bool isStoreImmediate(unsigned Opc) const;<br>
+    bool isRegOffOpcode(unsigned ExtOpc) const ;<br>
+    unsigned getRegOffOpcode(unsigned ExtOpc) const;<br>
+    unsigned getDirectRegReplacement(<wbr>unsigned ExtOpc) const;<br>
+    OffsetRange getOffsetRange(Register R, const MachineInstr &MI) const;<br>
+    OffsetRange getOffsetRange(const ExtDesc &ED) const;<br>
+    OffsetRange getOffsetRange(Register Rd) const;<br>
+<br>
+    void recordExtender(MachineInstr &MI, unsigned OpNum);<br>
+    void collectInstr(MachineInstr &MI);<br>
+    void collect(MachineFunction &MF);<br>
+    void assignInits(const ExtRoot &ER, unsigned Begin, unsigned End,<br>
+                     AssignmentMap &IMap);<br>
+    void calculatePlacement(const ExtenderInit &ExtI, const IndexList &Refs,<br>
+                            LocDefMap &Defs);<br>
+    Register insertInitializer(Loc DefL, const ExtenderInit &ExtI);<br>
+    bool replaceInstrExact(const ExtDesc &ED, Register ExtR);<br>
+    bool replaceInstrExpr(const ExtDesc &ED, const ExtenderInit &ExtI,<br>
+                          Register ExtR, int32_t &Diff);<br>
+    bool replaceInstr(unsigned Idx, Register ExtR, const ExtenderInit &ExtI);<br>
+    bool replaceExtenders(const AssignmentMap &IMap);<br>
+<br>
+    unsigned getOperandIndex(const MachineInstr &MI,<br>
+                             const MachineOperand &Op) const;<br>
+    const MachineOperand &getPredicateOp(const MachineInstr &MI) const;<br>
+    const MachineOperand &getLoadResultOp(const MachineInstr &MI) const;<br>
+    const MachineOperand &getStoredValueOp(const MachineInstr &MI) const;<br>
+<br>
+    friend struct PrintRegister;<br>
+    friend struct PrintExpr;<br>
+    friend struct PrintInit;<br>
+    friend struct PrintIMap;<br>
+    friend raw_ostream &operator<< (raw_ostream &OS,<br>
+                                    const struct PrintRegister &P);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintExpr &P);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintInit &P);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const ExtDesc &ED);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const ExtRoot &ER);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const ExtValue &EV);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const OffsetRange &OR);<br>
+    friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintIMap &P);<br>
+  };<br>
+<br>
+  using HCE = HexagonConstExtenders;<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const OffsetRange &OR) {<br>
+    if (OR.Min > OR.Max)<br>
+      OS << '!';<br>
+    OS << '[' << OR.Min << ',' << OR.Max << "]a" << unsigned(OR.Align);<br>
+    return OS;<br>
+  }<br>
+<br>
+  struct PrintRegister {<br>
+    PrintRegister(HCE::Register R, const HexagonRegisterInfo &I)<br>
+      : Rs(R), HRI(I) {}<br>
+    HCE::Register Rs;<br>
+    const HexagonRegisterInfo &HRI;<br>
+  };<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &P) {<br>
+    if (P.Rs.Reg != 0)<br>
+      OS << PrintReg(P.Rs.Reg, &P.HRI, P.Rs.Sub);<br>
+    else<br>
+      OS << "noreg";<br>
+    return OS;<br>
+  }<br>
+<br>
+  struct PrintExpr {<br>
+    PrintExpr(const HCE::ExtExpr &E, const HexagonRegisterInfo &I)<br>
+      : Ex(E), HRI(I) {}<br>
+    const HCE::ExtExpr &Ex;<br>
+    const HexagonRegisterInfo &HRI;<br>
+  };<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const PrintExpr &P) {<br>
+    OS << "## " << (P.Ex.Neg ? "- " : "+ ");<br>
+    if (P.Ex.Rs.Reg != 0)<br>
+      OS << PrintReg(P.Ex.Rs.Reg, &P.HRI, P.Ex.Rs.Sub);<br>
+    else<br>
+      OS << "__";<br>
+    OS << " << " << P.Ex.S;<br>
+    return OS;<br>
+  }<br>
+<br>
+  struct PrintInit {<br>
+    PrintInit(const HCE::ExtenderInit &EI, const HexagonRegisterInfo &I)<br>
+      : ExtI(EI), HRI(I) {}<br>
+    const HCE::ExtenderInit &ExtI;<br>
+    const HexagonRegisterInfo &HRI;<br>
+  };<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const PrintInit &P) {<br>
+    OS << '[' << P.ExtI.first << ", "<br>
+       << PrintExpr(P.ExtI.second, P.HRI) << ']';<br>
+    return OS;<br>
+  }<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtDesc &ED) {<br>
+    assert(ED.OpNum != -1u);<br>
+    const MachineBasicBlock &MBB = *ED.getOp().getParent()-><wbr>getParent();<br>
+    const MachineFunction &MF = *MBB.getParent();<br>
+    const auto &HRI = *MF.getSubtarget<<wbr>HexagonSubtarget>().<wbr>getRegisterInfo();<br>
+    OS << "bb#" << MBB.getNumber() << ": ";<br>
+    if (ED.Rd.Reg != 0)<br>
+      OS << PrintReg(ED.Rd.Reg, &HRI, ED.Rd.Sub);<br>
+    else<br>
+      OS << "__";<br>
+    OS << " = " << PrintExpr(ED.Expr, HRI);<br>
+    if (ED.IsDef)<br>
+      OS << ", def";<br>
+    return OS;<br>
+  }<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtRoot &ER) {<br>
+    switch (ER.Kind) {<br>
+      case MachineOperand::MO_Immediate:<br>
+        OS << "imm:" << ER.V.ImmVal;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>FPImmediate:<br>
+        OS << "fpi:" << *ER.V.CFP;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>ExternalSymbol:<br>
+        OS << "sym:" << *ER.V.SymbolName;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>GlobalAddress:<br>
+        OS << "gad:" << ER.V.GV->getName();<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>BlockAddress:<br>
+        OS << "blk:" << *<a href="http://ER.V.BA" rel="noreferrer" target="_blank">ER.V.BA</a>;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>TargetIndex:<br>
+        OS << "tgi:" << ER.V.ImmVal;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>ConstantPoolIndex:<br>
+        OS << "cpi:" << ER.V.ImmVal;<br>
+        break;<br>
+      case MachineOperand::MO_<wbr>JumpTableIndex:<br>
+        OS << "jti:" << ER.V.ImmVal;<br>
+        break;<br>
+      default:<br>
+        OS << "???:" << ER.V.ImmVal;<br>
+        break;<br>
+    }<br>
+    return OS;<br>
+  }<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtValue &EV) {<br>
+    OS << HCE::ExtRoot(EV) << "  off:" << EV.Offset;<br>
+    return OS;<br>
+  }<br>
+<br>
+  struct PrintIMap {<br>
+    PrintIMap(const HCE::AssignmentMap &M, const HexagonRegisterInfo &I)<br>
+      : IMap(M), HRI(I) {}<br>
+    const HCE::AssignmentMap &IMap;<br>
+    const HexagonRegisterInfo &HRI;<br>
+  };<br>
+<br>
+  raw_ostream &operator<< (raw_ostream &OS, const PrintIMap &P) {<br>
+    OS << "{\n";<br>
+    for (const std::pair<HCE::ExtenderInit,<wbr>HCE::IndexList> &Q : P.IMap) {<br>
+      OS << "  " << PrintInit(Q.first, P.HRI) << " -> {";<br>
+      for (unsigned I : Q.second)<br>
+        OS << ' ' << I;<br>
+      OS << " }\n";<br>
+    }<br>
+    OS << "}\n";<br>
+    return OS;<br>
+  }<br>
+}<br>
+<br>
+INITIALIZE_PASS_BEGIN(<wbr>HexagonConstExtenders, "hexagon-cext-opt",<br>
+      "Hexagon constant-extender optimization", false, false)<br>
+INITIALIZE_PASS_DEPENDENCY(<wbr>MachineDominatorTree)<br>
+INITIALIZE_PASS_END(<wbr>HexagonConstExtenders, "hexagon-cext-opt",<br>
+      "Hexagon constant-extender optimization", false, false)<br>
+<br>
+static unsigned ReplaceCounter = 0;<br>
+<br>
+char HCE::ID = 0;<br>
+<br>
+void RangeTree::dump() const {<br>
+  dbgs() << "Root: " << Root << '\n';<br>
+  if (Root)<br>
+    dump(Root);<br>
+}<br>
+<br>
+void RangeTree::dump(const Node *N) const {<br>
+  dbgs() << "Node: " << N << '\n';<br>
+  dbgs() << "  Height: " << N->Height << '\n';<br>
+  dbgs() << "  Count: " << N->Count << '\n';<br>
+  dbgs() << "  MaxEnd: " << N->MaxEnd << '\n';<br>
+  dbgs() << "  Range: " << N->Range << '\n';<br>
+  dbgs() << "  Left: " << N->Left << '\n';<br>
+  dbgs() << "  Right: " << N->Right << "\n\n";<br>
+<br>
+  if (N->Left)<br>
+    dump(N->Left);<br>
+  if (N->Right)<br>
+    dump(N->Right);<br>
+}<br>
+<br>
+void RangeTree::order(Node *N, SmallVectorImpl<Node*> &Seq) const {<br>
+  if (N == nullptr)<br>
+    return;<br>
+  order(N->Left, Seq);<br>
+  Seq.push_back(N);<br>
+  order(N->Right, Seq);<br>
+}<br>
+<br>
+void RangeTree::nodesWith(Node *N, int32_t P, bool CheckA,<br>
+      SmallVectorImpl<Node*> &Seq) const {<br>
+  if (N == nullptr || N->MaxEnd < P)<br>
+    return;<br>
+  nodesWith(N->Left, P, CheckA, Seq);<br>
+  if (N->Range.Min <= P) {<br>
+    if ((CheckA && N->Range.contains(P)) || (!CheckA && P <= N->Range.Max))<br>
+      Seq.push_back(N);<br>
+    nodesWith(N->Right, P, CheckA, Seq);<br>
+  }<br>
+}<br>
+<br>
+RangeTree::Node *RangeTree::add(Node *N, const OffsetRange &R) {<br>
+  if (N == nullptr)<br>
+    return new Node(R);<br>
+<br>
+  if (N->Range == R) {<br>
+    N->Count++;<br>
+    return N;<br>
+  }<br>
+<br>
+  if (R < N->Range)<br>
+    N->Left = add(N->Left, R);<br>
+  else<br>
+    N->Right = add(N->Right, R);<br>
+  return rebalance(update(N));<br>
+}<br>
+<br>
+RangeTree::Node *RangeTree::remove(Node *N, const Node *D) {<br>
+  assert(N != nullptr);<br>
+<br>
+  if (N != D) {<br>
+    assert(N->Range != D->Range && "N and D should not be equal");<br>
+    if (D->Range < N->Range)<br>
+      N->Left = remove(N->Left, D);<br>
+    else<br>
+      N->Right = remove(N->Right, D);<br>
+    return rebalance(update(N));<br>
+  }<br>
+<br>
+  // We got to the node we need to remove. If any of its children are<br>
+  // missing, simply replace it with the other child.<br>
+  if (N->Left == nullptr || N->Right == nullptr)<br>
+    return (N->Left == nullptr) ? N->Right : N->Left;<br>
+<br>
+  // Find the rightmost child of N->Left, remove it and plug it in place<br>
+  // of N.<br>
+  Node *M = N->Left;<br>
+  while (M->Right)<br>
+    M = M->Right;<br>
+  M->Left = remove(N->Left, M);<br>
+  M->Right = N->Right;<br>
+  return rebalance(update(M));<br>
+}<br>
+<br>
+RangeTree::Node *RangeTree::rotateLeft(Node *Lower, Node *Higher) {<br>
+  assert(Higher->Right == Lower);<br>
+  // The Lower node is on the right from Higher. Make sure that Lower's<br>
+  // balance is greater to the right. Otherwise the rotation will create<br>
+  // an unbalanced tree again.<br>
+  if (height(Lower->Left) > height(Lower->Right))<br>
+    Lower = rotateRight(Lower->Left, Lower);<br>
+  assert(height(Lower->Left) <= height(Lower->Right));<br>
+  Higher->Right = Lower->Left;<br>
+  update(Higher);<br>
+  Lower->Left = Higher;<br>
+  update(Lower);<br>
+  return Lower;<br>
+}<br>
+<br>
+RangeTree::Node *RangeTree::rotateRight(Node *Lower, Node *Higher) {<br>
+  assert(Higher->Left == Lower);<br>
+  // The Lower node is on the left from Higher. Make sure that Lower's<br>
+  // balance is greater to the left. Otherwise the rotation will create<br>
+  // an unbalanced tree again.<br>
+  if (height(Lower->Left) < height(Lower->Right))<br>
+    Lower = rotateLeft(Lower->Right, Lower);<br>
+  assert(height(Lower->Left) >= height(Lower->Right));<br>
+  Higher->Left = Lower->Right;<br>
+  update(Higher);<br>
+  Lower->Right = Higher;<br>
+  update(Lower);<br>
+  return Lower;<br>
+}<br>
+<br>
+<br>
+HCE::ExtRoot::ExtRoot(const MachineOperand &Op) {<br>
+  // Always store ImmVal, since it's the field used for comparisons.<br>
+  V.ImmVal = 0;<br>
+  if (Op.isImm())<br>
+    ; // Keep 0. Do not use Op.getImm() for value here (treat 0 as the root).<br>
+  else if (Op.isFPImm())<br>
+    V.CFP = Op.getFPImm();<br>
+  else if (Op.isSymbol())<br>
+    V.SymbolName = Op.getSymbolName();<br>
+  else if (Op.isGlobal())<br>
+    V.GV = Op.getGlobal();<br>
+  else if (Op.isBlockAddress())<br>
+    <a href="http://V.BA" rel="noreferrer" target="_blank">V.BA</a> = Op.getBlockAddress();<br>
+  else if (Op.isCPI() || Op.isTargetIndex() || Op.isJTI())<br>
+    V.ImmVal = Op.getIndex();<br>
+  else<br>
+    llvm_unreachable("Unexpected operand type");<br>
+<br>
+  Kind = Op.getType();<br>
+  TF = Op.getTargetFlags();<br>
+}<br>
+<br>
+bool HCE::ExtRoot::operator< (const HCE::ExtRoot &ER) const {<br>
+  if (Kind != ER.Kind)<br>
+    return Kind < ER.Kind;<br>
+  switch (Kind) {<br>
+    case MachineOperand::MO_Immediate:<br>
+    case MachineOperand::MO_<wbr>TargetIndex:<br>
+    case MachineOperand::MO_<wbr>ConstantPoolIndex:<br>
+    case MachineOperand::MO_<wbr>JumpTableIndex:<br>
+      return V.ImmVal < ER.V.ImmVal;<br>
+    case MachineOperand::MO_<wbr>FPImmediate: {<br>
+      const APFloat &ThisF = V.CFP->getValueAPF();<br>
+      const APFloat &OtherF = ER.V.CFP->getValueAPF();<br>
+      return ThisF.bitcastToAPInt().ult(<wbr>OtherF.bitcastToAPInt());<br>
+    }<br>
+    case MachineOperand::MO_<wbr>ExternalSymbol:<br>
+      return StringRef(V.SymbolName) < StringRef(ER.V.SymbolName);<br>
+    case MachineOperand::MO_<wbr>GlobalAddress:<br>
+      assert(V.GV->hasName() && ER.V.GV->hasName());<br>
+      return V.GV->getName() < ER.V.GV->getName();<br>
+    case MachineOperand::MO_<wbr>BlockAddress: {<br>
+      const BasicBlock *ThisB = V.BA->getBasicBlock();<br>
+      const BasicBlock *OtherB = ER.V.BA->getBasicBlock();<br>
+      assert(ThisB->getParent() == OtherB->getParent());<br>
+      const Function &F = *ThisB->getParent();<br>
+      return std::distance(F.begin(), ThisB->getIterator()) <<br>
+             std::distance(F.begin(), OtherB->getIterator());<br>
+    }<br>
+  }<br>
+  return V.ImmVal < ER.V.ImmVal;<br>
+}<br>
+<br>
+HCE::ExtValue::ExtValue(const MachineOperand &Op) : ExtRoot(Op) {<br>
+  if (Op.isImm())<br>
+    Offset = Op.getImm();<br>
+  else if (Op.isFPImm() || Op.isJTI())<br>
+    Offset = 0;<br>
+  else if (Op.isSymbol() || Op.isGlobal() || Op.isBlockAddress() ||<br>
+           Op.isCPI() || Op.isTargetIndex())<br>
+    Offset = Op.getOffset();<br>
+  else<br>
+    llvm_unreachable("Unexpected operand type");<br>
+}<br>
+<br>
+bool HCE::ExtValue::operator< (const HCE::ExtValue &EV) const {<br>
+  const ExtRoot &ER = *this;<br>
+  if (!(ER == ExtRoot(EV)))<br>
+    return ER < EV;<br>
+  return Offset < EV.Offset;<br>
+}<br>
+<br>
+HCE::ExtValue::operator MachineOperand() const {<br>
+  switch (Kind) {<br>
+    case MachineOperand::MO_Immediate:<br>
+      return MachineOperand::CreateImm(V.<wbr>ImmVal + Offset);<br>
+    case MachineOperand::MO_<wbr>FPImmediate:<br>
+      assert(Offset == 0);<br>
+      return MachineOperand::CreateFPImm(V.<wbr>CFP);<br>
+    case MachineOperand::MO_<wbr>ExternalSymbol:<br>
+      assert(Offset == 0);<br>
+      return MachineOperand::CreateES(V.<wbr>SymbolName, TF);<br>
+    case MachineOperand::MO_<wbr>GlobalAddress:<br>
+      return MachineOperand::CreateGA(V.GV, Offset, TF);<br>
+    case MachineOperand::MO_<wbr>BlockAddress:<br>
+      return MachineOperand::CreateBA(<a href="http://V.BA" rel="noreferrer" target="_blank">V.BA</a>, Offset, TF);<br>
+    case MachineOperand::MO_<wbr>TargetIndex:<br>
+      return MachineOperand::<wbr>CreateTargetIndex(V.ImmVal, Offset, TF);<br>
+    case MachineOperand::MO_<wbr>ConstantPoolIndex:<br>
+      return MachineOperand::CreateCPI(V.<wbr>ImmVal, Offset, TF);<br>
+    case MachineOperand::MO_<wbr>JumpTableIndex:<br>
+      assert(Offset == 0);<br>
+    default:<br>
+      llvm_unreachable("Unhandled kind");<br>
+ }<br>
+}<br>
+<br>
+bool HCE::isStoreImmediate(unsigned Opc) const {<br>
+  switch (Opc) {<br>
+    case Hexagon::S4_storeirbt_io:<br>
+    case Hexagon::S4_storeirbf_io:<br>
+    case Hexagon::S4_storeirht_io:<br>
+    case Hexagon::S4_storeirhf_io:<br>
+    case Hexagon::S4_storeirit_io:<br>
+    case Hexagon::S4_storeirif_io:<br>
+    case Hexagon::S4_storeirb_io:<br>
+    case Hexagon::S4_storeirh_io:<br>
+    case Hexagon::S4_storeiri_io:<br>
+      return true;<br>
+    default:<br>
+      break;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+bool HCE::isRegOffOpcode(unsigned Opc) const {<br>
+  switch (Opc) {<br>
+    case Hexagon::L2_loadrub_io:<br>
+    case Hexagon::L2_loadrb_io:<br>
+    case Hexagon::L2_loadruh_io:<br>
+    case Hexagon::L2_loadrh_io:<br>
+    case Hexagon::L2_loadri_io:<br>
+    case Hexagon::L2_loadrd_io:<br>
+    case Hexagon::L2_loadbzw2_io:<br>
+    case Hexagon::L2_loadbzw4_io:<br>
+    case Hexagon::L2_loadbsw2_io:<br>
+    case Hexagon::L2_loadbsw4_io:<br>
+    case Hexagon::L2_loadalignh_io:<br>
+    case Hexagon::L2_loadalignb_io:<br>
+    case Hexagon::L2_ploadrubt_io:<br>
+    case Hexagon::L2_ploadrubf_io:<br>
+    case Hexagon::L2_ploadrbt_io:<br>
+    case Hexagon::L2_ploadrbf_io:<br>
+    case Hexagon::L2_ploadruht_io:<br>
+    case Hexagon::L2_ploadruhf_io:<br>
+    case Hexagon::L2_ploadrht_io:<br>
+    case Hexagon::L2_ploadrhf_io:<br>
+    case Hexagon::L2_ploadrit_io:<br>
+    case Hexagon::L2_ploadrif_io:<br>
+    case Hexagon::L2_ploadrdt_io:<br>
+    case Hexagon::L2_ploadrdf_io:<br>
+    case Hexagon::S2_storerb_io:<br>
+    case Hexagon::S2_storerh_io:<br>
+    case Hexagon::S2_storerf_io:<br>
+    case Hexagon::S2_storeri_io:<br>
+    case Hexagon::S2_storerd_io:<br>
+    case Hexagon::S2_pstorerbt_io:<br>
+    case Hexagon::S2_pstorerbf_io:<br>
+    case Hexagon::S2_pstorerht_io:<br>
+    case Hexagon::S2_pstorerhf_io:<br>
+    case Hexagon::S2_pstorerft_io:<br>
+    case Hexagon::S2_pstorerff_io:<br>
+    case Hexagon::S2_pstorerit_io:<br>
+    case Hexagon::S2_pstorerif_io:<br>
+    case Hexagon::S2_pstorerdt_io:<br>
+    case Hexagon::S2_pstorerdf_io:<br>
+    case Hexagon::A2_addi:<br>
+      return true;<br>
+    default:<br>
+      break;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+unsigned HCE::getRegOffOpcode(unsigned ExtOpc) const {<br>
+  // If there exists an instruction that takes a register and offset,<br>
+  // that corresponds to the ExtOpc, return it, otherwise return 0.<br>
+  using namespace Hexagon;<br>
+  switch (ExtOpc) {<br>
+    case A2_tfrsi:    return A2_addi;<br>
+    default:<br>
+      break;<br>
+  }<br>
+  const MCInstrDesc &D = HII->get(ExtOpc);<br>
+  if (D.mayLoad() || D.mayStore()) {<br>
+    uint64_t F = D.TSFlags;<br>
+    unsigned AM = (F >> HexagonII::AddrModePos) & HexagonII::AddrModeMask;<br>
+    switch (AM) {<br>
+      case HexagonII::Absolute:<br>
+      case HexagonII::AbsoluteSet:<br>
+      case HexagonII::BaseLongOffset:<br>
+        switch (ExtOpc) {<br>
+          case PS_loadrubabs:<br>
+          case L4_loadrub_ap:<br>
+          case L4_loadrub_ur:     return L2_loadrub_io;<br>
+          case PS_loadrbabs:<br>
+          case L4_loadrb_ap:<br>
+          case L4_loadrb_ur:      return L2_loadrb_io;<br>
+          case PS_loadruhabs:<br>
+          case L4_loadruh_ap:<br>
+          case L4_loadruh_ur:     return L2_loadruh_io;<br>
+          case PS_loadrhabs:<br>
+          case L4_loadrh_ap:<br>
+          case L4_loadrh_ur:      return L2_loadrh_io;<br>
+          case PS_loadriabs:<br>
+          case L4_loadri_ap:<br>
+          case L4_loadri_ur:      return L2_loadri_io;<br>
+          case PS_loadrdabs:<br>
+          case L4_loadrd_ap:<br>
+          case L4_loadrd_ur:      return L2_loadrd_io;<br>
+          case L4_loadbzw2_ap:<br>
+          case L4_loadbzw2_ur:    return L2_loadbzw2_io;<br>
+          case L4_loadbzw4_ap:<br>
+          case L4_loadbzw4_ur:    return L2_loadbzw4_io;<br>
+          case L4_loadbsw2_ap:<br>
+          case L4_loadbsw2_ur:    return L2_loadbsw2_io;<br>
+          case L4_loadbsw4_ap:<br>
+          case L4_loadbsw4_ur:    return L2_loadbsw4_io;<br>
+          case L4_loadalignh_ap:<br>
+          case L4_loadalignh_ur:  return L2_loadalignh_io;<br>
+          case L4_loadalignb_ap:<br>
+          case L4_loadalignb_ur:  return L2_loadalignb_io;<br>
+          case L4_ploadrubt_abs:  return L2_ploadrubt_io;<br>
+          case L4_ploadrubf_abs:  return L2_ploadrubf_io;<br>
+          case L4_ploadrbt_abs:   return L2_ploadrbt_io;<br>
+          case L4_ploadrbf_abs:   return L2_ploadrbf_io;<br>
+          case L4_ploadruht_abs:  return L2_ploadruht_io;<br>
+          case L4_ploadruhf_abs:  return L2_ploadruhf_io;<br>
+          case L4_ploadrht_abs:   return L2_ploadrht_io;<br>
+          case L4_ploadrhf_abs:   return L2_ploadrhf_io;<br>
+          case L4_ploadrit_abs:   return L2_ploadrit_io;<br>
+          case L4_ploadrif_abs:   return L2_ploadrif_io;<br>
+          case L4_ploadrdt_abs:   return L2_ploadrdt_io;<br>
+          case L4_ploadrdf_abs:   return L2_ploadrdf_io;<br>
+          case PS_storerbabs:<br>
+          case S4_storerb_ap:<br>
+          case S4_storerb_ur:     return S2_storerb_io;<br>
+          case PS_storerhabs:<br>
+          case S4_storerh_ap:<br>
+          case S4_storerh_ur:     return S2_storerh_io;<br>
+          case PS_storerfabs:<br>
+          case S4_storerf_ap:<br>
+          case S4_storerf_ur:     return S2_storerf_io;<br>
+          case PS_storeriabs:<br>
+          case S4_storeri_ap:<br>
+          case S4_storeri_ur:     return S2_storeri_io;<br>
+          case PS_storerdabs:<br>
+          case S4_storerd_ap:<br>
+          case S4_storerd_ur:     return S2_storerd_io;<br>
+          case S4_pstorerbt_abs:  return S2_pstorerbt_io;<br>
+          case S4_pstorerbf_abs:  return S2_pstorerbf_io;<br>
+          case S4_pstorerht_abs:  return S2_pstorerht_io;<br>
+          case S4_pstorerhf_abs:  return S2_pstorerhf_io;<br>
+          case S4_pstorerft_abs:  return S2_pstorerft_io;<br>
+          case S4_pstorerff_abs:  return S2_pstorerff_io;<br>
+          case S4_pstorerit_abs:  return S2_pstorerit_io;<br>
+          case S4_pstorerif_abs:  return S2_pstorerif_io;<br>
+          case S4_pstorerdt_abs:  return S2_pstorerdt_io;<br>
+          case S4_pstorerdf_abs:  return S2_pstorerdf_io;<br>
+          default:<br>
+            break;<br>
+        }<br>
+        break;<br>
+      case HexagonII::BaseImmOffset:<br>
+        if (!isStoreImmediate(ExtOpc))<br>
+          return ExtOpc;<br>
+        break;<br>
+      default:<br>
+        break;<br>
+    }<br>
+  }<br>
+  return 0;<br>
+}<br>
+<br>
+unsigned HCE::getDirectRegReplacement(<wbr>unsigned ExtOpc) const {<br>
+  switch (ExtOpc) {<br>
+    case Hexagon::A2_addi:          return Hexagon::A2_add;<br>
+    case Hexagon::A2_andir:         return Hexagon::A2_and;<br>
+    case Hexagon::A2_combineii:     return Hexagon::A4_combineri;<br>
+    case Hexagon::A2_orir:          return Hexagon::A2_or;<br>
+    case Hexagon::A2_paddif:        return Hexagon::A2_paddf;<br>
+    case Hexagon::A2_paddit:        return Hexagon::A2_paddt;<br>
+    case Hexagon::A2_subri:         return Hexagon::A2_sub;<br>
+    case Hexagon::A2_tfrsi:         return TargetOpcode::COPY;<br>
+    case Hexagon::A4_cmpbeqi:       return Hexagon::A4_cmpbeq;<br>
+    case Hexagon::A4_cmpbgti:       return Hexagon::A4_cmpbgt;<br>
+    case Hexagon::A4_cmpbgtui:      return Hexagon::A4_cmpbgtu;<br>
+    case Hexagon::A4_cmpheqi:       return Hexagon::A4_cmpheq;<br>
+    case Hexagon::A4_cmphgti:       return Hexagon::A4_cmphgt;<br>
+    case Hexagon::A4_cmphgtui:      return Hexagon::A4_cmphgtu;<br>
+    case Hexagon::A4_combineii:     return Hexagon::A4_combineir;<br>
+    case Hexagon::A4_combineir:     return TargetOpcode::REG_SEQUENCE;<br>
+    case Hexagon::A4_combineri:     return TargetOpcode::REG_SEQUENCE;<br>
+    case Hexagon::A4_rcmpeqi:       return Hexagon::A4_rcmpeq;<br>
+    case Hexagon::A4_rcmpneqi:      return Hexagon::A4_rcmpneq;<br>
+    case Hexagon::C2_cmoveif:       return Hexagon::A2_tfrpf;<br>
+    case Hexagon::C2_cmoveit:       return Hexagon::A2_tfrpt;<br>
+    case Hexagon::C2_cmpeqi:        return Hexagon::C2_cmpeq;<br>
+    case Hexagon::C2_cmpgti:        return Hexagon::C2_cmpgt;<br>
+    case Hexagon::C2_cmpgtui:       return Hexagon::C2_cmpgtu;<br>
+    case Hexagon::C2_muxii:         return Hexagon::C2_muxir;<br>
+    case Hexagon::C2_muxir:         return Hexagon::C2_mux;<br>
+    case Hexagon::C2_muxri:         return Hexagon::C2_mux;<br>
+    case Hexagon::C4_cmpltei:       return Hexagon::C4_cmplte;<br>
+    case Hexagon::C4_cmplteui:      return Hexagon::C4_cmplteu;<br>
+    case Hexagon::C4_cmpneqi:       return Hexagon::C4_cmpneq;<br>
+    case Hexagon::M2_accii:         return Hexagon::M2_acci;        // T -> T<br>
+    /* No M2_macsin */<br>
+    case Hexagon::M2_macsip:        return Hexagon::M2_maci;        // T -> T<br>
+    case Hexagon::M2_mpysin:        return Hexagon::M2_mpyi;<br>
+    case Hexagon::M2_mpysip:        return Hexagon::M2_mpyi;<br>
+    case Hexagon::M2_mpysmi:        return Hexagon::M2_mpyi;<br>
+    case Hexagon::M2_naccii:        return Hexagon::M2_nacci;       // T -> T<br>
+    case Hexagon::M4_mpyri_addi:    return Hexagon::M4_mpyri_addr;<br>
+    case Hexagon::M4_mpyri_addr:    return Hexagon::M4_mpyrr_addr;  // _ -> T<br>
+    case Hexagon::M4_mpyrr_addi:    return Hexagon::M4_mpyrr_addr;  // _ -> T<br>
+    case Hexagon::S4_addaddi:       return Hexagon::M2_acci;        // _ -> T<br>
+    case Hexagon::S4_addi_asl_ri:   return Hexagon::S2_asl_i_r_acc; // T -> T<br>
+    case Hexagon::S4_addi_lsr_ri:   return Hexagon::S2_lsr_i_r_acc; // T -> T<br>
+    case Hexagon::S4_andi_asl_ri:   return Hexagon::S2_asl_i_r_and; // T -> T<br>
+    case Hexagon::S4_andi_lsr_ri:   return Hexagon::S2_lsr_i_r_and; // T -> T<br>
+    case Hexagon::S4_ori_asl_ri:    return Hexagon::S2_asl_i_r_or;  // T -> T<br>
+    case Hexagon::S4_ori_lsr_ri:    return Hexagon::S2_lsr_i_r_or;  // T -> T<br>
+    case Hexagon::S4_subaddi:       return Hexagon::M2_subacc;      // _ -> T<br>
+    case Hexagon::S4_subi_asl_ri:   return Hexagon::S2_asl_i_r_nac; // T -> T<br>
+    case Hexagon::S4_subi_lsr_ri:   return Hexagon::S2_lsr_i_r_nac; // T -> T<br>
+<br>
+    // Store-immediates:<br>
+    case Hexagon::S4_storeirbf_io:  return Hexagon::S2_pstorerbf_io;<br>
+    case Hexagon::S4_storeirb_io:   return Hexagon::S2_storerb_io;<br>
+    case Hexagon::S4_storeirbt_io:  return Hexagon::S2_pstorerbt_io;<br>
+    case Hexagon::S4_storeirhf_io:  return Hexagon::S2_pstorerhf_io;<br>
+    case Hexagon::S4_storeirh_io:   return Hexagon::S2_storerh_io;<br>
+    case Hexagon::S4_storeirht_io:  return Hexagon::S2_pstorerht_io;<br>
+    case Hexagon::S4_storeirif_io:  return Hexagon::S2_pstorerif_io;<br>
+    case Hexagon::S4_storeiri_io:   return Hexagon::S2_storeri_io;<br>
+    case Hexagon::S4_storeirit_io:  return Hexagon::S2_pstorerit_io;<br>
+<br>
+    default:<br>
+      break;<br>
+  }<br>
+  return 0;<br>
+}<br>
+<br>
+// Return the allowable deviation from the current value of Rb which the<br>
+// instruction MI can accommodate.<br>
+// The instruction MI is a user of register Rb, which is defined via an<br>
+// extender. It may be possible for MI to be tweaked to work for a register<br>
+// defined with a slightly different value. For example<br>
+//   ... = L2_loadrub_io Rb, 0<br>
+// can be modifed to be<br>
+//   ... = L2_loadrub_io Rb', 1<br>
+// if Rb' = Rb-1.<br>
+OffsetRange HCE::getOffsetRange(Register Rb, const MachineInstr &MI) const {<br>
+  unsigned Opc = MI.getOpcode();<br>
+  // Instructions that are constant-extended may be replaced with something<br>
+  // else that no longer offers the same range as the original.<br>
+  if (!isRegOffOpcode(Opc) || HII->isConstExtended(MI))<br>
+    return OffsetRange::zero();<br>
+<br>
+  if (Opc == Hexagon::A2_addi) {<br>
+    const MachineOperand &Op1 = MI.getOperand(1), &Op2 = MI.getOperand(2);<br>
+    if (Rb != Register(Op1) || !Op2.isImm())<br>
+      return OffsetRange::zero();<br>
+    OffsetRange R = { -(1<<15)+1, (1<<15)-1, 1 };<br>
+    return R.shift(Op2.getImm());<br>
+  }<br>
+<br>
+  // HII::getBaseAndOffsetPosition returns the increment position as "offset".<br>
+  if (HII->isPostIncrement(MI))<br>
+    return OffsetRange::zero();<br>
+<br>
+  const MCInstrDesc &D = HII->get(Opc);<br>
+  assert(D.mayLoad() || D.mayStore());<br>
+<br>
+  unsigned BaseP, OffP;<br>
+  if (!HII-><wbr>getBaseAndOffsetPosition(MI, BaseP, OffP) ||<br>
+      Rb != Register(MI.getOperand(BaseP)) ||<br>
+      !MI.getOperand(OffP).isImm())<br>
+    return OffsetRange::zero();<br>
+<br>
+  uint64_t F = (D.TSFlags >> HexagonII::MemAccessSizePos) &<br>
+                  HexagonII::MemAccesSizeMask;<br>
+  uint8_t A = HexagonII::<wbr>getMemAccessSizeInBytes(<wbr>HexagonII::MemAccessSize(F));<br>
+  unsigned L = Log2_32(A);<br>
+  unsigned S = 10+L;  // sint11_L<br>
+  int32_t Min = -alignDown((1<<S)-1, A);<br>
+  int32_t Max = 0;  // Force non-negative offsets.<br>
+<br>
+  OffsetRange R = { Min, Max, A };<br>
+  int32_t Off = MI.getOperand(OffP).getImm();<br>
+  return R.shift(Off);<br>
+}<br>
+<br>
+// Return the allowable deviation from the current value of the extender ED,<br>
+// for which the instruction corresponding to ED can be modified without<br>
+// using an extender.<br>
+// The instruction uses the extender directly. It will be replaced with<br>
+// another instruction, say MJ, where the extender will be replaced with a<br>
+// register. MJ can allow some variability with respect to the value of<br>
+// that register, as is the case with indexed memory instructions.<br>
+OffsetRange HCE::getOffsetRange(const ExtDesc &ED) const {<br>
+  // The only way that there can be a non-zero range available is if<br>
+  // the instruction using ED will be converted to an indexed memory<br>
+  // instruction.<br>
+  unsigned IdxOpc = getRegOffOpcode(ED.UseMI-><wbr>getOpcode());<br>
+  switch (IdxOpc) {<br>
+    case 0:<br>
+      return OffsetRange::zero();<br>
+    case Hexagon::A2_addi:    // s16<br>
+      return { -32767, 32767, 1 };<br>
+    case Hexagon::A2_subri:   // s10<br>
+      return { -511, 511, 1 };<br>
+  }<br>
+<br>
+  if (!ED.UseMI->mayLoad() && !ED.UseMI->mayStore())<br>
+    return OffsetRange::zero();<br>
+  const MCInstrDesc &D = HII->get(IdxOpc);<br>
+  uint64_t F = (D.TSFlags >> HexagonII::MemAccessSizePos) &<br>
+                  HexagonII::MemAccesSizeMask;<br>
+  uint8_t A = HexagonII::<wbr>getMemAccessSizeInBytes(<wbr>HexagonII::MemAccessSize(F));<br>
+  unsigned L = Log2_32(A);<br>
+  unsigned S = 10+L;  // sint11_L<br>
+  int32_t Min = -alignDown((1<<S)-1, A);<br>
+  int32_t Max = 0;  // Force non-negative offsets.<br>
+  return { Min, Max, A };<br>
+}<br>
+<br>
+// Get the allowable deviation from the current value of Rd by checking<br>
+// all uses of Rd.<br>
+OffsetRange HCE::getOffsetRange(Register Rd) const {<br>
+  OffsetRange Range;<br>
+  for (const MachineOperand &Op : MRI->use_operands(Rd.Reg)) {<br>
+    // Make sure that the register being used by this operand is identical<br>
+    // to the register that was defined: using a different subregister<br>
+    // precludes any non-trivial range.<br>
+    if (Rd != Register(Op))<br>
+      return OffsetRange::zero();<br>
+    Range.intersect(<wbr>getOffsetRange(Rd, *Op.getParent()));<br>
+  }<br>
+  return Range;<br>
+}<br>
+<br>
+void HCE::recordExtender(<wbr>MachineInstr &MI, unsigned OpNum) {<br>
+  unsigned Opc = MI.getOpcode();<br>
+  ExtDesc ED;<br>
+  ED.OpNum = OpNum;<br>
+<br>
+  bool IsLoad = MI.mayLoad();<br>
+  bool IsStore = MI.mayStore();<br>
+<br>
+  if (IsLoad || IsStore) {<br>
+    unsigned AM = HII->getAddrMode(MI);<br>
+    switch (AM) {<br>
+      // (Re: ##Off + Rb<<S) = Rd: ##Val<br>
+      case HexagonII::Absolute:       // (__: ## + __<<_)<br>
+        break;<br>
+      case HexagonII::AbsoluteSet:    // (Rd: ## + __<<_)<br>
+        ED.Rd = MI.getOperand(OpNum-1);<br>
+        ED.IsDef = true;<br>
+        break;<br>
+      case HexagonII::BaseImmOffset:  // (__: ## + Rs<<0)<br>
+        // Store-immediates are treated as non-memory operations, since<br>
+        // it's the value being stored that is extended (as opposed to<br>
+        // a part of the address).<br>
+        if (!isStoreImmediate(Opc))<br>
+          <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum-1);<br>
+        break;<br>
+      case HexagonII::BaseLongOffset: // (__: ## + Rs<<S)<br>
+        <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum-2);<br>
+        ED.Expr.S = MI.getOperand(OpNum-1).getImm(<wbr>);<br>
+        break;<br>
+      default:<br>
+        llvm_unreachable("Unhandled memory instruction");<br>
+    }<br>
+  } else {<br>
+    switch (Opc) {<br>
+      case Hexagon::A2_tfrsi:         // (Rd: ## + __<<_)<br>
+        ED.Rd = MI.getOperand(0);<br>
+        ED.IsDef = true;<br>
+        break;<br>
+      case Hexagon::A2_combineii:     // (Rd: ## + __<<_)<br>
+      case Hexagon::A4_combineir:<br>
+        ED.Rd = { MI.getOperand(0).getReg(), Hexagon::isub_hi };<br>
+        ED.IsDef = true;<br>
+        break;<br>
+      case Hexagon::A4_combineri:     // (Rd: ## + __<<_)<br>
+        ED.Rd = { MI.getOperand(0).getReg(), Hexagon::isub_lo };<br>
+        ED.IsDef = true;<br>
+        break;<br>
+      case Hexagon::A2_addi:          // (Rd: ## + Rs<<0)<br>
+        ED.Rd = MI.getOperand(0);<br>
+        <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum-1);<br>
+        break;<br>
+      case Hexagon::M2_accii:         // (__: ## + Rs<<0)<br>
+      case Hexagon::M2_naccii:<br>
+      case Hexagon::S4_addaddi:<br>
+        <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum-1);<br>
+        break;<br>
+      case Hexagon::A2_subri:         // (Rd: ## - Rs<<0)<br>
+        ED.Rd = MI.getOperand(0);<br>
+        <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum+1);<br>
+        ED.Expr.Neg = true;<br>
+        break;<br>
+      case Hexagon::S4_subaddi:       // (__: ## - Rs<<0)<br>
+        <a href="http://ED.Expr.Rs" rel="noreferrer" target="_blank">ED.Expr.Rs</a> = MI.getOperand(OpNum+1);<br>
+        ED.Expr.Neg = true;<br>
+      default:                        // (__: ## + __<<_)<br>
+        break;<br>
+    }<br>
+  }<br>
+<br>
+  ED.UseMI = &MI;<br>
+  Extenders.push_back(ED);<br>
+}<br>
+<br>
+void HCE::collectInstr(MachineInstr &MI) {<br>
+  if (!HII->isConstExtended(MI))<br>
+    return;<br>
+<br>
+  // Skip some non-convertible instructions.<br>
+  unsigned Opc = MI.getOpcode();<br>
+  switch (Opc) {<br>
+    case Hexagon::M2_macsin:  // There is no Rx -= mpyi(Rs,Rt).<br>
+    case Hexagon::C4_addipc:<br>
+    case Hexagon::S4_or_andi:<br>
+    case Hexagon::S4_or_andix:<br>
+    case Hexagon::S4_or_ori:<br>
+      return;<br>
+  }<br>
+  recordExtender(MI, HII->getCExtOpNum(MI));<br>
+}<br>
+<br>
+void HCE::collect(MachineFunction &MF) {<br>
+  Extenders.clear();<br>
+  for (MachineBasicBlock &MBB : MF)<br>
+    for (MachineInstr &MI : MBB)<br>
+      collectInstr(MI);<br>
+}<br>
+<br>
+void HCE::assignInits(const ExtRoot &ER, unsigned Begin, unsigned End,<br>
+      AssignmentMap &IMap) {<br>
+  // Sanity check: make sure that all extenders in the range [Begin..End)<br>
+  // share the same root ER.<br>
+  for (unsigned I = Begin; I != End; ++I)<br>
+    assert(ER == ExtRoot(Extenders[I].getOp()))<wbr>;<br>
+<br>
+  // Construct the list of ranges, such that for each P in Ranges[I],<br>
+  // a register Reg = ER+P can be used in place of Extender[I]. If the<br>
+  // instruction allows, uses in the form of Reg+Off are considered<br>
+  // (here, Off = required_value - P).<br>
+  std::vector<OffsetRange> Ranges(End-Begin);<br>
+<br>
+  // For each extender that is a def, visit all uses of the defined register,<br>
+  // and produce an offset range that works for all uses. The def doesn't<br>
+  // have to be checked, because it can become dead if all uses can be updated<br>
+  // to use a different reg/offset.<br>
+  for (unsigned I = Begin; I != End; ++I) {<br>
+    const ExtDesc &ED = Extenders[I];<br>
+    if (!ED.IsDef)<br>
+      continue;<br>
+    ExtValue EV(ED);<br>
+    DEBUG(dbgs() << " =" << I << ". " << EV << "  " << ED << '\n');<br>
+    assert(ED.Rd.Reg != 0);<br>
+    Ranges[I-Begin] = getOffsetRange(ED.Rd).shift(<wbr>EV.Offset);<br>
+    // A2_tfrsi is a special case: it will be replaced with A2_addi, which<br>
+    // has a 16-bit signed offset. This means that A2_tfrsi not only has a<br>
+    // range coming from its uses, but also from the fact that its replacement<br>
+    // has a range as well.<br>
+    if (ED.UseMI->getOpcode() == Hexagon::A2_tfrsi) {<br>
+      int32_t D = alignDown(32767, Ranges[I-Begin].Align); // XXX hardcoded<br>
+      Ranges[I-Begin].extendBy(-D).<wbr>extendBy(D);<br>
+    }<br>
+  }<br>
+<br>
+  // Visit all non-def extenders. For each one, determine the offset range<br>
+  // available for it.<br>
+  for (unsigned I = Begin; I != End; ++I) {<br>
+    const ExtDesc &ED = Extenders[I];<br>
+    if (ED.IsDef)<br>
+      continue;<br>
+    ExtValue EV(ED);<br>
+    DEBUG(dbgs() << "  " << I << ". " << EV << "  " << ED << '\n');<br>
+    OffsetRange Dev = getOffsetRange(ED);<br>
+    Ranges[I-Begin].intersect(Dev.<wbr>shift(EV.Offset));<br>
+  }<br>
+<br>
+  // Here for each I there is a corresponding Range[I]. Construct the<br>
+  // inverse map, that to each range will assign the set of indexes in<br>
+  // [Begin..End) that this range corresponds to.<br>
+  std::map<OffsetRange, IndexList> RangeMap;<br>
+  for (unsigned I = Begin; I != End; ++I)<br>
+    RangeMap[Ranges[I-Begin]].<wbr>insert(I);<br>
+<br>
+  DEBUG({<br>
+    dbgs() << "Ranges\n";<br>
+    for (unsigned I = Begin; I != End; ++I)<br>
+      dbgs() << "  " << I << ". " << Ranges[I-Begin] << '\n';<br>
+    dbgs() << "RangeMap\n";<br>
+    for (auto &P : RangeMap) {<br>
+      dbgs() << "  " << P.first << " ->";<br>
+      for (unsigned I : P.second)<br>
+        dbgs() << ' ' << I;<br>
+      dbgs() << '\n';<br>
+    }<br>
+  });<br>
+<br>
+  // Select the definition points, and generate the assignment between<br>
+  // these points and the uses.<br>
+<br>
+  // For each candidate offset, keep a pair CandData consisting of<br>
+  // the total number of ranges containing that candidate, and the<br>
+  // vector of corresponding RangeTree nodes.<br>
+  using CandData = std::pair<unsigned, SmallVector<RangeTree::Node*,<wbr>8>>;<br>
+  std::map<int32_t, CandData> CandMap;<br>
+<br>
+  RangeTree Tree;<br>
+  for (const OffsetRange &R : Ranges)<br>
+    Tree.add(R);<br>
+  SmallVector<RangeTree::Node*,<wbr>8> Nodes;<br>
+  Tree.order(Nodes);<br>
+<br>
+  auto MaxAlign = [](const SmallVectorImpl<RangeTree::<wbr>Node*> &Nodes) {<br>
+    uint8_t Align = 1;<br>
+    for (RangeTree::Node *N : Nodes)<br>
+      Align = std::max(Align, N->Range.Align);<br>
+    return Align;<br>
+  };<br>
+<br>
+  // Construct the set of all potential definition points from the endpoints<br>
+  // of the ranges. If a given endpoint also belongs to a different range,<br>
+  // but with a higher alignment, also consider the more-highly-aligned<br>
+  // value of this endpoint.<br>
+  std::set<int32_t> CandSet;<br>
+  for (RangeTree::Node *N : Nodes) {<br>
+    const OffsetRange &R = N->Range;<br>
+    uint8_t A0 = MaxAlign(Tree.nodesWith(R.Min, false));<br>
+    CandSet.insert(R.Min);<br>
+    if (R.Align < A0)<br>
+      CandSet.insert(R.Min < 0 ? -alignDown(-R.Min, A0) : alignTo(R.Min, A0));<br>
+    uint8_t A1 = MaxAlign(Tree.nodesWith(R.Max, false));<br>
+    CandSet.insert(R.Max);<br>
+    if (R.Align < A1)<br>
+      CandSet.insert(R.Max < 0 ? -alignTo(-R.Max, A1) : alignDown(R.Max, A1));<br>
+  }<br>
+<br>
+  // Build the assignment map: candidate C -> { list of extender indexes }.<br>
+  // This has to be done iteratively:<br>
+  // - pick the candidate that covers the maximum number of extenders,<br>
+  // - add the candidate to the map,<br>
+  // - remove the extenders from the pool.<br>
+  while (true) {<br>
+    using CMap = std::map<int32_t,unsigned>;<br>
+    CMap Counts;<br>
+    for (auto It = CandSet.begin(), Et = CandSet.end(); It != Et; ) {<br>
+      auto &&V = Tree.nodesWith(*It);<br>
+      unsigned N = std::accumulate(V.begin(), V.end(), 0u,<br>
+                    [](unsigned Acc, const RangeTree::Node *N) {<br>
+                      return Acc + N->Count;<br>
+                    });<br>
+      if (N != 0)<br>
+        Counts.insert({*It, N});<br>
+      It = (N != 0) ? std::next(It) : CandSet.erase(It);<br>
+    }<br>
+    if (Counts.empty())<br>
+      break;<br>
+<br>
+    // Find the best candidate with respect to the number of extenders covered.<br>
+    auto BestIt = std::max_element(Counts.begin(<wbr>), Counts.end(),<br>
+                    [](const CMap::value_type &A, const CMap::value_type &B) {<br>
+                      return A.second < B.second ||<br>
+                             (A.second == B.second && A < B);<br>
+                    });<br>
+    int32_t Best = BestIt->first;<br>
+    ExtValue BestV(ER, Best);<br>
+    for (RangeTree::Node *N : Tree.nodesWith(Best)) {<br>
+      for (unsigned I : RangeMap[N->Range])<br>
+        IMap[{BestV,Extenders[I].Expr}<wbr>].insert(I);<br>
+      Tree.erase(N);<br>
+    }<br>
+  }<br>
+<br>
+  DEBUG(dbgs() << "IMap (before fixup) = " << PrintIMap(IMap, *HRI));<br>
+<br>
+  // There is some ambiguity in what initializer should be used, if the<br>
+  // descriptor's subexpression is non-trivial: it can be the entire<br>
+  // subexpression (which is what has been done so far), or it can be<br>
+  // the extender's value itself, if all corresponding extenders have the<br>
+  // exact value of the initializer (i.e. require offset of 0).<br>
+<br>
+  // To reduce the number of initializers, merge such special cases.<br>
+  for (std::pair<const ExtenderInit,IndexList> &P : IMap) {<br>
+    // Skip trivial initializers.<br>
+    if (P.first.second.trivial())<br>
+      continue;<br>
+    // If the corresponding trivial initializer does not exist, skip this<br>
+    // entry.<br>
+    const ExtValue &EV = P.first.first;<br>
+    AssignmentMap::iterator F = IMap.find({EV, ExtExpr()});<br>
+    if (F == IMap.end())<br>
+      continue;<br>
+    // Finally, check if all extenders have the same value as the initializer.<br>
+    auto SameValue = [&EV,this](unsigned I) {<br>
+      const ExtDesc &ED = Extenders[I];<br>
+      return ExtValue(ED).Offset == EV.Offset;<br>
+    };<br>
+    if (all_of(P.second, SameValue)) {<br>
+      F->second.insert(P.second.<wbr>begin(), P.second.end());<br>
+      P.second.clear();<br>
+    }<br>
+  }<br>
+<br>
+  DEBUG(dbgs() << "IMap (after fixup) = " << PrintIMap(IMap, *HRI));<br>
+}<br>
+<br>
+void HCE::calculatePlacement(const ExtenderInit &ExtI, const IndexList &Refs,<br>
+      LocDefMap &Defs) {<br>
+  if (Refs.empty())<br>
+    return;<br>
+<br>
+  // The placement calculation is somewhat simple right now: it finds a<br>
+  // single location for the def that dominates all refs. Since this may<br>
+  // place the def far from the uses, producing several locations for<br>
+  // defs that collectively dominate all refs could be better.<br>
+  // For now only do the single one.<br>
+  DenseSet<MachineBasicBlock*> Blocks;<br>
+  DenseSet<MachineInstr*> RefMIs;<br>
+  const ExtDesc &ED0 = Extenders[Refs[0]];<br>
+  MachineBasicBlock *DomB = ED0.UseMI->getParent();<br>
+  RefMIs.insert(ED0.UseMI);<br>
+  Blocks.insert(DomB);<br>
+  for (unsigned i = 1, e = Refs.size(); i != e; ++i) {<br>
+    const ExtDesc &ED = Extenders[Refs[i]];<br>
+    MachineBasicBlock *MBB = ED.UseMI->getParent();<br>
+    RefMIs.insert(ED.UseMI);<br>
+    DomB = MDT-><wbr>findNearestCommonDominator(<wbr>DomB, MBB);<br>
+    Blocks.insert(MBB);<br>
+  }<br>
+<br>
+#ifndef NDEBUG<br>
+  // The block DomB should be dominated by the def of each register used<br>
+  // in the initializer.<br>
+  Register Rs = <a href="http://ExtI.second.Rs" rel="noreferrer" target="_blank">ExtI.second.Rs</a>;  // Only one reg allowed now.<br>
+  const MachineInstr *DefI = Rs.isVReg() ? MRI->getVRegDef(Rs.Reg) : nullptr;<br>
+<br>
+  // This should be guaranteed given that the entire expression is used<br>
+  // at each instruction in Refs. Add an assertion just in case.<br>
+  assert(!DefI || MDT->dominates(DefI-><wbr>getParent(), DomB));<br>
+#endif<br>
+<br>
+  MachineBasicBlock::iterator It;<br>
+  if (Blocks.count(DomB)) {<br>
+    // Try to find the latest possible location for the def.<br>
+    MachineBasicBlock::iterator End = DomB->end();<br>
+    for (It = DomB->begin(); It != End; ++It)<br>
+      if (RefMIs.count(&*It))<br>
+        break;<br>
+    assert(It != End && "Should have found a ref in DomB");<br>
+  } else {<br>
+    // DomB does not contain any refs.<br>
+    It = DomB->getFirstTerminator();<br>
+  }<br>
+  Loc DefLoc(DomB, It);<br>
+  Defs.emplace(DefLoc, Refs);<br>
+}<br>
+<br>
+HCE::Register HCE::insertInitializer(Loc DefL, const ExtenderInit &ExtI) {<br>
+  unsigned DefR = MRI->createVirtualRegister(&<wbr>Hexagon::IntRegsRegClass);<br>
+  MachineBasicBlock &MBB = *DefL.Block;<br>
+  MachineBasicBlock::iterator At = DefL.At;<br>
+  DebugLoc dl = DefL.Block->findDebugLoc(DefL.<wbr>At);<br>
+  const ExtValue &EV = ExtI.first;<br>
+  MachineOperand ExtOp(EV);<br>
+<br>
+  const ExtExpr &Ex = ExtI.second;<br>
+  const MachineInstr *InitI = nullptr;<br>
+<br>
+  if (Ex.Rs.isSlot()) {<br>
+    assert(Ex.S == 0 && "Cannot have a shift of a stack slot");<br>
+    assert(!Ex.Neg && "Cannot subtract a stack slot");<br>
+    // DefR = PS_fi Rb,##EV<br>
+    InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::PS_fi), DefR)<br>
+              .add(MachineOperand(Ex.Rs))<br>
+              .add(ExtOp);<br>
+  } else {<br>
+    assert((Ex.Rs.Reg == 0 || Ex.Rs.isVReg()) && "Expecting virtual register");<br>
+    if (Ex.trivial()) {<br>
+      // DefR = ##EV<br>
+      InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_tfrsi), DefR)<br>
+                .add(ExtOp);<br>
+    } else if (Ex.S == 0) {<br>
+      if (Ex.Neg) {<br>
+        // DefR = sub(##EV,Rb)<br>
+        InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_subri), DefR)<br>
+                  .add(ExtOp)<br>
+                  .add(MachineOperand(Ex.Rs));<br>
+      } else {<br>
+        // DefR = add(Rb,##EV)<br>
+        InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_addi), DefR)<br>
+                  .add(MachineOperand(Ex.Rs))<br>
+                  .add(ExtOp);<br>
+      }<br>
+    } else {<br>
+      unsigned NewOpc = Ex.Neg ? Hexagon::S4_subi_asl_ri<br>
+                               : Hexagon::S4_addi_asl_ri;<br>
+      // DefR = add(##EV,asl(Rb,S))<br>
+      InitI = BuildMI(MBB, At, dl, HII->get(NewOpc), DefR)<br>
+                .add(ExtOp)<br>
+                .add(MachineOperand(Ex.Rs))<br>
+                .addImm(Ex.S);<br>
+    }<br>
+  }<br>
+<br>
+  assert(InitI);<br>
+  (void)InitI;<br>
+  DEBUG(dbgs() << "Inserted def in bb#" << MBB.getNumber()<br>
+               << " for initializer: " << PrintInit(ExtI, *HRI)<br>
+               << "\n  " << *InitI);<br>
+  return { DefR, 0 };<br>
+}<br>
+<br>
+// Replace the extender at index Idx with the register ExtR.<br>
+bool HCE::replaceInstrExact(const ExtDesc &ED, Register ExtR) {<br>
+  MachineInstr &MI = *ED.UseMI;<br>
+  MachineBasicBlock &MBB = *MI.getParent();<br>
+  MachineBasicBlock::iterator At = MI.getIterator();<br>
+  DebugLoc dl = MI.getDebugLoc();<br>
+  unsigned ExtOpc = MI.getOpcode();<br>
+<br>
+  // With a few exceptions, direct replacement amounts to creating an<br>
+  // instruction with a corresponding register opcode, with all operands<br>
+  // the same, except for the register used in place of the extender.<br>
+  unsigned RegOpc = getDirectRegReplacement(<wbr>ExtOpc);<br>
+<br>
+  if (RegOpc == TargetOpcode::REG_SEQUENCE) {<br>
+    if (ExtOpc == Hexagon::A4_combineri)<br>
+      BuildMI(MBB, At, dl, HII->get(RegOpc))<br>
+        .add(MI.getOperand(0))<br>
+        .add(MI.getOperand(1))<br>
+        .addImm(Hexagon::isub_hi)<br>
+        .add(MachineOperand(ExtR))<br>
+        .addImm(Hexagon::isub_lo);<br>
+    else if (ExtOpc == Hexagon::A4_combineir)<br>
+      BuildMI(MBB, At, dl, HII->get(RegOpc))<br>
+        .add(MI.getOperand(0))<br>
+        .add(MachineOperand(ExtR))<br>
+        .addImm(Hexagon::isub_hi)<br>
+        .add(MI.getOperand(2))<br>
+        .addImm(Hexagon::isub_lo);<br>
+    else<br>
+      llvm_unreachable("Unexpected opcode became REG_SEQUENCE");<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+  if (ExtOpc == Hexagon::C2_cmpgei || ExtOpc == Hexagon::C2_cmpgeui) {<br>
+    unsigned NewOpc = ExtOpc == Hexagon::C2_cmpgei ? Hexagon::C2_cmplt<br>
+                                                   : Hexagon::C2_cmpltu;<br>
+    BuildMI(MBB, At, dl, HII->get(NewOpc))<br>
+      .add(MI.getOperand(0))<br>
+      .add(MachineOperand(ExtR))<br>
+      .add(MI.getOperand(1));<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+  if (RegOpc != 0) {<br>
+    MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(RegOpc));<br>
+    unsigned RegN = ED.OpNum;<br>
+    // Copy all operands except the one that has the extender.<br>
+    for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {<br>
+      if (i != RegN)<br>
+        MIB.add(MI.getOperand(i));<br>
+      else<br>
+        MIB.add(MachineOperand(ExtR));<br>
+    }<br>
+    MIB.setMemRefs(MI.memoperands_<wbr>begin(), MI.memoperands_end());<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+  if ((MI.mayLoad() || MI.mayStore()) && !isStoreImmediate(ExtOpc)) {<br>
+    // For memory instructions, there is an asymmetry in the addressing<br>
+    // modes. Addressing modes allowing extenders can be replaced with<br>
+    // addressing modes that use registers, but the order of operands<br>
+    // (or even their number) may be different.<br>
+    // Replacements:<br>
+    //   BaseImmOffset (io)  -> BaseRegOffset (rr)<br>
+    //   BaseLongOffset (ur) -> BaseRegOffset (rr)<br>
+    unsigned RegOpc, Shift;<br>
+    unsigned AM = HII->getAddrMode(MI);<br>
+    if (AM == HexagonII::BaseImmOffset) {<br>
+      RegOpc = HII->changeAddrMode_io_rr(<wbr>ExtOpc);<br>
+      Shift = 0;<br>
+    } else if (AM == HexagonII::BaseLongOffset) {<br>
+      // Loads:  Rd = L4_loadri_ur Rs, S, ##<br>
+      // Stores: S4_storeri_ur Rs, S, ##, Rt<br>
+      RegOpc = HII->changeAddrMode_ur_rr(<wbr>ExtOpc);<br>
+      Shift = MI.getOperand(MI.mayLoad() ? 2 : 1).getImm();<br>
+    } else {<br>
+      llvm_unreachable("Unexpected addressing mode");<br>
+    }<br>
+#ifndef NDEBUG<br>
+    if (RegOpc == -1u) {<br>
+      dbgs() << "\nExtOpc: " << HII->getName(ExtOpc) << " has no rr version\n";<br>
+      llvm_unreachable("No corresponding rr instruction");<br>
+    }<br>
+#endif<br>
+<br>
+    unsigned BaseP, OffP;<br>
+    HII->getBaseAndOffsetPosition(<wbr>MI, BaseP, OffP);<br>
+<br>
+    // Build an rr instruction: (RegOff + RegBase<<0)<br>
+    MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(RegOpc));<br>
+    // First, add the def for loads.<br>
+    if (MI.mayLoad())<br>
+      MIB.add(getLoadResultOp(MI));<br>
+    // Handle possible predication.<br>
+    if (HII->isPredicated(MI))<br>
+      MIB.add(getPredicateOp(MI));<br>
+    // Build the address.<br>
+    MIB.add(MachineOperand(ExtR));      // RegOff<br>
+    MIB.add(MI.getOperand(BaseP));      // RegBase<br>
+    MIB.addImm(Shift);                  // << Shift<br>
+    // Add the stored value for stores.<br>
+    if (MI.mayStore())<br>
+      MIB.add(getStoredValueOp(MI));<br>
+    MIB.setMemRefs(MI.memoperands_<wbr>begin(), MI.memoperands_end());<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+#ifndef NDEBUG<br>
+  dbgs() << '\n' << MI;<br>
+#endif<br>
+  llvm_unreachable("Unhandled exact replacement");<br>
+  return false;<br>
+}<br>
+<br>
+// Replace the extender ED with a form corresponding to the initializer ExtI.<br>
+bool HCE::replaceInstrExpr(const ExtDesc &ED, const ExtenderInit &ExtI,<br>
+      Register ExtR, int32_t &Diff) {<br>
+  MachineInstr &MI = *ED.UseMI;<br>
+  MachineBasicBlock &MBB = *MI.getParent();<br>
+  MachineBasicBlock::iterator At = MI.getIterator();<br>
+  DebugLoc dl = MI.getDebugLoc();<br>
+  unsigned ExtOpc = MI.getOpcode();<br>
+<br>
+  if (ExtOpc == Hexagon::A2_tfrsi) {<br>
+    // A2_tfrsi is a special case: it's replaced with A2_addi, which introduces<br>
+    // another range. One range is the one that's common to all tfrsi's uses,<br>
+    // this one is the range of immediates in A2_addi. When calculating ranges,<br>
+    // the addi's 16-bit argument was included, so now we need to make it such<br>
+    // that the produced value is in the range for the uses alone.<br>
+    // Most of the time, simply adding Diff will make the addi produce exact<br>
+    // result, but if Diff is outside of the 16-bit range, some adjustment<br>
+    // will be needed.<br>
+    unsigned IdxOpc = getRegOffOpcode(ExtOpc);<br>
+    assert(IdxOpc == Hexagon::A2_addi);<br>
+<br>
+    // Clamp Diff to the 16 bit range.<br>
+    int32_t D = isInt<16>(Diff) ? Diff : (Diff > 32767 ? 32767 : -32767);<br>
+    BuildMI(MBB, At, dl, HII->get(IdxOpc))<br>
+      .add(MI.getOperand(0))<br>
+      .add(MachineOperand(ExtR))<br>
+      .addImm(D);<br>
+    Diff -= D;<br>
+#ifndef NDEBUG<br>
+    // Make sure the output is within allowable range for uses.<br>
+    OffsetRange Uses = getOffsetRange(MI.getOperand(<wbr>0));<br>
+    assert(Uses.contains(Diff));<br>
+#endif<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+  const ExtValue &EV = ExtI.first; (void)EV;<br>
+  const ExtExpr &Ex = ExtI.second; (void)Ex;<br>
+<br>
+  if (ExtOpc == Hexagon::A2_addi || ExtOpc == Hexagon::A2_subri) {<br>
+    // If addi/subri are replaced with the exactly matching initializer,<br>
+    // they amount to COPY.<br>
+    // Check that the initializer is an exact match (for simplicity).<br>
+    bool IsAddi = ExtOpc == Hexagon::A2_addi;<br>
+    const MachineOperand &RegOp = MI.getOperand(IsAddi ? 1 : 2);<br>
+    const MachineOperand &ImmOp = MI.getOperand(IsAddi ? 2 : 1);<br>
+    assert(Ex.Rs == RegOp && EV == ImmOp && Ex.Neg != IsAddi &&<br>
+           "Initializer mismatch");<br>
+    BuildMI(MBB, At, dl, HII->get(TargetOpcode::COPY))<br>
+      .add(MI.getOperand(0))<br>
+      .add(MachineOperand(ExtR));<br>
+    Diff = 0;<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+  if (ExtOpc == Hexagon::M2_accii || ExtOpc == Hexagon::M2_naccii ||<br>
+      ExtOpc == Hexagon::S4_addaddi || ExtOpc == Hexagon::S4_subaddi) {<br>
+    // M2_accii:    add(Rt,add(Rs,V)) (tied)<br>
+    // M2_naccii:   sub(Rt,add(Rs,V))<br>
+    // S4_addaddi:  add(Rt,add(Rs,V))<br>
+    // S4_subaddi:  add(Rt,sub(V,Rs))<br>
+    // Check that Rs and V match the initializer expression. The Rs+V is the<br>
+    // combination that is considered "subexpression" for V, although Rx+V<br>
+    // would also be valid.<br>
+    bool IsSub = ExtOpc == Hexagon::S4_subaddi;<br>
+    Register Rs = MI.getOperand(IsSub ? 3 : 2);<br>
+    ExtValue V = MI.getOperand(IsSub ? 2 : 3);<br>
+    assert(EV == V && Rs == Ex.Rs && IsSub == Ex.Neg && "Initializer mismatch");<br>
+    unsigned NewOpc = ExtOpc == Hexagon::M2_naccii ? Hexagon::A2_sub<br>
+                                                   : Hexagon::A2_add;<br>
+    BuildMI(MBB, At, dl, HII->get(NewOpc))<br>
+      .add(MI.getOperand(0))<br>
+      .add(MI.getOperand(1))<br>
+      .add(MachineOperand(ExtR));<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+  if (MI.mayLoad() || MI.mayStore()) {<br>
+    unsigned IdxOpc = getRegOffOpcode(ExtOpc);<br>
+    assert(IdxOpc && "Expecting indexed opcode");<br>
+    MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(IdxOpc));<br>
+    // Construct the new indexed instruction.<br>
+    // First, add the def for loads.<br>
+    if (MI.mayLoad())<br>
+      MIB.add(getLoadResultOp(MI));<br>
+    // Handle possible predication.<br>
+    if (HII->isPredicated(MI))<br>
+      MIB.add(getPredicateOp(MI));<br>
+    // Build the address.<br>
+    MIB.add(MachineOperand(ExtR));<br>
+    MIB.addImm(Diff);<br>
+    // Add the stored value for stores.<br>
+    if (MI.mayStore())<br>
+      MIB.add(getStoredValueOp(MI));<br>
+    MIB.setMemRefs(MI.memoperands_<wbr>begin(), MI.memoperands_end());<br>
+    MBB.erase(MI);<br>
+    return true;<br>
+  }<br>
+<br>
+#ifndef NDEBUG<br>
+  dbgs() << '\n' << PrintInit(ExtI, *HRI) << "  " << MI;<br>
+#endif<br>
+  llvm_unreachable("Unhandled expr replacement");<br>
+  return false;<br>
+}<br>
+<br>
+bool HCE::replaceInstr(unsigned Idx, Register ExtR, const ExtenderInit &ExtI) {<br>
+  if (ReplaceLimit.<wbr>getNumOccurrences()) {<br>
+    if (ReplaceLimit <= ReplaceCounter)<br>
+      return false;<br>
+    ++ReplaceCounter;<br>
+  }<br>
+  const ExtDesc &ED = Extenders[Idx];<br>
+  assert((!ED.IsDef || ED.Rd.Reg != 0) && "Missing Rd for def");<br>
+  const ExtValue &DefV = ExtI.first;<br>
+  assert(ExtRoot(ExtValue(ED)) == ExtRoot(DefV) && "Extender root mismatch");<br>
+  const ExtExpr &DefEx = ExtI.second;<br>
+<br>
+  ExtValue EV(ED);<br>
+  int32_t Diff = EV.Offset - DefV.Offset;<br>
+  const MachineInstr &MI = *ED.UseMI;<br>
+  DEBUG(dbgs() << __func__ << " Idx:" << Idx << " ExtR:"<br>
+               << PrintRegister(ExtR, *HRI) << " Diff:" << Diff << '\n');<br>
+<br>
+  // These two addressing modes must be converted into indexed forms<br>
+  // regardless of what the initializer looks like.<br>
+  bool IsAbs = false, IsAbsSet = false;<br>
+  if (MI.mayLoad() || MI.mayStore()) {<br>
+    unsigned AM = HII->getAddrMode(MI);<br>
+    IsAbs = AM == HexagonII::Absolute;<br>
+    IsAbsSet = AM == HexagonII::AbsoluteSet;<br>
+  }<br>
+<br>
+  // If it's a def, remember all operands that need to be updated.<br>
+  // If ED is a def, and Diff is not 0, then all uses of the register Rd<br>
+  // defined by ED must be in the form (Rd, imm), i.e. the immediate offset<br>
+  // must follow the Rd in the operand list.<br>
+  std::vector<std::pair<<wbr>MachineInstr*,unsigned>> RegOps;<br>
+  if (ED.IsDef && Diff != 0) {<br>
+    for (MachineOperand &Op : MRI->use_operands(ED.Rd.Reg)) {<br>
+      MachineInstr &UI = *Op.getParent();<br>
+      RegOps.push_back({&UI, getOperandIndex(UI, Op)});<br>
+    }<br>
+  }<br>
+<br>
+  // Replace the instruction.<br>
+  bool Replaced = false;<br>
+  if (Diff == 0 && DefEx.trivial() && !IsAbs && !IsAbsSet)<br>
+    Replaced = replaceInstrExact(ED, ExtR);<br>
+  else<br>
+    Replaced = replaceInstrExpr(ED, ExtI, ExtR, Diff);<br>
+<br>
+  if (Diff != 0 && Replaced && ED.IsDef) {<br>
+    // Update offsets of the def's uses.<br>
+    for (std::pair<MachineInstr*,<wbr>unsigned> P : RegOps) {<br>
+      unsigned J = P.second;<br>
+      assert(P.first-><wbr>getNumOperands() < J+1 &&<br>
+             P.first->getOperand(J+1).<wbr>isImm());<br>
+      MachineOperand &ImmOp = P.first->getOperand(J+1);<br>
+      ImmOp.setImm(ImmOp.getImm() + Diff);<br>
+    }<br>
+    // If it was an absolute-set instruction, the "set" part has been removed.<br>
+    // ExtR will now be the register with the extended value, and since all<br>
+    // users of Rd have been updated, all that needs to be done is to replace<br>
+    // Rd with ExtR.<br>
+    if (IsAbsSet) {<br>
+      assert(ED.Rd.Sub == 0 && ExtR.Sub == 0);<br>
+      MRI->replaceRegWith(ED.Rd.Reg, ExtR.Reg);<br>
+    }<br>
+  }<br>
+<br>
+  return Replaced;<br>
+}<br>
+<br>
+bool HCE::replaceExtenders(const AssignmentMap &IMap) {<br>
+  LocDefMap Defs;<br>
+  bool Changed = false;<br>
+<br>
+  for (const std::pair<ExtenderInit,<wbr>IndexList> &P : IMap) {<br>
+    const IndexList &Idxs = P.second;<br>
+    if (Idxs.size() < CountThreshold)<br>
+      continue;<br>
+<br>
+    Defs.clear();<br>
+    calculatePlacement(P.first, Idxs, Defs);<br>
+    for (const std::pair<Loc,IndexList> &Q : Defs) {<br>
+      Register DefR = insertInitializer(Q.first, P.first);<br>
+      NewRegs.push_back(DefR.Reg);<br>
+      for (unsigned I : Q.second)<br>
+        Changed |= replaceInstr(I, DefR, P.first);<br>
+    }<br>
+  }<br>
+  return Changed;<br>
+}<br>
+<br>
+unsigned HCE::getOperandIndex(const MachineInstr &MI,<br>
+      const MachineOperand &Op) const {<br>
+  for (unsigned i = 0, n = MI.getNumOperands(); i != n; ++i)<br>
+    if (&MI.getOperand(i) == &Op)<br>
+      return i;<br>
+  llvm_unreachable("Not an operand of MI");<br>
+}<br>
+<br>
+const MachineOperand &HCE::getPredicateOp(const MachineInstr &MI) const {<br>
+  assert(HII->isPredicated(MI));<br>
+  for (const MachineOperand &Op : MI.operands()) {<br>
+    if (!Op.isReg() || !Op.isUse() ||<br>
+        MRI->getRegClass(Op.getReg()) != &Hexagon::PredRegsRegClass)<br>
+      continue;<br>
+    assert(Op.getSubReg() == 0 && "Predicate register with a subregister");<br>
+    return Op;<br>
+  }<br>
+  llvm_unreachable("Predicate operand not found");<br>
+}<br>
+<br>
+const MachineOperand &HCE::getLoadResultOp(const MachineInstr &MI) const {<br>
+  assert(MI.mayLoad());<br>
+  return MI.getOperand(0);<br>
+}<br>
+<br>
+const MachineOperand &HCE::getStoredValueOp(const MachineInstr &MI) const {<br>
+  assert(MI.mayStore());<br>
+  return MI.getOperand(MI.<wbr>getNumExplicitOperands()-1);<br>
+}<br>
+<br>
+bool HCE::runOnMachineFunction(<wbr>MachineFunction &MF) {<br>
+  if (skipFunction(*MF.getFunction(<wbr>)))<br>
+    return false;<br>
+  DEBUG(MF.print(dbgs() << "Before " << getPassName() << '\n', nullptr));<br>
+<br>
+  HII = MF.getSubtarget<<wbr>HexagonSubtarget>().<wbr>getInstrInfo();<br>
+  HRI = MF.getSubtarget<<wbr>HexagonSubtarget>().<wbr>getRegisterInfo();<br>
+  MDT = &getAnalysis<<wbr>MachineDominatorTree>();<br>
+  MRI = &MF.getRegInfo();<br>
+  AssignmentMap IMap;<br>
+<br>
+  collect(MF);<br>
+  std::sort(Extenders.begin(), Extenders.end(),<br>
+    [](const ExtDesc &A, const ExtDesc &B) {<br>
+      return ExtValue(A) < ExtValue(B);<br>
+    });<br>
+<br>
+  bool Changed = false;<br>
+  DEBUG(dbgs() << "Collected " << Extenders.size() << " extenders\n");<br>
+  for (unsigned I = 0, E = Extenders.size(); I != E; ) {<br>
+    unsigned B = I;<br>
+    const ExtRoot &T = Extenders[B].getOp();<br>
+    while (I != E && ExtRoot(Extenders[I].getOp()) == T)<br>
+      ++I;<br>
+<br>
+    IMap.clear();<br>
+    assignInits(T, B, I, IMap);<br>
+    Changed |= replaceExtenders(IMap);<br>
+  }<br>
+<br>
+  DEBUG({<br>
+    if (Changed)<br>
+      MF.print(dbgs() << "After " << getPassName() << '\n', nullptr);<br>
+    else<br>
+      dbgs() << "No changes\n";<br>
+  });<br>
+  return Changed;<br>
+}<br>
+<br>
+FunctionPass *llvm::<wbr>createHexagonConstExtenders() {<br>
+  return new HexagonConstExtenders();<br>
+}<br>
<br>
Modified: llvm/trunk/lib/Target/Hexagon/<wbr>HexagonTargetMachine.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonTargetMachine.cpp?rev=315735&r1=315734&r2=315735&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/lib/Target/<wbr>Hexagon/HexagonTargetMachine.<wbr>cpp?rev=315735&r1=315734&r2=<wbr>315735&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Target/Hexagon/<wbr>HexagonTargetMachine.cpp (original)<br>
+++ llvm/trunk/lib/Target/Hexagon/<wbr>HexagonTargetMachine.cpp Fri Oct 13 12:02:59 2017<br>
@@ -28,6 +28,9 @@<br>
<br>
 using namespace llvm;<br>
<br>
+static cl::opt<bool> EnableCExtOpt("hexagon-cext", cl::Hidden, cl::ZeroOrMore,<br>
+  cl::init(true), cl::desc("Enable Hexagon constant-extender optimization"));<br>
+<br>
 static cl::opt<bool> EnableRDFOpt("rdf-opt", cl::Hidden, cl::ZeroOrMore,<br>
   cl::init(true), cl::desc("Enable RDF-based optimizations"));<br>
<br>
@@ -119,6 +122,7 @@ SchedCustomRegistry("hexagon", "Run Hexa<br>
<br>
 namespace llvm {<br>
   extern char &HexagonExpandCondsetsID;<br>
+  void initializeHexagonConstExtender<wbr>sPass(PassRegistry&);<br>
   void initializeHexagonEarlyIfConver<wbr>sionPass(PassRegistry&);<br>
   void initializeHexagonExpandCondset<wbr>sPass(PassRegistry&);<br>
   void initializeHexagonGenMuxPass(<wbr>PassRegistry&);<br>
@@ -135,6 +139,7 @@ namespace llvm {<br>
   FunctionPass *<wbr>createHexagonCallFrameInformat<wbr>ion();<br>
   FunctionPass *createHexagonCFGOptimizer();<br>
   FunctionPass *createHexagonCommonGEP();<br>
+  FunctionPass *createHexagonConstExtenders()<wbr>;<br>
   FunctionPass *<wbr>createHexagonConstPropagationP<wbr>ass();<br>
   FunctionPass *createHexagonCopyToCombine();<br>
   FunctionPass *<wbr>createHexagonEarlyIfConversion<wbr>();<br>
@@ -176,6 +181,7 @@ extern "C" void LLVMInitializeHexagonTar<br>
   RegisterTargetMachine<<wbr>HexagonTargetMachine> X(getTheHexagonTarget());<br>
<br>
   PassRegistry &PR = *PassRegistry::<wbr>getPassRegistry();<br>
+  initializeHexagonConstExtender<wbr>sPass(PR);<br>
   initializeHexagonEarlyIfConver<wbr>sionPass(PR);<br>
   initializeHexagonGenMuxPass(<wbr>PR);<br>
   initializeHexagonLoopIdiomReco<wbr>gnizePass(PR);<br>
@@ -340,6 +346,8 @@ bool HexagonPassConfig::<wbr>addInstSelector(<br>
<br>
 void HexagonPassConfig::<wbr>addPreRegAlloc() {<br>
   if (getOptLevel() != CodeGenOpt::None) {<br>
+    if (EnableCExtOpt)<br>
+      addPass(<wbr>createHexagonConstExtenders())<wbr>;<br>
     if (EnableExpandCondsets)<br>
       insertPass(&<wbr>RegisterCoalescerID, &HexagonExpandCondsetsID);<br>
     if (!DisableStoreWidening)<br>
<br>
Added: llvm/trunk/test/CodeGen/<wbr>Hexagon/cext-opt-basic.mir<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/cext-opt-basic.mir?rev=315735&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/test/<wbr>CodeGen/Hexagon/cext-opt-<wbr>basic.mir?rev=315735&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/CodeGen/<wbr>Hexagon/cext-opt-basic.mir (added)<br>
+++ llvm/trunk/test/CodeGen/<wbr>Hexagon/cext-opt-basic.mir Fri Oct 13 12:02:59 2017<br>
@@ -0,0 +1,75 @@<br>
+# RUN: llc -march=hexagon -run-pass hexagon-cext-opt -hexagon-cext-threshold=3 %s -o - | FileCheck %s<br>
+<br>
+--- |<br>
+  define void @test0() { ret void }<br>
+  define void @test1() { ret void }<br>
+  define void @test2() { ret void }<br>
+  @global_address = global [1024 x i32] zeroinitializer, align 8<br>
+...<br>
+<br>
+# CHECK-LABEL: name: test0<br>
+# CHECK: [[B:%[0-9]+]] = A2_tfrsi @global_address<br>
+# CHECK: L2_loadri_io [[B]], 0<br>
+# CHECK: L2_loadri_io [[B]], 4<br>
+# CHECK: L2_loadri_io [[B]], 8<br>
+---<br>
+name: test0<br>
+registers:<br>
+  - { id: 0, class: intregs }<br>
+  - { id: 1, class: intregs }<br>
+  - { id: 2, class: intregs }<br>
+body: |<br>
+  bb.0:<br>
+    %0 = PS_loadriabs @global_address<br>
+    %1 = PS_loadriabs @global_address+4<br>
+    %2 = PS_loadriabs @global_address+8<br>
+...<br>
+<br>
+# CHECK-LABEL: name: test1<br>
+# CHECK: [[C:%[0-9]+]] = COPY %r0<br>
+# CHECK: [[B:%[0-9]+]] = A2_addi [[C]], @global_address<br>
+# CHECK: L2_loadri_io [[B]], 0<br>
+# CHECK: L2_loadri_io [[B]], 4<br>
+# CHECK: L2_loadri_io [[B]], 8<br>
+---<br>
+name: test1<br>
+registers:<br>
+  - { id: 0, class: intregs }<br>
+  - { id: 1, class: intregs }<br>
+  - { id: 2, class: intregs }<br>
+  - { id: 3, class: intregs }<br>
+body: |<br>
+  bb.0:<br>
+    liveins: %r0<br>
+    %0 = COPY %r0<br>
+    %1 = L4_loadri_ur %0, 0, @global_address<br>
+    %2 = L4_loadri_ur %0, 0, @global_address+4<br>
+    %3 = L4_loadri_ur %0, 0, @global_address+8<br>
+...<br>
+<br>
+# CHECK-LABEL: name: test2<br>
+# CHECK: [[C:%[0-9]+]] = COPY %r0<br>
+# CHECK: [[B:%[0-9]+]] = A2_tfrsi @global_address + 4<br>
+# CHECK: [[T0:%[0-9]+]] = A2_addi [[B]], -4<br>
+# CHECK: %r0 = COPY [[T0]]<br>
+# CHECK: [[T1:%[0-9]+]] = A2_addi [[B]], -2<br>
+# CHECK: %r1 = COPY [[T1]]<br>
+# CHECK: L4_loadri_rr [[B]], [[C]], 0<br>
+---<br>
+name: test2<br>
+registers:<br>
+  - { id: 0, class: intregs }<br>
+  - { id: 1, class: intregs }<br>
+  - { id: 2, class: intregs }<br>
+  - { id: 3, class: intregs }<br>
+body: |<br>
+  bb.0:<br>
+    liveins: %r0<br>
+    %0 = COPY %r0<br>
+    %1 = A2_tfrsi @global_address<br>
+    %r0 = COPY %1<br>
+    %2 = A2_tfrsi @global_address+2<br>
+    %r1 = COPY %2<br>
+    %3 = L4_loadri_ur %0, 0, @global_address+4<br>
+...<br>
+<br>
<br>
Modified: llvm/trunk/test/CodeGen/<wbr>Hexagon/zextloadi1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/zextloadi1.ll?rev=315735&r1=315734&r2=315735&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/llvm/trunk/test/<wbr>CodeGen/Hexagon/zextloadi1.ll?<wbr>rev=315735&r1=315734&r2=<wbr>315735&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/CodeGen/<wbr>Hexagon/zextloadi1.ll (original)<br>
+++ llvm/trunk/test/CodeGen/<wbr>Hexagon/zextloadi1.ll Fri Oct 13 12:02:59 2017<br>
@@ -1,4 +1,4 @@<br>
-; RUN: llc -march=hexagon < %s | FileCheck %s<br>
+; RUN: llc -march=hexagon -hexagon-cext=0 < %s | FileCheck %s<br>
<br>
 @i65_l = external global i65<br>
 @i65_s = external global i65<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>