xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp (revision 62987288060ff68c817b7056815aa9fb8ba8ecd7)
10b57cec5SDimitry Andric //===- HexagonConstExtenders.cpp ------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
100b57cec5SDimitry Andric #include "HexagonRegisterInfo.h"
110b57cec5SDimitry Andric #include "HexagonSubtarget.h"
1281ad6265SDimitry Andric #include "llvm/ADT/SetVector.h"
130b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
188bcb0991SDimitry Andric #include "llvm/CodeGen/Register.h"
19480093f4SDimitry Andric #include "llvm/InitializePasses.h"
208bcb0991SDimitry Andric #include "llvm/Pass.h"
210b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
230b57cec5SDimitry Andric #include <map>
240b57cec5SDimitry Andric #include <set>
250b57cec5SDimitry Andric #include <utility>
260b57cec5SDimitry Andric #include <vector>
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "hexagon-cext-opt"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric 
3281ad6265SDimitry Andric static cl::opt<unsigned> CountThreshold(
3381ad6265SDimitry Andric     "hexagon-cext-threshold", cl::init(3), cl::Hidden,
340b57cec5SDimitry Andric     cl::desc("Minimum number of extenders to trigger replacement"));
350b57cec5SDimitry Andric 
3681ad6265SDimitry Andric static cl::opt<unsigned>
3781ad6265SDimitry Andric     ReplaceLimit("hexagon-cext-limit", cl::init(0), cl::Hidden,
3881ad6265SDimitry Andric                  cl::desc("Maximum number of replacements"));
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric namespace llvm {
410b57cec5SDimitry Andric   void initializeHexagonConstExtendersPass(PassRegistry&);
420b57cec5SDimitry Andric   FunctionPass *createHexagonConstExtenders();
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric static int32_t adjustUp(int32_t V, uint8_t A, uint8_t O) {
460b57cec5SDimitry Andric   assert(isPowerOf2_32(A));
470b57cec5SDimitry Andric   int32_t U = (V & -A) + O;
480b57cec5SDimitry Andric   return U >= V ? U : U+A;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric static int32_t adjustDown(int32_t V, uint8_t A, uint8_t O) {
520b57cec5SDimitry Andric   assert(isPowerOf2_32(A));
530b57cec5SDimitry Andric   int32_t U = (V & -A) + O;
540b57cec5SDimitry Andric   return U <= V ? U : U-A;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric namespace {
580b57cec5SDimitry Andric   struct OffsetRange {
590b57cec5SDimitry Andric     // The range of values between Min and Max that are of form Align*N+Offset,
600b57cec5SDimitry Andric     // for some integer N. Min and Max are required to be of that form as well,
610b57cec5SDimitry Andric     // except in the case of an empty range.
620b57cec5SDimitry Andric     int32_t Min = INT_MIN, Max = INT_MAX;
630b57cec5SDimitry Andric     uint8_t Align = 1;
640b57cec5SDimitry Andric     uint8_t Offset = 0;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     OffsetRange() = default;
670b57cec5SDimitry Andric     OffsetRange(int32_t L, int32_t H, uint8_t A, uint8_t O = 0)
680b57cec5SDimitry Andric       : Min(L), Max(H), Align(A), Offset(O) {}
690b57cec5SDimitry Andric     OffsetRange &intersect(OffsetRange A) {
700b57cec5SDimitry Andric       if (Align < A.Align)
710b57cec5SDimitry Andric         std::swap(*this, A);
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric       // Align >= A.Align.
740b57cec5SDimitry Andric       if (Offset >= A.Offset && (Offset - A.Offset) % A.Align == 0) {
750b57cec5SDimitry Andric         Min = adjustUp(std::max(Min, A.Min), Align, Offset);
760b57cec5SDimitry Andric         Max = adjustDown(std::min(Max, A.Max), Align, Offset);
770b57cec5SDimitry Andric       } else {
780b57cec5SDimitry Andric         // Make an empty range.
790b57cec5SDimitry Andric         Min = 0;
800b57cec5SDimitry Andric         Max = -1;
810b57cec5SDimitry Andric       }
820b57cec5SDimitry Andric       // Canonicalize empty ranges.
830b57cec5SDimitry Andric       if (Min > Max)
840b57cec5SDimitry Andric         std::tie(Min, Max, Align) = std::make_tuple(0, -1, 1);
850b57cec5SDimitry Andric       return *this;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric     OffsetRange &shift(int32_t S) {
880b57cec5SDimitry Andric       Min += S;
890b57cec5SDimitry Andric       Max += S;
900b57cec5SDimitry Andric       Offset = (Offset+S) % Align;
910b57cec5SDimitry Andric       return *this;
920b57cec5SDimitry Andric     }
930b57cec5SDimitry Andric     OffsetRange &extendBy(int32_t D) {
940b57cec5SDimitry Andric       // If D < 0, extend Min, otherwise extend Max.
950b57cec5SDimitry Andric       assert(D % Align == 0);
960b57cec5SDimitry Andric       if (D < 0)
970b57cec5SDimitry Andric         Min = (INT_MIN-D < Min) ? Min+D : INT_MIN;
980b57cec5SDimitry Andric       else
990b57cec5SDimitry Andric         Max = (INT_MAX-D > Max) ? Max+D : INT_MAX;
1000b57cec5SDimitry Andric       return *this;
1010b57cec5SDimitry Andric     }
1020b57cec5SDimitry Andric     bool empty() const {
1030b57cec5SDimitry Andric       return Min > Max;
1040b57cec5SDimitry Andric     }
1050b57cec5SDimitry Andric     bool contains(int32_t V) const {
1060b57cec5SDimitry Andric       return Min <= V && V <= Max && (V-Offset) % Align == 0;
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric     bool operator==(const OffsetRange &R) const {
1090b57cec5SDimitry Andric       return Min == R.Min && Max == R.Max && Align == R.Align;
1100b57cec5SDimitry Andric     }
1110b57cec5SDimitry Andric     bool operator!=(const OffsetRange &R) const {
1120b57cec5SDimitry Andric       return !operator==(R);
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric     bool operator<(const OffsetRange &R) const {
1150b57cec5SDimitry Andric       if (Min != R.Min)
1160b57cec5SDimitry Andric         return Min < R.Min;
1170b57cec5SDimitry Andric       if (Max != R.Max)
1180b57cec5SDimitry Andric         return Max < R.Max;
1190b57cec5SDimitry Andric       return Align < R.Align;
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric     static OffsetRange zero() { return {0, 0, 1}; }
1220b57cec5SDimitry Andric   };
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   struct RangeTree {
1250b57cec5SDimitry Andric     struct Node {
1260b57cec5SDimitry Andric       Node(const OffsetRange &R) : MaxEnd(R.Max), Range(R) {}
1270b57cec5SDimitry Andric       unsigned Height = 1;
1280b57cec5SDimitry Andric       unsigned Count = 1;
1290b57cec5SDimitry Andric       int32_t MaxEnd;
1300b57cec5SDimitry Andric       const OffsetRange &Range;
1310b57cec5SDimitry Andric       Node *Left = nullptr, *Right = nullptr;
1320b57cec5SDimitry Andric     };
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     Node *Root = nullptr;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric     void add(const OffsetRange &R) {
1370b57cec5SDimitry Andric       Root = add(Root, R);
1380b57cec5SDimitry Andric     }
1390b57cec5SDimitry Andric     void erase(const Node *N) {
1400b57cec5SDimitry Andric       Root = remove(Root, N);
1410b57cec5SDimitry Andric       delete N;
1420b57cec5SDimitry Andric     }
1430b57cec5SDimitry Andric     void order(SmallVectorImpl<Node*> &Seq) const {
1440b57cec5SDimitry Andric       order(Root, Seq);
1450b57cec5SDimitry Andric     }
1460b57cec5SDimitry Andric     SmallVector<Node*,8> nodesWith(int32_t P, bool CheckAlign = true) {
1470b57cec5SDimitry Andric       SmallVector<Node*,8> Nodes;
1480b57cec5SDimitry Andric       nodesWith(Root, P, CheckAlign, Nodes);
1490b57cec5SDimitry Andric       return Nodes;
1500b57cec5SDimitry Andric     }
1510b57cec5SDimitry Andric     void dump() const;
1520b57cec5SDimitry Andric     ~RangeTree() {
1530b57cec5SDimitry Andric       SmallVector<Node*,8> Nodes;
1540b57cec5SDimitry Andric       order(Nodes);
1550b57cec5SDimitry Andric       for (Node *N : Nodes)
1560b57cec5SDimitry Andric         delete N;
1570b57cec5SDimitry Andric     }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   private:
1600b57cec5SDimitry Andric     void dump(const Node *N) const;
1610b57cec5SDimitry Andric     void order(Node *N, SmallVectorImpl<Node*> &Seq) const;
1620b57cec5SDimitry Andric     void nodesWith(Node *N, int32_t P, bool CheckA,
1630b57cec5SDimitry Andric                    SmallVectorImpl<Node*> &Seq) const;
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     Node *add(Node *N, const OffsetRange &R);
1660b57cec5SDimitry Andric     Node *remove(Node *N, const Node *D);
1670b57cec5SDimitry Andric     Node *rotateLeft(Node *Lower, Node *Higher);
1680b57cec5SDimitry Andric     Node *rotateRight(Node *Lower, Node *Higher);
1690b57cec5SDimitry Andric     unsigned height(Node *N) {
1700b57cec5SDimitry Andric       return N != nullptr ? N->Height : 0;
1710b57cec5SDimitry Andric     }
1720b57cec5SDimitry Andric     Node *update(Node *N) {
1730b57cec5SDimitry Andric       assert(N != nullptr);
1740b57cec5SDimitry Andric       N->Height = 1 + std::max(height(N->Left), height(N->Right));
1750b57cec5SDimitry Andric       if (N->Left)
1760b57cec5SDimitry Andric         N->MaxEnd = std::max(N->MaxEnd, N->Left->MaxEnd);
1770b57cec5SDimitry Andric       if (N->Right)
1780b57cec5SDimitry Andric         N->MaxEnd = std::max(N->MaxEnd, N->Right->MaxEnd);
1790b57cec5SDimitry Andric       return N;
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric     Node *rebalance(Node *N) {
1820b57cec5SDimitry Andric       assert(N != nullptr);
1830b57cec5SDimitry Andric       int32_t Balance = height(N->Right) - height(N->Left);
1840b57cec5SDimitry Andric       if (Balance < -1)
1850b57cec5SDimitry Andric         return rotateRight(N->Left, N);
1860b57cec5SDimitry Andric       if (Balance > 1)
1870b57cec5SDimitry Andric         return rotateLeft(N->Right, N);
1880b57cec5SDimitry Andric       return N;
1890b57cec5SDimitry Andric     }
1900b57cec5SDimitry Andric   };
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   struct Loc {
1930b57cec5SDimitry Andric     MachineBasicBlock *Block = nullptr;
1940b57cec5SDimitry Andric     MachineBasicBlock::iterator At;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     Loc(MachineBasicBlock *B, MachineBasicBlock::iterator It)
1970b57cec5SDimitry Andric       : Block(B), At(It) {
1980b57cec5SDimitry Andric       if (B->end() == It) {
1990b57cec5SDimitry Andric         Pos = -1;
2000b57cec5SDimitry Andric       } else {
2010b57cec5SDimitry Andric         assert(It->getParent() == B);
2020b57cec5SDimitry Andric         Pos = std::distance(B->begin(), It);
2030b57cec5SDimitry Andric       }
2040b57cec5SDimitry Andric     }
2050b57cec5SDimitry Andric     bool operator<(Loc A) const {
2060b57cec5SDimitry Andric       if (Block != A.Block)
2070b57cec5SDimitry Andric         return Block->getNumber() < A.Block->getNumber();
2080b57cec5SDimitry Andric       if (A.Pos == -1)
2090b57cec5SDimitry Andric         return Pos != A.Pos;
2100b57cec5SDimitry Andric       return Pos != -1 && Pos < A.Pos;
2110b57cec5SDimitry Andric     }
2120b57cec5SDimitry Andric   private:
2130b57cec5SDimitry Andric     int Pos = 0;
2140b57cec5SDimitry Andric   };
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   struct HexagonConstExtenders : public MachineFunctionPass {
2170b57cec5SDimitry Andric     static char ID;
2180b57cec5SDimitry Andric     HexagonConstExtenders() : MachineFunctionPass(ID) {}
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override {
2210fca6ea1SDimitry Andric       AU.addRequired<MachineDominatorTreeWrapperPass>();
2220fca6ea1SDimitry Andric       AU.addPreserved<MachineDominatorTreeWrapperPass>();
2230b57cec5SDimitry Andric       MachineFunctionPass::getAnalysisUsage(AU);
2240b57cec5SDimitry Andric     }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric     StringRef getPassName() const override {
2270b57cec5SDimitry Andric       return "Hexagon constant-extender optimization";
2280b57cec5SDimitry Andric     }
2290b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   private:
2320b57cec5SDimitry Andric     struct Register {
2330b57cec5SDimitry Andric       Register() = default;
23404eeddc0SDimitry Andric       Register(llvm::Register R, unsigned S) : Reg(R), Sub(S) {}
2350b57cec5SDimitry Andric       Register(const MachineOperand &Op)
2360b57cec5SDimitry Andric         : Reg(Op.getReg()), Sub(Op.getSubReg()) {}
2370b57cec5SDimitry Andric       Register &operator=(const MachineOperand &Op) {
2380b57cec5SDimitry Andric         if (Op.isReg()) {
2390b57cec5SDimitry Andric           Reg = Op.getReg();
2400b57cec5SDimitry Andric           Sub = Op.getSubReg();
2410b57cec5SDimitry Andric         } else if (Op.isFI()) {
2428bcb0991SDimitry Andric           Reg = llvm::Register::index2StackSlot(Op.getIndex());
2430b57cec5SDimitry Andric         }
2440b57cec5SDimitry Andric         return *this;
2450b57cec5SDimitry Andric       }
2460b57cec5SDimitry Andric       bool isVReg() const {
247e8d8bef9SDimitry Andric         return Reg != 0 && !Reg.isStack() && Reg.isVirtual();
2480b57cec5SDimitry Andric       }
249e8d8bef9SDimitry Andric       bool isSlot() const { return Reg != 0 && Reg.isStack(); }
2500b57cec5SDimitry Andric       operator MachineOperand() const {
2510b57cec5SDimitry Andric         if (isVReg())
2520b57cec5SDimitry Andric           return MachineOperand::CreateReg(Reg, /*Def*/false, /*Imp*/false,
2530b57cec5SDimitry Andric                           /*Kill*/false, /*Dead*/false, /*Undef*/false,
2540b57cec5SDimitry Andric                           /*EarlyClobber*/false, Sub);
255e8d8bef9SDimitry Andric         if (Reg.isStack()) {
2568bcb0991SDimitry Andric           int FI = llvm::Register::stackSlot2Index(Reg);
2570b57cec5SDimitry Andric           return MachineOperand::CreateFI(FI);
2580b57cec5SDimitry Andric         }
2590b57cec5SDimitry Andric         llvm_unreachable("Cannot create MachineOperand");
2600b57cec5SDimitry Andric       }
2610b57cec5SDimitry Andric       bool operator==(Register R) const { return Reg == R.Reg && Sub == R.Sub; }
2620b57cec5SDimitry Andric       bool operator!=(Register R) const { return !operator==(R); }
2630b57cec5SDimitry Andric       bool operator<(Register R) const {
2640b57cec5SDimitry Andric         // For std::map.
2650b57cec5SDimitry Andric         return Reg < R.Reg || (Reg == R.Reg && Sub < R.Sub);
2660b57cec5SDimitry Andric       }
267e8d8bef9SDimitry Andric       llvm::Register Reg;
268e8d8bef9SDimitry Andric       unsigned Sub = 0;
2690b57cec5SDimitry Andric     };
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     struct ExtExpr {
2720b57cec5SDimitry Andric       // A subexpression in which the extender is used. In general, this
2730b57cec5SDimitry Andric       // represents an expression where adding D to the extender will be
2740b57cec5SDimitry Andric       // equivalent to adding D to the expression as a whole. In other
2750b57cec5SDimitry Andric       // words, expr(add(##V,D) = add(expr(##V),D).
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric       // The original motivation for this are the io/ur addressing modes,
2780b57cec5SDimitry Andric       // where the offset is extended. Consider the io example:
2790b57cec5SDimitry Andric       // In memw(Rs+##V), the ##V could be replaced by a register Rt to
2800b57cec5SDimitry Andric       // form the rr mode: memw(Rt+Rs<<0). In such case, however, the
2810b57cec5SDimitry Andric       // register Rt must have exactly the value of ##V. If there was
2820b57cec5SDimitry Andric       // another instruction memw(Rs+##V+4), it would need a different Rt.
2830b57cec5SDimitry Andric       // Now, if Rt was initialized as "##V+Rs<<0", both of these
2840b57cec5SDimitry Andric       // instructions could use the same Rt, just with different offsets.
2850b57cec5SDimitry Andric       // Here it's clear that "initializer+4" should be the same as if
2860b57cec5SDimitry Andric       // the offset 4 was added to the ##V in the initializer.
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric       // The only kinds of expressions that support the requirement of
2890b57cec5SDimitry Andric       // commuting with addition are addition and subtraction from ##V.
2900b57cec5SDimitry Andric       // Include shifting the Rs to account for the ur addressing mode:
2910b57cec5SDimitry Andric       //   ##Val + Rs << S
2920b57cec5SDimitry Andric       //   ##Val - Rs
2930b57cec5SDimitry Andric       Register Rs;
2940b57cec5SDimitry Andric       unsigned S = 0;
2950b57cec5SDimitry Andric       bool Neg = false;
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric       ExtExpr() = default;
2980b57cec5SDimitry Andric       ExtExpr(Register RS, bool NG, unsigned SH) : Rs(RS), S(SH), Neg(NG) {}
2990b57cec5SDimitry Andric       // Expression is trivial if it does not modify the extender.
3000b57cec5SDimitry Andric       bool trivial() const {
3010b57cec5SDimitry Andric         return Rs.Reg == 0;
3020b57cec5SDimitry Andric       }
3030b57cec5SDimitry Andric       bool operator==(const ExtExpr &Ex) const {
3040b57cec5SDimitry Andric         return Rs == Ex.Rs && S == Ex.S && Neg == Ex.Neg;
3050b57cec5SDimitry Andric       }
3060b57cec5SDimitry Andric       bool operator!=(const ExtExpr &Ex) const {
3070b57cec5SDimitry Andric         return !operator==(Ex);
3080b57cec5SDimitry Andric       }
3090b57cec5SDimitry Andric       bool operator<(const ExtExpr &Ex) const {
3100b57cec5SDimitry Andric         if (Rs != Ex.Rs)
3110b57cec5SDimitry Andric           return Rs < Ex.Rs;
3120b57cec5SDimitry Andric         if (S != Ex.S)
3130b57cec5SDimitry Andric           return S < Ex.S;
3140b57cec5SDimitry Andric         return !Neg && Ex.Neg;
3150b57cec5SDimitry Andric       }
3160b57cec5SDimitry Andric     };
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     struct ExtDesc {
3190b57cec5SDimitry Andric       MachineInstr *UseMI = nullptr;
3200b57cec5SDimitry Andric       unsigned OpNum = -1u;
3210b57cec5SDimitry Andric       // The subexpression in which the extender is used (e.g. address
3220b57cec5SDimitry Andric       // computation).
3230b57cec5SDimitry Andric       ExtExpr Expr;
3240b57cec5SDimitry Andric       // Optional register that is assigned the value of Expr.
3250b57cec5SDimitry Andric       Register Rd;
3260b57cec5SDimitry Andric       // Def means that the output of the instruction may differ from the
3270b57cec5SDimitry Andric       // original by a constant c, and that the difference can be corrected
3280b57cec5SDimitry Andric       // by adding/subtracting c in all users of the defined register.
3290b57cec5SDimitry Andric       bool IsDef = false;
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric       MachineOperand &getOp() {
3320b57cec5SDimitry Andric         return UseMI->getOperand(OpNum);
3330b57cec5SDimitry Andric       }
3340b57cec5SDimitry Andric       const MachineOperand &getOp() const {
3350b57cec5SDimitry Andric         return UseMI->getOperand(OpNum);
3360b57cec5SDimitry Andric       }
3370b57cec5SDimitry Andric     };
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     struct ExtRoot {
3400b57cec5SDimitry Andric       union {
3410b57cec5SDimitry Andric         const ConstantFP *CFP;  // MO_FPImmediate
3420b57cec5SDimitry Andric         const char *SymbolName; // MO_ExternalSymbol
3430b57cec5SDimitry Andric         const GlobalValue *GV;  // MO_GlobalAddress
3440b57cec5SDimitry Andric         const BlockAddress *BA; // MO_BlockAddress
3450b57cec5SDimitry Andric         int64_t ImmVal;         // MO_Immediate, MO_TargetIndex,
3460b57cec5SDimitry Andric                                 // and MO_ConstantPoolIndex
3470b57cec5SDimitry Andric       } V;
3480b57cec5SDimitry Andric       unsigned Kind;            // Same as in MachineOperand.
3490b57cec5SDimitry Andric       unsigned char TF;         // TargetFlags.
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric       ExtRoot(const MachineOperand &Op);
3520b57cec5SDimitry Andric       bool operator==(const ExtRoot &ER) const {
3530b57cec5SDimitry Andric         return Kind == ER.Kind && V.ImmVal == ER.V.ImmVal;
3540b57cec5SDimitry Andric       }
3550b57cec5SDimitry Andric       bool operator!=(const ExtRoot &ER) const {
3560b57cec5SDimitry Andric         return !operator==(ER);
3570b57cec5SDimitry Andric       }
3580b57cec5SDimitry Andric       bool operator<(const ExtRoot &ER) const;
3590b57cec5SDimitry Andric     };
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric     struct ExtValue : public ExtRoot {
3620b57cec5SDimitry Andric       int32_t Offset;
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric       ExtValue(const MachineOperand &Op);
3650b57cec5SDimitry Andric       ExtValue(const ExtDesc &ED) : ExtValue(ED.getOp()) {}
3660b57cec5SDimitry Andric       ExtValue(const ExtRoot &ER, int32_t Off) : ExtRoot(ER), Offset(Off) {}
3670b57cec5SDimitry Andric       bool operator<(const ExtValue &EV) const;
3680b57cec5SDimitry Andric       bool operator==(const ExtValue &EV) const {
3690b57cec5SDimitry Andric         return ExtRoot(*this) == ExtRoot(EV) && Offset == EV.Offset;
3700b57cec5SDimitry Andric       }
3710b57cec5SDimitry Andric       bool operator!=(const ExtValue &EV) const {
3720b57cec5SDimitry Andric         return !operator==(EV);
3730b57cec5SDimitry Andric       }
3740b57cec5SDimitry Andric       explicit operator MachineOperand() const;
3750b57cec5SDimitry Andric     };
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric     using IndexList = SetVector<unsigned>;
3780b57cec5SDimitry Andric     using ExtenderInit = std::pair<ExtValue, ExtExpr>;
3790b57cec5SDimitry Andric     using AssignmentMap = std::map<ExtenderInit, IndexList>;
3800b57cec5SDimitry Andric     using LocDefList = std::vector<std::pair<Loc, IndexList>>;
3810b57cec5SDimitry Andric 
3825ffd83dbSDimitry Andric     const HexagonSubtarget *HST = nullptr;
3830b57cec5SDimitry Andric     const HexagonInstrInfo *HII = nullptr;
3840b57cec5SDimitry Andric     const HexagonRegisterInfo *HRI = nullptr;
3850b57cec5SDimitry Andric     MachineDominatorTree *MDT = nullptr;
3860b57cec5SDimitry Andric     MachineRegisterInfo *MRI = nullptr;
3870b57cec5SDimitry Andric     std::vector<ExtDesc> Extenders;
3880b57cec5SDimitry Andric     std::vector<unsigned> NewRegs;
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric     bool isStoreImmediate(unsigned Opc) const;
3910b57cec5SDimitry Andric     bool isRegOffOpcode(unsigned ExtOpc) const ;
3920b57cec5SDimitry Andric     unsigned getRegOffOpcode(unsigned ExtOpc) const;
3930b57cec5SDimitry Andric     unsigned getDirectRegReplacement(unsigned ExtOpc) const;
3940b57cec5SDimitry Andric     OffsetRange getOffsetRange(Register R, const MachineInstr &MI) const;
3950b57cec5SDimitry Andric     OffsetRange getOffsetRange(const ExtDesc &ED) const;
3960b57cec5SDimitry Andric     OffsetRange getOffsetRange(Register Rd) const;
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric     void recordExtender(MachineInstr &MI, unsigned OpNum);
3990b57cec5SDimitry Andric     void collectInstr(MachineInstr &MI);
4000b57cec5SDimitry Andric     void collect(MachineFunction &MF);
4010b57cec5SDimitry Andric     void assignInits(const ExtRoot &ER, unsigned Begin, unsigned End,
4020b57cec5SDimitry Andric                      AssignmentMap &IMap);
4030b57cec5SDimitry Andric     void calculatePlacement(const ExtenderInit &ExtI, const IndexList &Refs,
4040b57cec5SDimitry Andric                             LocDefList &Defs);
4050b57cec5SDimitry Andric     Register insertInitializer(Loc DefL, const ExtenderInit &ExtI);
4060b57cec5SDimitry Andric     bool replaceInstrExact(const ExtDesc &ED, Register ExtR);
4070b57cec5SDimitry Andric     bool replaceInstrExpr(const ExtDesc &ED, const ExtenderInit &ExtI,
4080b57cec5SDimitry Andric                           Register ExtR, int32_t &Diff);
4090b57cec5SDimitry Andric     bool replaceInstr(unsigned Idx, Register ExtR, const ExtenderInit &ExtI);
4100b57cec5SDimitry Andric     bool replaceExtenders(const AssignmentMap &IMap);
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric     unsigned getOperandIndex(const MachineInstr &MI,
4130b57cec5SDimitry Andric                              const MachineOperand &Op) const;
4140b57cec5SDimitry Andric     const MachineOperand &getPredicateOp(const MachineInstr &MI) const;
4150b57cec5SDimitry Andric     const MachineOperand &getLoadResultOp(const MachineInstr &MI) const;
4160b57cec5SDimitry Andric     const MachineOperand &getStoredValueOp(const MachineInstr &MI) const;
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric     friend struct PrintRegister;
4190b57cec5SDimitry Andric     friend struct PrintExpr;
4200b57cec5SDimitry Andric     friend struct PrintInit;
4210b57cec5SDimitry Andric     friend struct PrintIMap;
4220b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS,
4230b57cec5SDimitry Andric                                     const struct PrintRegister &P);
4240b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintExpr &P);
4250b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintInit &P);
4260b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const ExtDesc &ED);
4270b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const ExtRoot &ER);
4280b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const ExtValue &EV);
4290b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const OffsetRange &OR);
4300b57cec5SDimitry Andric     friend raw_ostream &operator<< (raw_ostream &OS, const struct PrintIMap &P);
4310b57cec5SDimitry Andric   };
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   using HCE = HexagonConstExtenders;
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
4360b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const OffsetRange &OR) {
4370b57cec5SDimitry Andric     if (OR.Min > OR.Max)
4380b57cec5SDimitry Andric       OS << '!';
4390b57cec5SDimitry Andric     OS << '[' << OR.Min << ',' << OR.Max << "]a" << unsigned(OR.Align)
4400b57cec5SDimitry Andric        << '+' << unsigned(OR.Offset);
4410b57cec5SDimitry Andric     return OS;
4420b57cec5SDimitry Andric   }
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   struct PrintRegister {
4450b57cec5SDimitry Andric     PrintRegister(HCE::Register R, const HexagonRegisterInfo &I)
4460b57cec5SDimitry Andric       : Rs(R), HRI(I) {}
4470b57cec5SDimitry Andric     HCE::Register Rs;
4480b57cec5SDimitry Andric     const HexagonRegisterInfo &HRI;
4490b57cec5SDimitry Andric   };
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
4520b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &P) {
4530b57cec5SDimitry Andric     if (P.Rs.Reg != 0)
4540b57cec5SDimitry Andric       OS << printReg(P.Rs.Reg, &P.HRI, P.Rs.Sub);
4550b57cec5SDimitry Andric     else
4560b57cec5SDimitry Andric       OS << "noreg";
4570b57cec5SDimitry Andric     return OS;
4580b57cec5SDimitry Andric   }
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   struct PrintExpr {
4610b57cec5SDimitry Andric     PrintExpr(const HCE::ExtExpr &E, const HexagonRegisterInfo &I)
4620b57cec5SDimitry Andric       : Ex(E), HRI(I) {}
4630b57cec5SDimitry Andric     const HCE::ExtExpr &Ex;
4640b57cec5SDimitry Andric     const HexagonRegisterInfo &HRI;
4650b57cec5SDimitry Andric   };
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
4680b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const PrintExpr &P) {
4690b57cec5SDimitry Andric     OS << "## " << (P.Ex.Neg ? "- " : "+ ");
4700b57cec5SDimitry Andric     if (P.Ex.Rs.Reg != 0)
4710b57cec5SDimitry Andric       OS << printReg(P.Ex.Rs.Reg, &P.HRI, P.Ex.Rs.Sub);
4720b57cec5SDimitry Andric     else
4730b57cec5SDimitry Andric       OS << "__";
4740b57cec5SDimitry Andric     OS << " << " << P.Ex.S;
4750b57cec5SDimitry Andric     return OS;
4760b57cec5SDimitry Andric   }
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric   struct PrintInit {
4790b57cec5SDimitry Andric     PrintInit(const HCE::ExtenderInit &EI, const HexagonRegisterInfo &I)
4800b57cec5SDimitry Andric       : ExtI(EI), HRI(I) {}
4810b57cec5SDimitry Andric     const HCE::ExtenderInit &ExtI;
4820b57cec5SDimitry Andric     const HexagonRegisterInfo &HRI;
4830b57cec5SDimitry Andric   };
4840b57cec5SDimitry Andric 
4850b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
4860b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const PrintInit &P) {
4870b57cec5SDimitry Andric     OS << '[' << P.ExtI.first << ", "
4880b57cec5SDimitry Andric        << PrintExpr(P.ExtI.second, P.HRI) << ']';
4890b57cec5SDimitry Andric     return OS;
4900b57cec5SDimitry Andric   }
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
4930b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtDesc &ED) {
4940b57cec5SDimitry Andric     assert(ED.OpNum != -1u);
4950b57cec5SDimitry Andric     const MachineBasicBlock &MBB = *ED.getOp().getParent()->getParent();
4960b57cec5SDimitry Andric     const MachineFunction &MF = *MBB.getParent();
4970b57cec5SDimitry Andric     const auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
4980b57cec5SDimitry Andric     OS << "bb#" << MBB.getNumber() << ": ";
4990b57cec5SDimitry Andric     if (ED.Rd.Reg != 0)
5000b57cec5SDimitry Andric       OS << printReg(ED.Rd.Reg, &HRI, ED.Rd.Sub);
5010b57cec5SDimitry Andric     else
5020b57cec5SDimitry Andric       OS << "__";
5030b57cec5SDimitry Andric     OS << " = " << PrintExpr(ED.Expr, HRI);
5040b57cec5SDimitry Andric     if (ED.IsDef)
5050b57cec5SDimitry Andric       OS << ", def";
5060b57cec5SDimitry Andric     return OS;
5070b57cec5SDimitry Andric   }
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
5100b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtRoot &ER) {
5110b57cec5SDimitry Andric     switch (ER.Kind) {
5120b57cec5SDimitry Andric       case MachineOperand::MO_Immediate:
5130b57cec5SDimitry Andric         OS << "imm:" << ER.V.ImmVal;
5140b57cec5SDimitry Andric         break;
5150b57cec5SDimitry Andric       case MachineOperand::MO_FPImmediate:
5160b57cec5SDimitry Andric         OS << "fpi:" << *ER.V.CFP;
5170b57cec5SDimitry Andric         break;
5180b57cec5SDimitry Andric       case MachineOperand::MO_ExternalSymbol:
5190b57cec5SDimitry Andric         OS << "sym:" << *ER.V.SymbolName;
5200b57cec5SDimitry Andric         break;
5210b57cec5SDimitry Andric       case MachineOperand::MO_GlobalAddress:
5220b57cec5SDimitry Andric         OS << "gad:" << ER.V.GV->getName();
5230b57cec5SDimitry Andric         break;
5240b57cec5SDimitry Andric       case MachineOperand::MO_BlockAddress:
5250b57cec5SDimitry Andric         OS << "blk:" << *ER.V.BA;
5260b57cec5SDimitry Andric         break;
5270b57cec5SDimitry Andric       case MachineOperand::MO_TargetIndex:
5280b57cec5SDimitry Andric         OS << "tgi:" << ER.V.ImmVal;
5290b57cec5SDimitry Andric         break;
5300b57cec5SDimitry Andric       case MachineOperand::MO_ConstantPoolIndex:
5310b57cec5SDimitry Andric         OS << "cpi:" << ER.V.ImmVal;
5320b57cec5SDimitry Andric         break;
5330b57cec5SDimitry Andric       case MachineOperand::MO_JumpTableIndex:
5340b57cec5SDimitry Andric         OS << "jti:" << ER.V.ImmVal;
5350b57cec5SDimitry Andric         break;
5360b57cec5SDimitry Andric       default:
5370b57cec5SDimitry Andric         OS << "???:" << ER.V.ImmVal;
5380b57cec5SDimitry Andric         break;
5390b57cec5SDimitry Andric     }
5400b57cec5SDimitry Andric     return OS;
5410b57cec5SDimitry Andric   }
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
5440b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const HCE::ExtValue &EV) {
5450b57cec5SDimitry Andric     OS << HCE::ExtRoot(EV) << "  off:" << EV.Offset;
5460b57cec5SDimitry Andric     return OS;
5470b57cec5SDimitry Andric   }
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   struct PrintIMap {
5500b57cec5SDimitry Andric     PrintIMap(const HCE::AssignmentMap &M, const HexagonRegisterInfo &I)
5510b57cec5SDimitry Andric       : IMap(M), HRI(I) {}
5520b57cec5SDimitry Andric     const HCE::AssignmentMap &IMap;
5530b57cec5SDimitry Andric     const HexagonRegisterInfo &HRI;
5540b57cec5SDimitry Andric   };
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric   LLVM_ATTRIBUTE_UNUSED
5570b57cec5SDimitry Andric   raw_ostream &operator<< (raw_ostream &OS, const PrintIMap &P) {
5580b57cec5SDimitry Andric     OS << "{\n";
559480093f4SDimitry Andric     for (const std::pair<const HCE::ExtenderInit, HCE::IndexList> &Q : P.IMap) {
5600b57cec5SDimitry Andric       OS << "  " << PrintInit(Q.first, P.HRI) << " -> {";
5610b57cec5SDimitry Andric       for (unsigned I : Q.second)
5620b57cec5SDimitry Andric         OS << ' ' << I;
5630b57cec5SDimitry Andric       OS << " }\n";
5640b57cec5SDimitry Andric     }
5650b57cec5SDimitry Andric     OS << "}\n";
5660b57cec5SDimitry Andric     return OS;
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonConstExtenders, "hexagon-cext-opt",
5710b57cec5SDimitry Andric       "Hexagon constant-extender optimization", false, false)
5720fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
5730b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonConstExtenders, "hexagon-cext-opt",
5740b57cec5SDimitry Andric       "Hexagon constant-extender optimization", false, false)
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric static unsigned ReplaceCounter = 0;
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric char HCE::ID = 0;
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric #ifndef NDEBUG
5810b57cec5SDimitry Andric LLVM_DUMP_METHOD void RangeTree::dump() const {
5820b57cec5SDimitry Andric   dbgs() << "Root: " << Root << '\n';
5830b57cec5SDimitry Andric   if (Root)
5840b57cec5SDimitry Andric     dump(Root);
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric LLVM_DUMP_METHOD void RangeTree::dump(const Node *N) const {
5880b57cec5SDimitry Andric   dbgs() << "Node: " << N << '\n';
5890b57cec5SDimitry Andric   dbgs() << "  Height: " << N->Height << '\n';
5900b57cec5SDimitry Andric   dbgs() << "  Count: " << N->Count << '\n';
5910b57cec5SDimitry Andric   dbgs() << "  MaxEnd: " << N->MaxEnd << '\n';
5920b57cec5SDimitry Andric   dbgs() << "  Range: " << N->Range << '\n';
5930b57cec5SDimitry Andric   dbgs() << "  Left: " << N->Left << '\n';
5940b57cec5SDimitry Andric   dbgs() << "  Right: " << N->Right << "\n\n";
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   if (N->Left)
5970b57cec5SDimitry Andric     dump(N->Left);
5980b57cec5SDimitry Andric   if (N->Right)
5990b57cec5SDimitry Andric     dump(N->Right);
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric #endif
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric void RangeTree::order(Node *N, SmallVectorImpl<Node*> &Seq) const {
6040b57cec5SDimitry Andric   if (N == nullptr)
6050b57cec5SDimitry Andric     return;
6060b57cec5SDimitry Andric   order(N->Left, Seq);
6070b57cec5SDimitry Andric   Seq.push_back(N);
6080b57cec5SDimitry Andric   order(N->Right, Seq);
6090b57cec5SDimitry Andric }
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric void RangeTree::nodesWith(Node *N, int32_t P, bool CheckA,
6120b57cec5SDimitry Andric       SmallVectorImpl<Node*> &Seq) const {
6130b57cec5SDimitry Andric   if (N == nullptr || N->MaxEnd < P)
6140b57cec5SDimitry Andric     return;
6150b57cec5SDimitry Andric   nodesWith(N->Left, P, CheckA, Seq);
6160b57cec5SDimitry Andric   if (N->Range.Min <= P) {
6170b57cec5SDimitry Andric     if ((CheckA && N->Range.contains(P)) || (!CheckA && P <= N->Range.Max))
6180b57cec5SDimitry Andric       Seq.push_back(N);
6190b57cec5SDimitry Andric     nodesWith(N->Right, P, CheckA, Seq);
6200b57cec5SDimitry Andric   }
6210b57cec5SDimitry Andric }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric RangeTree::Node *RangeTree::add(Node *N, const OffsetRange &R) {
6240b57cec5SDimitry Andric   if (N == nullptr)
6250b57cec5SDimitry Andric     return new Node(R);
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric   if (N->Range == R) {
6280b57cec5SDimitry Andric     N->Count++;
6290b57cec5SDimitry Andric     return N;
6300b57cec5SDimitry Andric   }
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric   if (R < N->Range)
6330b57cec5SDimitry Andric     N->Left = add(N->Left, R);
6340b57cec5SDimitry Andric   else
6350b57cec5SDimitry Andric     N->Right = add(N->Right, R);
6360b57cec5SDimitry Andric   return rebalance(update(N));
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric RangeTree::Node *RangeTree::remove(Node *N, const Node *D) {
6400b57cec5SDimitry Andric   assert(N != nullptr);
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   if (N != D) {
6430b57cec5SDimitry Andric     assert(N->Range != D->Range && "N and D should not be equal");
6440b57cec5SDimitry Andric     if (D->Range < N->Range)
6450b57cec5SDimitry Andric       N->Left = remove(N->Left, D);
6460b57cec5SDimitry Andric     else
6470b57cec5SDimitry Andric       N->Right = remove(N->Right, D);
6480b57cec5SDimitry Andric     return rebalance(update(N));
6490b57cec5SDimitry Andric   }
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric   // We got to the node we need to remove. If any of its children are
6520b57cec5SDimitry Andric   // missing, simply replace it with the other child.
6530b57cec5SDimitry Andric   if (N->Left == nullptr || N->Right == nullptr)
6540b57cec5SDimitry Andric     return (N->Left == nullptr) ? N->Right : N->Left;
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   // Find the rightmost child of N->Left, remove it and plug it in place
6570b57cec5SDimitry Andric   // of N.
6580b57cec5SDimitry Andric   Node *M = N->Left;
6590b57cec5SDimitry Andric   while (M->Right)
6600b57cec5SDimitry Andric     M = M->Right;
6610b57cec5SDimitry Andric   M->Left = remove(N->Left, M);
6620b57cec5SDimitry Andric   M->Right = N->Right;
6630b57cec5SDimitry Andric   return rebalance(update(M));
6640b57cec5SDimitry Andric }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric RangeTree::Node *RangeTree::rotateLeft(Node *Lower, Node *Higher) {
6670b57cec5SDimitry Andric   assert(Higher->Right == Lower);
6680b57cec5SDimitry Andric   // The Lower node is on the right from Higher. Make sure that Lower's
6690b57cec5SDimitry Andric   // balance is greater to the right. Otherwise the rotation will create
6700b57cec5SDimitry Andric   // an unbalanced tree again.
6710b57cec5SDimitry Andric   if (height(Lower->Left) > height(Lower->Right))
6720b57cec5SDimitry Andric     Lower = rotateRight(Lower->Left, Lower);
6730b57cec5SDimitry Andric   assert(height(Lower->Left) <= height(Lower->Right));
6740b57cec5SDimitry Andric   Higher->Right = Lower->Left;
6750b57cec5SDimitry Andric   update(Higher);
6760b57cec5SDimitry Andric   Lower->Left = Higher;
6770b57cec5SDimitry Andric   update(Lower);
6780b57cec5SDimitry Andric   return Lower;
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric RangeTree::Node *RangeTree::rotateRight(Node *Lower, Node *Higher) {
6820b57cec5SDimitry Andric   assert(Higher->Left == Lower);
6830b57cec5SDimitry Andric   // The Lower node is on the left from Higher. Make sure that Lower's
6840b57cec5SDimitry Andric   // balance is greater to the left. Otherwise the rotation will create
6850b57cec5SDimitry Andric   // an unbalanced tree again.
6860b57cec5SDimitry Andric   if (height(Lower->Left) < height(Lower->Right))
6870b57cec5SDimitry Andric     Lower = rotateLeft(Lower->Right, Lower);
6880b57cec5SDimitry Andric   assert(height(Lower->Left) >= height(Lower->Right));
6890b57cec5SDimitry Andric   Higher->Left = Lower->Right;
6900b57cec5SDimitry Andric   update(Higher);
6910b57cec5SDimitry Andric   Lower->Right = Higher;
6920b57cec5SDimitry Andric   update(Lower);
6930b57cec5SDimitry Andric   return Lower;
6940b57cec5SDimitry Andric }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric HCE::ExtRoot::ExtRoot(const MachineOperand &Op) {
6980b57cec5SDimitry Andric   // Always store ImmVal, since it's the field used for comparisons.
6990b57cec5SDimitry Andric   V.ImmVal = 0;
7000b57cec5SDimitry Andric   if (Op.isImm())
7010b57cec5SDimitry Andric     ; // Keep 0. Do not use Op.getImm() for value here (treat 0 as the root).
7020b57cec5SDimitry Andric   else if (Op.isFPImm())
7030b57cec5SDimitry Andric     V.CFP = Op.getFPImm();
7040b57cec5SDimitry Andric   else if (Op.isSymbol())
7050b57cec5SDimitry Andric     V.SymbolName = Op.getSymbolName();
7060b57cec5SDimitry Andric   else if (Op.isGlobal())
7070b57cec5SDimitry Andric     V.GV = Op.getGlobal();
7080b57cec5SDimitry Andric   else if (Op.isBlockAddress())
7090b57cec5SDimitry Andric     V.BA = Op.getBlockAddress();
7100b57cec5SDimitry Andric   else if (Op.isCPI() || Op.isTargetIndex() || Op.isJTI())
7110b57cec5SDimitry Andric     V.ImmVal = Op.getIndex();
7120b57cec5SDimitry Andric   else
7130b57cec5SDimitry Andric     llvm_unreachable("Unexpected operand type");
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   Kind = Op.getType();
7160b57cec5SDimitry Andric   TF = Op.getTargetFlags();
7170b57cec5SDimitry Andric }
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric bool HCE::ExtRoot::operator< (const HCE::ExtRoot &ER) const {
7200b57cec5SDimitry Andric   if (Kind != ER.Kind)
7210b57cec5SDimitry Andric     return Kind < ER.Kind;
7220b57cec5SDimitry Andric   switch (Kind) {
7230b57cec5SDimitry Andric     case MachineOperand::MO_Immediate:
7240b57cec5SDimitry Andric     case MachineOperand::MO_TargetIndex:
7250b57cec5SDimitry Andric     case MachineOperand::MO_ConstantPoolIndex:
7260b57cec5SDimitry Andric     case MachineOperand::MO_JumpTableIndex:
7270b57cec5SDimitry Andric       return V.ImmVal < ER.V.ImmVal;
7280b57cec5SDimitry Andric     case MachineOperand::MO_FPImmediate: {
7290b57cec5SDimitry Andric       const APFloat &ThisF = V.CFP->getValueAPF();
7300b57cec5SDimitry Andric       const APFloat &OtherF = ER.V.CFP->getValueAPF();
7310b57cec5SDimitry Andric       return ThisF.bitcastToAPInt().ult(OtherF.bitcastToAPInt());
7320b57cec5SDimitry Andric     }
7330b57cec5SDimitry Andric     case MachineOperand::MO_ExternalSymbol:
7340b57cec5SDimitry Andric       return StringRef(V.SymbolName) < StringRef(ER.V.SymbolName);
7350b57cec5SDimitry Andric     case MachineOperand::MO_GlobalAddress:
7360b57cec5SDimitry Andric       // Do not use GUIDs, since they depend on the source path. Moving the
7370b57cec5SDimitry Andric       // source file to a different directory could cause different GUID
7380b57cec5SDimitry Andric       // values for a pair of given symbols. These symbols could then compare
7390b57cec5SDimitry Andric       // "less" in one directory, but "greater" in another.
7400b57cec5SDimitry Andric       assert(!V.GV->getName().empty() && !ER.V.GV->getName().empty());
7410b57cec5SDimitry Andric       return V.GV->getName() < ER.V.GV->getName();
7420b57cec5SDimitry Andric     case MachineOperand::MO_BlockAddress: {
7430b57cec5SDimitry Andric       const BasicBlock *ThisB = V.BA->getBasicBlock();
7440b57cec5SDimitry Andric       const BasicBlock *OtherB = ER.V.BA->getBasicBlock();
7450b57cec5SDimitry Andric       assert(ThisB->getParent() == OtherB->getParent());
7460b57cec5SDimitry Andric       const Function &F = *ThisB->getParent();
7470b57cec5SDimitry Andric       return std::distance(F.begin(), ThisB->getIterator()) <
7480b57cec5SDimitry Andric              std::distance(F.begin(), OtherB->getIterator());
7490b57cec5SDimitry Andric     }
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric   return V.ImmVal < ER.V.ImmVal;
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric HCE::ExtValue::ExtValue(const MachineOperand &Op) : ExtRoot(Op) {
7550b57cec5SDimitry Andric   if (Op.isImm())
7560b57cec5SDimitry Andric     Offset = Op.getImm();
7570b57cec5SDimitry Andric   else if (Op.isFPImm() || Op.isJTI())
7580b57cec5SDimitry Andric     Offset = 0;
7590b57cec5SDimitry Andric   else if (Op.isSymbol() || Op.isGlobal() || Op.isBlockAddress() ||
7600b57cec5SDimitry Andric            Op.isCPI() || Op.isTargetIndex())
7610b57cec5SDimitry Andric     Offset = Op.getOffset();
7620b57cec5SDimitry Andric   else
7630b57cec5SDimitry Andric     llvm_unreachable("Unexpected operand type");
7640b57cec5SDimitry Andric }
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric bool HCE::ExtValue::operator< (const HCE::ExtValue &EV) const {
7670b57cec5SDimitry Andric   const ExtRoot &ER = *this;
7680b57cec5SDimitry Andric   if (!(ER == ExtRoot(EV)))
7690b57cec5SDimitry Andric     return ER < EV;
7700b57cec5SDimitry Andric   return Offset < EV.Offset;
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric HCE::ExtValue::operator MachineOperand() const {
7740b57cec5SDimitry Andric   switch (Kind) {
7750b57cec5SDimitry Andric     case MachineOperand::MO_Immediate:
7760b57cec5SDimitry Andric       return MachineOperand::CreateImm(V.ImmVal + Offset);
7770b57cec5SDimitry Andric     case MachineOperand::MO_FPImmediate:
7780b57cec5SDimitry Andric       assert(Offset == 0);
7790b57cec5SDimitry Andric       return MachineOperand::CreateFPImm(V.CFP);
7800b57cec5SDimitry Andric     case MachineOperand::MO_ExternalSymbol:
7810b57cec5SDimitry Andric       assert(Offset == 0);
7820b57cec5SDimitry Andric       return MachineOperand::CreateES(V.SymbolName, TF);
7830b57cec5SDimitry Andric     case MachineOperand::MO_GlobalAddress:
7840b57cec5SDimitry Andric       return MachineOperand::CreateGA(V.GV, Offset, TF);
7850b57cec5SDimitry Andric     case MachineOperand::MO_BlockAddress:
7860b57cec5SDimitry Andric       return MachineOperand::CreateBA(V.BA, Offset, TF);
7870b57cec5SDimitry Andric     case MachineOperand::MO_TargetIndex:
7880b57cec5SDimitry Andric       return MachineOperand::CreateTargetIndex(V.ImmVal, Offset, TF);
7890b57cec5SDimitry Andric     case MachineOperand::MO_ConstantPoolIndex:
7900b57cec5SDimitry Andric       return MachineOperand::CreateCPI(V.ImmVal, Offset, TF);
7910b57cec5SDimitry Andric     case MachineOperand::MO_JumpTableIndex:
7920b57cec5SDimitry Andric       assert(Offset == 0);
7930b57cec5SDimitry Andric       return MachineOperand::CreateJTI(V.ImmVal, TF);
7940b57cec5SDimitry Andric     default:
7950b57cec5SDimitry Andric       llvm_unreachable("Unhandled kind");
7960b57cec5SDimitry Andric  }
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric bool HCE::isStoreImmediate(unsigned Opc) const {
8000b57cec5SDimitry Andric   switch (Opc) {
8010b57cec5SDimitry Andric     case Hexagon::S4_storeirbt_io:
8020b57cec5SDimitry Andric     case Hexagon::S4_storeirbf_io:
8030b57cec5SDimitry Andric     case Hexagon::S4_storeirht_io:
8040b57cec5SDimitry Andric     case Hexagon::S4_storeirhf_io:
8050b57cec5SDimitry Andric     case Hexagon::S4_storeirit_io:
8060b57cec5SDimitry Andric     case Hexagon::S4_storeirif_io:
8070b57cec5SDimitry Andric     case Hexagon::S4_storeirb_io:
8080b57cec5SDimitry Andric     case Hexagon::S4_storeirh_io:
8090b57cec5SDimitry Andric     case Hexagon::S4_storeiri_io:
8100b57cec5SDimitry Andric       return true;
8110b57cec5SDimitry Andric     default:
8120b57cec5SDimitry Andric       break;
8130b57cec5SDimitry Andric   }
8140b57cec5SDimitry Andric   return false;
8150b57cec5SDimitry Andric }
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric bool HCE::isRegOffOpcode(unsigned Opc) const {
8180b57cec5SDimitry Andric   switch (Opc) {
8190b57cec5SDimitry Andric     case Hexagon::L2_loadrub_io:
8200b57cec5SDimitry Andric     case Hexagon::L2_loadrb_io:
8210b57cec5SDimitry Andric     case Hexagon::L2_loadruh_io:
8220b57cec5SDimitry Andric     case Hexagon::L2_loadrh_io:
8230b57cec5SDimitry Andric     case Hexagon::L2_loadri_io:
8240b57cec5SDimitry Andric     case Hexagon::L2_loadrd_io:
8250b57cec5SDimitry Andric     case Hexagon::L2_loadbzw2_io:
8260b57cec5SDimitry Andric     case Hexagon::L2_loadbzw4_io:
8270b57cec5SDimitry Andric     case Hexagon::L2_loadbsw2_io:
8280b57cec5SDimitry Andric     case Hexagon::L2_loadbsw4_io:
8290b57cec5SDimitry Andric     case Hexagon::L2_loadalignh_io:
8300b57cec5SDimitry Andric     case Hexagon::L2_loadalignb_io:
8310b57cec5SDimitry Andric     case Hexagon::L2_ploadrubt_io:
8320b57cec5SDimitry Andric     case Hexagon::L2_ploadrubf_io:
8330b57cec5SDimitry Andric     case Hexagon::L2_ploadrbt_io:
8340b57cec5SDimitry Andric     case Hexagon::L2_ploadrbf_io:
8350b57cec5SDimitry Andric     case Hexagon::L2_ploadruht_io:
8360b57cec5SDimitry Andric     case Hexagon::L2_ploadruhf_io:
8370b57cec5SDimitry Andric     case Hexagon::L2_ploadrht_io:
8380b57cec5SDimitry Andric     case Hexagon::L2_ploadrhf_io:
8390b57cec5SDimitry Andric     case Hexagon::L2_ploadrit_io:
8400b57cec5SDimitry Andric     case Hexagon::L2_ploadrif_io:
8410b57cec5SDimitry Andric     case Hexagon::L2_ploadrdt_io:
8420b57cec5SDimitry Andric     case Hexagon::L2_ploadrdf_io:
8430b57cec5SDimitry Andric     case Hexagon::S2_storerb_io:
8440b57cec5SDimitry Andric     case Hexagon::S2_storerh_io:
8450b57cec5SDimitry Andric     case Hexagon::S2_storerf_io:
8460b57cec5SDimitry Andric     case Hexagon::S2_storeri_io:
8470b57cec5SDimitry Andric     case Hexagon::S2_storerd_io:
8480b57cec5SDimitry Andric     case Hexagon::S2_pstorerbt_io:
8490b57cec5SDimitry Andric     case Hexagon::S2_pstorerbf_io:
8500b57cec5SDimitry Andric     case Hexagon::S2_pstorerht_io:
8510b57cec5SDimitry Andric     case Hexagon::S2_pstorerhf_io:
8520b57cec5SDimitry Andric     case Hexagon::S2_pstorerft_io:
8530b57cec5SDimitry Andric     case Hexagon::S2_pstorerff_io:
8540b57cec5SDimitry Andric     case Hexagon::S2_pstorerit_io:
8550b57cec5SDimitry Andric     case Hexagon::S2_pstorerif_io:
8560b57cec5SDimitry Andric     case Hexagon::S2_pstorerdt_io:
8570b57cec5SDimitry Andric     case Hexagon::S2_pstorerdf_io:
8580b57cec5SDimitry Andric     case Hexagon::A2_addi:
8590b57cec5SDimitry Andric       return true;
8600b57cec5SDimitry Andric     default:
8610b57cec5SDimitry Andric       break;
8620b57cec5SDimitry Andric   }
8630b57cec5SDimitry Andric   return false;
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric unsigned HCE::getRegOffOpcode(unsigned ExtOpc) const {
8670b57cec5SDimitry Andric   // If there exists an instruction that takes a register and offset,
8680b57cec5SDimitry Andric   // that corresponds to the ExtOpc, return it, otherwise return 0.
8690b57cec5SDimitry Andric   using namespace Hexagon;
8700b57cec5SDimitry Andric   switch (ExtOpc) {
8710b57cec5SDimitry Andric     case A2_tfrsi:    return A2_addi;
8720b57cec5SDimitry Andric     default:
8730b57cec5SDimitry Andric       break;
8740b57cec5SDimitry Andric   }
8750b57cec5SDimitry Andric   const MCInstrDesc &D = HII->get(ExtOpc);
8760b57cec5SDimitry Andric   if (D.mayLoad() || D.mayStore()) {
8770b57cec5SDimitry Andric     uint64_t F = D.TSFlags;
8780b57cec5SDimitry Andric     unsigned AM = (F >> HexagonII::AddrModePos) & HexagonII::AddrModeMask;
8790b57cec5SDimitry Andric     switch (AM) {
8800b57cec5SDimitry Andric       case HexagonII::Absolute:
8810b57cec5SDimitry Andric       case HexagonII::AbsoluteSet:
8820b57cec5SDimitry Andric       case HexagonII::BaseLongOffset:
8830b57cec5SDimitry Andric         switch (ExtOpc) {
8840b57cec5SDimitry Andric           case PS_loadrubabs:
8850b57cec5SDimitry Andric           case L4_loadrub_ap:
8860b57cec5SDimitry Andric           case L4_loadrub_ur:     return L2_loadrub_io;
8870b57cec5SDimitry Andric           case PS_loadrbabs:
8880b57cec5SDimitry Andric           case L4_loadrb_ap:
8890b57cec5SDimitry Andric           case L4_loadrb_ur:      return L2_loadrb_io;
8900b57cec5SDimitry Andric           case PS_loadruhabs:
8910b57cec5SDimitry Andric           case L4_loadruh_ap:
8920b57cec5SDimitry Andric           case L4_loadruh_ur:     return L2_loadruh_io;
8930b57cec5SDimitry Andric           case PS_loadrhabs:
8940b57cec5SDimitry Andric           case L4_loadrh_ap:
8950b57cec5SDimitry Andric           case L4_loadrh_ur:      return L2_loadrh_io;
8960b57cec5SDimitry Andric           case PS_loadriabs:
8970b57cec5SDimitry Andric           case L4_loadri_ap:
8980b57cec5SDimitry Andric           case L4_loadri_ur:      return L2_loadri_io;
8990b57cec5SDimitry Andric           case PS_loadrdabs:
9000b57cec5SDimitry Andric           case L4_loadrd_ap:
9010b57cec5SDimitry Andric           case L4_loadrd_ur:      return L2_loadrd_io;
9020b57cec5SDimitry Andric           case L4_loadbzw2_ap:
9030b57cec5SDimitry Andric           case L4_loadbzw2_ur:    return L2_loadbzw2_io;
9040b57cec5SDimitry Andric           case L4_loadbzw4_ap:
9050b57cec5SDimitry Andric           case L4_loadbzw4_ur:    return L2_loadbzw4_io;
9060b57cec5SDimitry Andric           case L4_loadbsw2_ap:
9070b57cec5SDimitry Andric           case L4_loadbsw2_ur:    return L2_loadbsw2_io;
9080b57cec5SDimitry Andric           case L4_loadbsw4_ap:
9090b57cec5SDimitry Andric           case L4_loadbsw4_ur:    return L2_loadbsw4_io;
9100b57cec5SDimitry Andric           case L4_loadalignh_ap:
9110b57cec5SDimitry Andric           case L4_loadalignh_ur:  return L2_loadalignh_io;
9120b57cec5SDimitry Andric           case L4_loadalignb_ap:
9130b57cec5SDimitry Andric           case L4_loadalignb_ur:  return L2_loadalignb_io;
9140b57cec5SDimitry Andric           case L4_ploadrubt_abs:  return L2_ploadrubt_io;
9150b57cec5SDimitry Andric           case L4_ploadrubf_abs:  return L2_ploadrubf_io;
9160b57cec5SDimitry Andric           case L4_ploadrbt_abs:   return L2_ploadrbt_io;
9170b57cec5SDimitry Andric           case L4_ploadrbf_abs:   return L2_ploadrbf_io;
9180b57cec5SDimitry Andric           case L4_ploadruht_abs:  return L2_ploadruht_io;
9190b57cec5SDimitry Andric           case L4_ploadruhf_abs:  return L2_ploadruhf_io;
9200b57cec5SDimitry Andric           case L4_ploadrht_abs:   return L2_ploadrht_io;
9210b57cec5SDimitry Andric           case L4_ploadrhf_abs:   return L2_ploadrhf_io;
9220b57cec5SDimitry Andric           case L4_ploadrit_abs:   return L2_ploadrit_io;
9230b57cec5SDimitry Andric           case L4_ploadrif_abs:   return L2_ploadrif_io;
9240b57cec5SDimitry Andric           case L4_ploadrdt_abs:   return L2_ploadrdt_io;
9250b57cec5SDimitry Andric           case L4_ploadrdf_abs:   return L2_ploadrdf_io;
9260b57cec5SDimitry Andric           case PS_storerbabs:
9270b57cec5SDimitry Andric           case S4_storerb_ap:
9280b57cec5SDimitry Andric           case S4_storerb_ur:     return S2_storerb_io;
9290b57cec5SDimitry Andric           case PS_storerhabs:
9300b57cec5SDimitry Andric           case S4_storerh_ap:
9310b57cec5SDimitry Andric           case S4_storerh_ur:     return S2_storerh_io;
9320b57cec5SDimitry Andric           case PS_storerfabs:
9330b57cec5SDimitry Andric           case S4_storerf_ap:
9340b57cec5SDimitry Andric           case S4_storerf_ur:     return S2_storerf_io;
9350b57cec5SDimitry Andric           case PS_storeriabs:
9360b57cec5SDimitry Andric           case S4_storeri_ap:
9370b57cec5SDimitry Andric           case S4_storeri_ur:     return S2_storeri_io;
9380b57cec5SDimitry Andric           case PS_storerdabs:
9390b57cec5SDimitry Andric           case S4_storerd_ap:
9400b57cec5SDimitry Andric           case S4_storerd_ur:     return S2_storerd_io;
9410b57cec5SDimitry Andric           case S4_pstorerbt_abs:  return S2_pstorerbt_io;
9420b57cec5SDimitry Andric           case S4_pstorerbf_abs:  return S2_pstorerbf_io;
9430b57cec5SDimitry Andric           case S4_pstorerht_abs:  return S2_pstorerht_io;
9440b57cec5SDimitry Andric           case S4_pstorerhf_abs:  return S2_pstorerhf_io;
9450b57cec5SDimitry Andric           case S4_pstorerft_abs:  return S2_pstorerft_io;
9460b57cec5SDimitry Andric           case S4_pstorerff_abs:  return S2_pstorerff_io;
9470b57cec5SDimitry Andric           case S4_pstorerit_abs:  return S2_pstorerit_io;
9480b57cec5SDimitry Andric           case S4_pstorerif_abs:  return S2_pstorerif_io;
9490b57cec5SDimitry Andric           case S4_pstorerdt_abs:  return S2_pstorerdt_io;
9500b57cec5SDimitry Andric           case S4_pstorerdf_abs:  return S2_pstorerdf_io;
9510b57cec5SDimitry Andric           default:
9520b57cec5SDimitry Andric             break;
9530b57cec5SDimitry Andric         }
9540b57cec5SDimitry Andric         break;
9550b57cec5SDimitry Andric       case HexagonII::BaseImmOffset:
9560b57cec5SDimitry Andric         if (!isStoreImmediate(ExtOpc))
9570b57cec5SDimitry Andric           return ExtOpc;
9580b57cec5SDimitry Andric         break;
9590b57cec5SDimitry Andric       default:
9600b57cec5SDimitry Andric         break;
9610b57cec5SDimitry Andric     }
9620b57cec5SDimitry Andric   }
9630b57cec5SDimitry Andric   return 0;
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric 
9660b57cec5SDimitry Andric unsigned HCE::getDirectRegReplacement(unsigned ExtOpc) const {
9670b57cec5SDimitry Andric   switch (ExtOpc) {
9680b57cec5SDimitry Andric     case Hexagon::A2_addi:          return Hexagon::A2_add;
9690b57cec5SDimitry Andric     case Hexagon::A2_andir:         return Hexagon::A2_and;
9700b57cec5SDimitry Andric     case Hexagon::A2_combineii:     return Hexagon::A4_combineri;
9710b57cec5SDimitry Andric     case Hexagon::A2_orir:          return Hexagon::A2_or;
9720b57cec5SDimitry Andric     case Hexagon::A2_paddif:        return Hexagon::A2_paddf;
9730b57cec5SDimitry Andric     case Hexagon::A2_paddit:        return Hexagon::A2_paddt;
9740b57cec5SDimitry Andric     case Hexagon::A2_subri:         return Hexagon::A2_sub;
9750b57cec5SDimitry Andric     case Hexagon::A2_tfrsi:         return TargetOpcode::COPY;
9760b57cec5SDimitry Andric     case Hexagon::A4_cmpbeqi:       return Hexagon::A4_cmpbeq;
9770b57cec5SDimitry Andric     case Hexagon::A4_cmpbgti:       return Hexagon::A4_cmpbgt;
9780b57cec5SDimitry Andric     case Hexagon::A4_cmpbgtui:      return Hexagon::A4_cmpbgtu;
9790b57cec5SDimitry Andric     case Hexagon::A4_cmpheqi:       return Hexagon::A4_cmpheq;
9800b57cec5SDimitry Andric     case Hexagon::A4_cmphgti:       return Hexagon::A4_cmphgt;
9810b57cec5SDimitry Andric     case Hexagon::A4_cmphgtui:      return Hexagon::A4_cmphgtu;
9820b57cec5SDimitry Andric     case Hexagon::A4_combineii:     return Hexagon::A4_combineir;
9830b57cec5SDimitry Andric     case Hexagon::A4_combineir:     return TargetOpcode::REG_SEQUENCE;
9840b57cec5SDimitry Andric     case Hexagon::A4_combineri:     return TargetOpcode::REG_SEQUENCE;
9850b57cec5SDimitry Andric     case Hexagon::A4_rcmpeqi:       return Hexagon::A4_rcmpeq;
9860b57cec5SDimitry Andric     case Hexagon::A4_rcmpneqi:      return Hexagon::A4_rcmpneq;
9870b57cec5SDimitry Andric     case Hexagon::C2_cmoveif:       return Hexagon::A2_tfrpf;
9880b57cec5SDimitry Andric     case Hexagon::C2_cmoveit:       return Hexagon::A2_tfrpt;
9890b57cec5SDimitry Andric     case Hexagon::C2_cmpeqi:        return Hexagon::C2_cmpeq;
9900b57cec5SDimitry Andric     case Hexagon::C2_cmpgti:        return Hexagon::C2_cmpgt;
9910b57cec5SDimitry Andric     case Hexagon::C2_cmpgtui:       return Hexagon::C2_cmpgtu;
9920b57cec5SDimitry Andric     case Hexagon::C2_muxii:         return Hexagon::C2_muxir;
9930b57cec5SDimitry Andric     case Hexagon::C2_muxir:         return Hexagon::C2_mux;
9940b57cec5SDimitry Andric     case Hexagon::C2_muxri:         return Hexagon::C2_mux;
9950b57cec5SDimitry Andric     case Hexagon::C4_cmpltei:       return Hexagon::C4_cmplte;
9960b57cec5SDimitry Andric     case Hexagon::C4_cmplteui:      return Hexagon::C4_cmplteu;
9970b57cec5SDimitry Andric     case Hexagon::C4_cmpneqi:       return Hexagon::C4_cmpneq;
9980b57cec5SDimitry Andric     case Hexagon::M2_accii:         return Hexagon::M2_acci;        // T -> T
9990b57cec5SDimitry Andric     /* No M2_macsin */
10000b57cec5SDimitry Andric     case Hexagon::M2_macsip:        return Hexagon::M2_maci;        // T -> T
10010b57cec5SDimitry Andric     case Hexagon::M2_mpysin:        return Hexagon::M2_mpyi;
10020b57cec5SDimitry Andric     case Hexagon::M2_mpysip:        return Hexagon::M2_mpyi;
10030b57cec5SDimitry Andric     case Hexagon::M2_mpysmi:        return Hexagon::M2_mpyi;
10040b57cec5SDimitry Andric     case Hexagon::M2_naccii:        return Hexagon::M2_nacci;       // T -> T
10050b57cec5SDimitry Andric     case Hexagon::M4_mpyri_addi:    return Hexagon::M4_mpyri_addr;
10060b57cec5SDimitry Andric     case Hexagon::M4_mpyri_addr:    return Hexagon::M4_mpyrr_addr;  // _ -> T
10070b57cec5SDimitry Andric     case Hexagon::M4_mpyrr_addi:    return Hexagon::M4_mpyrr_addr;  // _ -> T
10080b57cec5SDimitry Andric     case Hexagon::S4_addaddi:       return Hexagon::M2_acci;        // _ -> T
10090b57cec5SDimitry Andric     case Hexagon::S4_addi_asl_ri:   return Hexagon::S2_asl_i_r_acc; // T -> T
10100b57cec5SDimitry Andric     case Hexagon::S4_addi_lsr_ri:   return Hexagon::S2_lsr_i_r_acc; // T -> T
10110b57cec5SDimitry Andric     case Hexagon::S4_andi_asl_ri:   return Hexagon::S2_asl_i_r_and; // T -> T
10120b57cec5SDimitry Andric     case Hexagon::S4_andi_lsr_ri:   return Hexagon::S2_lsr_i_r_and; // T -> T
10130b57cec5SDimitry Andric     case Hexagon::S4_ori_asl_ri:    return Hexagon::S2_asl_i_r_or;  // T -> T
10140b57cec5SDimitry Andric     case Hexagon::S4_ori_lsr_ri:    return Hexagon::S2_lsr_i_r_or;  // T -> T
10150b57cec5SDimitry Andric     case Hexagon::S4_subaddi:       return Hexagon::M2_subacc;      // _ -> T
10160b57cec5SDimitry Andric     case Hexagon::S4_subi_asl_ri:   return Hexagon::S2_asl_i_r_nac; // T -> T
10170b57cec5SDimitry Andric     case Hexagon::S4_subi_lsr_ri:   return Hexagon::S2_lsr_i_r_nac; // T -> T
10180b57cec5SDimitry Andric 
10190b57cec5SDimitry Andric     // Store-immediates:
10200b57cec5SDimitry Andric     case Hexagon::S4_storeirbf_io:  return Hexagon::S2_pstorerbf_io;
10210b57cec5SDimitry Andric     case Hexagon::S4_storeirb_io:   return Hexagon::S2_storerb_io;
10220b57cec5SDimitry Andric     case Hexagon::S4_storeirbt_io:  return Hexagon::S2_pstorerbt_io;
10230b57cec5SDimitry Andric     case Hexagon::S4_storeirhf_io:  return Hexagon::S2_pstorerhf_io;
10240b57cec5SDimitry Andric     case Hexagon::S4_storeirh_io:   return Hexagon::S2_storerh_io;
10250b57cec5SDimitry Andric     case Hexagon::S4_storeirht_io:  return Hexagon::S2_pstorerht_io;
10260b57cec5SDimitry Andric     case Hexagon::S4_storeirif_io:  return Hexagon::S2_pstorerif_io;
10270b57cec5SDimitry Andric     case Hexagon::S4_storeiri_io:   return Hexagon::S2_storeri_io;
10280b57cec5SDimitry Andric     case Hexagon::S4_storeirit_io:  return Hexagon::S2_pstorerit_io;
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric     default:
10310b57cec5SDimitry Andric       break;
10320b57cec5SDimitry Andric   }
10330b57cec5SDimitry Andric   return 0;
10340b57cec5SDimitry Andric }
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric // Return the allowable deviation from the current value of Rb (i.e. the
10370b57cec5SDimitry Andric // range of values that can be added to the current value) which the
10380b57cec5SDimitry Andric // instruction MI can accommodate.
10390b57cec5SDimitry Andric // The instruction MI is a user of register Rb, which is defined via an
10400b57cec5SDimitry Andric // extender. It may be possible for MI to be tweaked to work for a register
10410b57cec5SDimitry Andric // defined with a slightly different value. For example
10420b57cec5SDimitry Andric //   ... = L2_loadrub_io Rb, 1
10430b57cec5SDimitry Andric // can be modifed to be
10440b57cec5SDimitry Andric //   ... = L2_loadrub_io Rb', 0
10450b57cec5SDimitry Andric // if Rb' = Rb+1.
10460b57cec5SDimitry Andric // The range for Rb would be [Min+1, Max+1], where [Min, Max] is a range
10470b57cec5SDimitry Andric // for L2_loadrub with offset 0. That means that Rb could be replaced with
10480b57cec5SDimitry Andric // Rc, where Rc-Rb belongs to [Min+1, Max+1].
10490b57cec5SDimitry Andric OffsetRange HCE::getOffsetRange(Register Rb, const MachineInstr &MI) const {
10500b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
10510b57cec5SDimitry Andric   // Instructions that are constant-extended may be replaced with something
10520b57cec5SDimitry Andric   // else that no longer offers the same range as the original.
10530b57cec5SDimitry Andric   if (!isRegOffOpcode(Opc) || HII->isConstExtended(MI))
10540b57cec5SDimitry Andric     return OffsetRange::zero();
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric   if (Opc == Hexagon::A2_addi) {
10570b57cec5SDimitry Andric     const MachineOperand &Op1 = MI.getOperand(1), &Op2 = MI.getOperand(2);
10580b57cec5SDimitry Andric     if (Rb != Register(Op1) || !Op2.isImm())
10590b57cec5SDimitry Andric       return OffsetRange::zero();
10600b57cec5SDimitry Andric     OffsetRange R = { -(1<<15)+1, (1<<15)-1, 1 };
10610b57cec5SDimitry Andric     return R.shift(Op2.getImm());
10620b57cec5SDimitry Andric   }
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric   // HII::getBaseAndOffsetPosition returns the increment position as "offset".
10650b57cec5SDimitry Andric   if (HII->isPostIncrement(MI))
10660b57cec5SDimitry Andric     return OffsetRange::zero();
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric   const MCInstrDesc &D = HII->get(Opc);
10690b57cec5SDimitry Andric   assert(D.mayLoad() || D.mayStore());
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric   unsigned BaseP, OffP;
10720b57cec5SDimitry Andric   if (!HII->getBaseAndOffsetPosition(MI, BaseP, OffP) ||
10730b57cec5SDimitry Andric       Rb != Register(MI.getOperand(BaseP)) ||
10740b57cec5SDimitry Andric       !MI.getOperand(OffP).isImm())
10750b57cec5SDimitry Andric     return OffsetRange::zero();
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric   uint64_t F = (D.TSFlags >> HexagonII::MemAccessSizePos) &
10780b57cec5SDimitry Andric                   HexagonII::MemAccesSizeMask;
10790b57cec5SDimitry Andric   uint8_t A = HexagonII::getMemAccessSizeInBytes(HexagonII::MemAccessSize(F));
10800b57cec5SDimitry Andric   unsigned L = Log2_32(A);
10810b57cec5SDimitry Andric   unsigned S = 10+L;  // sint11_L
10820b57cec5SDimitry Andric   int32_t Min = -alignDown((1<<S)-1, A);
10830b57cec5SDimitry Andric 
10840b57cec5SDimitry Andric   // The range will be shifted by Off. To prefer non-negative offsets,
10850b57cec5SDimitry Andric   // adjust Max accordingly.
10860b57cec5SDimitry Andric   int32_t Off = MI.getOperand(OffP).getImm();
10870b57cec5SDimitry Andric   int32_t Max = Off >= 0 ? 0 : -Off;
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric   OffsetRange R = { Min, Max, A };
10900b57cec5SDimitry Andric   return R.shift(Off);
10910b57cec5SDimitry Andric }
10920b57cec5SDimitry Andric 
10930b57cec5SDimitry Andric // Return the allowable deviation from the current value of the extender ED,
10940b57cec5SDimitry Andric // for which the instruction corresponding to ED can be modified without
10950b57cec5SDimitry Andric // using an extender.
10960b57cec5SDimitry Andric // The instruction uses the extender directly. It will be replaced with
10970b57cec5SDimitry Andric // another instruction, say MJ, where the extender will be replaced with a
10980b57cec5SDimitry Andric // register. MJ can allow some variability with respect to the value of
10990b57cec5SDimitry Andric // that register, as is the case with indexed memory instructions.
11000b57cec5SDimitry Andric OffsetRange HCE::getOffsetRange(const ExtDesc &ED) const {
11010b57cec5SDimitry Andric   // The only way that there can be a non-zero range available is if
11020b57cec5SDimitry Andric   // the instruction using ED will be converted to an indexed memory
11030b57cec5SDimitry Andric   // instruction.
11040b57cec5SDimitry Andric   unsigned IdxOpc = getRegOffOpcode(ED.UseMI->getOpcode());
11050b57cec5SDimitry Andric   switch (IdxOpc) {
11060b57cec5SDimitry Andric     case 0:
11070b57cec5SDimitry Andric       return OffsetRange::zero();
11080b57cec5SDimitry Andric     case Hexagon::A2_addi:    // s16
11090b57cec5SDimitry Andric       return { -32767, 32767, 1 };
11100b57cec5SDimitry Andric     case Hexagon::A2_subri:   // s10
11110b57cec5SDimitry Andric       return { -511, 511, 1 };
11120b57cec5SDimitry Andric   }
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric   if (!ED.UseMI->mayLoad() && !ED.UseMI->mayStore())
11150b57cec5SDimitry Andric     return OffsetRange::zero();
11160b57cec5SDimitry Andric   const MCInstrDesc &D = HII->get(IdxOpc);
11170b57cec5SDimitry Andric   uint64_t F = (D.TSFlags >> HexagonII::MemAccessSizePos) &
11180b57cec5SDimitry Andric                   HexagonII::MemAccesSizeMask;
11190b57cec5SDimitry Andric   uint8_t A = HexagonII::getMemAccessSizeInBytes(HexagonII::MemAccessSize(F));
11200b57cec5SDimitry Andric   unsigned L = Log2_32(A);
11210b57cec5SDimitry Andric   unsigned S = 10+L;  // sint11_L
11220b57cec5SDimitry Andric   int32_t Min = -alignDown((1<<S)-1, A);
11230b57cec5SDimitry Andric   int32_t Max = 0;  // Force non-negative offsets.
11240b57cec5SDimitry Andric   return { Min, Max, A };
11250b57cec5SDimitry Andric }
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric // Get the allowable deviation from the current value of Rd by checking
11280b57cec5SDimitry Andric // all uses of Rd.
11290b57cec5SDimitry Andric OffsetRange HCE::getOffsetRange(Register Rd) const {
11300b57cec5SDimitry Andric   OffsetRange Range;
11310b57cec5SDimitry Andric   for (const MachineOperand &Op : MRI->use_operands(Rd.Reg)) {
11320b57cec5SDimitry Andric     // Make sure that the register being used by this operand is identical
11330b57cec5SDimitry Andric     // to the register that was defined: using a different subregister
11340b57cec5SDimitry Andric     // precludes any non-trivial range.
11350b57cec5SDimitry Andric     if (Rd != Register(Op))
11360b57cec5SDimitry Andric       return OffsetRange::zero();
11370b57cec5SDimitry Andric     Range.intersect(getOffsetRange(Rd, *Op.getParent()));
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric   return Range;
11400b57cec5SDimitry Andric }
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric void HCE::recordExtender(MachineInstr &MI, unsigned OpNum) {
11430b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
11440b57cec5SDimitry Andric   ExtDesc ED;
11450b57cec5SDimitry Andric   ED.OpNum = OpNum;
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric   bool IsLoad = MI.mayLoad();
11480b57cec5SDimitry Andric   bool IsStore = MI.mayStore();
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric   // Fixed stack slots have negative indexes, and they cannot be used
11510b57cec5SDimitry Andric   // with TRI::stackSlot2Index and TRI::index2StackSlot. This is somewhat
11520b57cec5SDimitry Andric   // unfortunate, but should not be a frequent thing.
11530b57cec5SDimitry Andric   for (MachineOperand &Op : MI.operands())
11540b57cec5SDimitry Andric     if (Op.isFI() && Op.getIndex() < 0)
11550b57cec5SDimitry Andric       return;
11560b57cec5SDimitry Andric 
11570b57cec5SDimitry Andric   if (IsLoad || IsStore) {
11580b57cec5SDimitry Andric     unsigned AM = HII->getAddrMode(MI);
11590b57cec5SDimitry Andric     switch (AM) {
11600b57cec5SDimitry Andric       // (Re: ##Off + Rb<<S) = Rd: ##Val
11610b57cec5SDimitry Andric       case HexagonII::Absolute:       // (__: ## + __<<_)
11620b57cec5SDimitry Andric         break;
11630b57cec5SDimitry Andric       case HexagonII::AbsoluteSet:    // (Rd: ## + __<<_)
11640b57cec5SDimitry Andric         ED.Rd = MI.getOperand(OpNum-1);
11650b57cec5SDimitry Andric         ED.IsDef = true;
11660b57cec5SDimitry Andric         break;
11670b57cec5SDimitry Andric       case HexagonII::BaseImmOffset:  // (__: ## + Rs<<0)
11680b57cec5SDimitry Andric         // Store-immediates are treated as non-memory operations, since
11690b57cec5SDimitry Andric         // it's the value being stored that is extended (as opposed to
11700b57cec5SDimitry Andric         // a part of the address).
11710b57cec5SDimitry Andric         if (!isStoreImmediate(Opc))
11720b57cec5SDimitry Andric           ED.Expr.Rs = MI.getOperand(OpNum-1);
11730b57cec5SDimitry Andric         break;
11740b57cec5SDimitry Andric       case HexagonII::BaseLongOffset: // (__: ## + Rs<<S)
11750b57cec5SDimitry Andric         ED.Expr.Rs = MI.getOperand(OpNum-2);
11760b57cec5SDimitry Andric         ED.Expr.S = MI.getOperand(OpNum-1).getImm();
11770b57cec5SDimitry Andric         break;
11780b57cec5SDimitry Andric       default:
11790b57cec5SDimitry Andric         llvm_unreachable("Unhandled memory instruction");
11800b57cec5SDimitry Andric     }
11810b57cec5SDimitry Andric   } else {
11820b57cec5SDimitry Andric     switch (Opc) {
11830b57cec5SDimitry Andric       case Hexagon::A2_tfrsi:         // (Rd: ## + __<<_)
11840b57cec5SDimitry Andric         ED.Rd = MI.getOperand(0);
11850b57cec5SDimitry Andric         ED.IsDef = true;
11860b57cec5SDimitry Andric         break;
11870b57cec5SDimitry Andric       case Hexagon::A2_combineii:     // (Rd: ## + __<<_)
11880b57cec5SDimitry Andric       case Hexagon::A4_combineir:
11890b57cec5SDimitry Andric         ED.Rd = { MI.getOperand(0).getReg(), Hexagon::isub_hi };
11900b57cec5SDimitry Andric         ED.IsDef = true;
11910b57cec5SDimitry Andric         break;
11920b57cec5SDimitry Andric       case Hexagon::A4_combineri:     // (Rd: ## + __<<_)
11930b57cec5SDimitry Andric         ED.Rd = { MI.getOperand(0).getReg(), Hexagon::isub_lo };
11940b57cec5SDimitry Andric         ED.IsDef = true;
11950b57cec5SDimitry Andric         break;
11960b57cec5SDimitry Andric       case Hexagon::A2_addi:          // (Rd: ## + Rs<<0)
11970b57cec5SDimitry Andric         ED.Rd = MI.getOperand(0);
11980b57cec5SDimitry Andric         ED.Expr.Rs = MI.getOperand(OpNum-1);
11990b57cec5SDimitry Andric         break;
12000b57cec5SDimitry Andric       case Hexagon::M2_accii:         // (__: ## + Rs<<0)
12010b57cec5SDimitry Andric       case Hexagon::M2_naccii:
12020b57cec5SDimitry Andric       case Hexagon::S4_addaddi:
12030b57cec5SDimitry Andric         ED.Expr.Rs = MI.getOperand(OpNum-1);
12040b57cec5SDimitry Andric         break;
12050b57cec5SDimitry Andric       case Hexagon::A2_subri:         // (Rd: ## - Rs<<0)
12060b57cec5SDimitry Andric         ED.Rd = MI.getOperand(0);
12070b57cec5SDimitry Andric         ED.Expr.Rs = MI.getOperand(OpNum+1);
12080b57cec5SDimitry Andric         ED.Expr.Neg = true;
12090b57cec5SDimitry Andric         break;
12100b57cec5SDimitry Andric       case Hexagon::S4_subaddi:       // (__: ## - Rs<<0)
12110b57cec5SDimitry Andric         ED.Expr.Rs = MI.getOperand(OpNum+1);
12120b57cec5SDimitry Andric         ED.Expr.Neg = true;
12130b57cec5SDimitry Andric         break;
12140b57cec5SDimitry Andric       default:                        // (__: ## + __<<_)
12150b57cec5SDimitry Andric         break;
12160b57cec5SDimitry Andric     }
12170b57cec5SDimitry Andric   }
12180b57cec5SDimitry Andric 
12190b57cec5SDimitry Andric   ED.UseMI = &MI;
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric   // Ignore unnamed globals.
12220b57cec5SDimitry Andric   ExtRoot ER(ED.getOp());
12230b57cec5SDimitry Andric   if (ER.Kind == MachineOperand::MO_GlobalAddress)
12240b57cec5SDimitry Andric     if (ER.V.GV->getName().empty())
12250b57cec5SDimitry Andric       return;
1226*62987288SDimitry Andric   // Ignore block address that points to block in another function
1227*62987288SDimitry Andric   if (ER.Kind == MachineOperand::MO_BlockAddress)
1228*62987288SDimitry Andric     if (ER.V.BA->getFunction() != &(MI.getMF()->getFunction()))
1229*62987288SDimitry Andric       return;
12300b57cec5SDimitry Andric   Extenders.push_back(ED);
12310b57cec5SDimitry Andric }
12320b57cec5SDimitry Andric 
12330b57cec5SDimitry Andric void HCE::collectInstr(MachineInstr &MI) {
12340b57cec5SDimitry Andric   if (!HII->isConstExtended(MI))
12350b57cec5SDimitry Andric     return;
12360b57cec5SDimitry Andric 
12370b57cec5SDimitry Andric   // Skip some non-convertible instructions.
12380b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
12390b57cec5SDimitry Andric   switch (Opc) {
12400b57cec5SDimitry Andric     case Hexagon::M2_macsin:  // There is no Rx -= mpyi(Rs,Rt).
12410b57cec5SDimitry Andric     case Hexagon::C4_addipc:
12420b57cec5SDimitry Andric     case Hexagon::S4_or_andi:
12430b57cec5SDimitry Andric     case Hexagon::S4_or_andix:
12440b57cec5SDimitry Andric     case Hexagon::S4_or_ori:
12450b57cec5SDimitry Andric       return;
12460b57cec5SDimitry Andric   }
12470b57cec5SDimitry Andric   recordExtender(MI, HII->getCExtOpNum(MI));
12480b57cec5SDimitry Andric }
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric void HCE::collect(MachineFunction &MF) {
12510b57cec5SDimitry Andric   Extenders.clear();
12520b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
12530b57cec5SDimitry Andric     // Skip unreachable blocks.
12540b57cec5SDimitry Andric     if (MBB.getNumber() == -1)
12550b57cec5SDimitry Andric       continue;
12560b57cec5SDimitry Andric     for (MachineInstr &MI : MBB)
12570b57cec5SDimitry Andric       collectInstr(MI);
12580b57cec5SDimitry Andric   }
12590b57cec5SDimitry Andric }
12600b57cec5SDimitry Andric 
12610b57cec5SDimitry Andric void HCE::assignInits(const ExtRoot &ER, unsigned Begin, unsigned End,
12620b57cec5SDimitry Andric       AssignmentMap &IMap) {
12634824e7fdSDimitry Andric   // Basic correctness: make sure that all extenders in the range [Begin..End)
12640b57cec5SDimitry Andric   // share the same root ER.
12650b57cec5SDimitry Andric   for (unsigned I = Begin; I != End; ++I)
12660b57cec5SDimitry Andric     assert(ER == ExtRoot(Extenders[I].getOp()));
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric   // Construct the list of ranges, such that for each P in Ranges[I],
12690b57cec5SDimitry Andric   // a register Reg = ER+P can be used in place of Extender[I]. If the
12700b57cec5SDimitry Andric   // instruction allows, uses in the form of Reg+Off are considered
12710b57cec5SDimitry Andric   // (here, Off = required_value - P).
12720b57cec5SDimitry Andric   std::vector<OffsetRange> Ranges(End-Begin);
12730b57cec5SDimitry Andric 
12740b57cec5SDimitry Andric   // For each extender that is a def, visit all uses of the defined register,
12750b57cec5SDimitry Andric   // and produce an offset range that works for all uses. The def doesn't
12760b57cec5SDimitry Andric   // have to be checked, because it can become dead if all uses can be updated
12770b57cec5SDimitry Andric   // to use a different reg/offset.
12780b57cec5SDimitry Andric   for (unsigned I = Begin; I != End; ++I) {
12790b57cec5SDimitry Andric     const ExtDesc &ED = Extenders[I];
12800b57cec5SDimitry Andric     if (!ED.IsDef)
12810b57cec5SDimitry Andric       continue;
12820b57cec5SDimitry Andric     ExtValue EV(ED);
12830b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << " =" << I << ". " << EV << "  " << ED << '\n');
12840b57cec5SDimitry Andric     assert(ED.Rd.Reg != 0);
12850b57cec5SDimitry Andric     Ranges[I-Begin] = getOffsetRange(ED.Rd).shift(EV.Offset);
12860b57cec5SDimitry Andric     // A2_tfrsi is a special case: it will be replaced with A2_addi, which
12870b57cec5SDimitry Andric     // has a 16-bit signed offset. This means that A2_tfrsi not only has a
12880b57cec5SDimitry Andric     // range coming from its uses, but also from the fact that its replacement
12890b57cec5SDimitry Andric     // has a range as well.
12900b57cec5SDimitry Andric     if (ED.UseMI->getOpcode() == Hexagon::A2_tfrsi) {
12910b57cec5SDimitry Andric       int32_t D = alignDown(32767, Ranges[I-Begin].Align); // XXX hardcoded
12920b57cec5SDimitry Andric       Ranges[I-Begin].extendBy(-D).extendBy(D);
12930b57cec5SDimitry Andric     }
12940b57cec5SDimitry Andric   }
12950b57cec5SDimitry Andric 
12960b57cec5SDimitry Andric   // Visit all non-def extenders. For each one, determine the offset range
12970b57cec5SDimitry Andric   // available for it.
12980b57cec5SDimitry Andric   for (unsigned I = Begin; I != End; ++I) {
12990b57cec5SDimitry Andric     const ExtDesc &ED = Extenders[I];
13000b57cec5SDimitry Andric     if (ED.IsDef)
13010b57cec5SDimitry Andric       continue;
13020b57cec5SDimitry Andric     ExtValue EV(ED);
13030b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << I << ". " << EV << "  " << ED << '\n');
13040b57cec5SDimitry Andric     OffsetRange Dev = getOffsetRange(ED);
13050b57cec5SDimitry Andric     Ranges[I-Begin].intersect(Dev.shift(EV.Offset));
13060b57cec5SDimitry Andric   }
13070b57cec5SDimitry Andric 
13080b57cec5SDimitry Andric   // Here for each I there is a corresponding Range[I]. Construct the
13090b57cec5SDimitry Andric   // inverse map, that to each range will assign the set of indexes in
13100b57cec5SDimitry Andric   // [Begin..End) that this range corresponds to.
13110b57cec5SDimitry Andric   std::map<OffsetRange, IndexList> RangeMap;
13120b57cec5SDimitry Andric   for (unsigned I = Begin; I != End; ++I)
13130b57cec5SDimitry Andric     RangeMap[Ranges[I-Begin]].insert(I);
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric   LLVM_DEBUG({
13160b57cec5SDimitry Andric     dbgs() << "Ranges\n";
13170b57cec5SDimitry Andric     for (unsigned I = Begin; I != End; ++I)
13180b57cec5SDimitry Andric       dbgs() << "  " << I << ". " << Ranges[I-Begin] << '\n';
13190b57cec5SDimitry Andric     dbgs() << "RangeMap\n";
13200b57cec5SDimitry Andric     for (auto &P : RangeMap) {
13210b57cec5SDimitry Andric       dbgs() << "  " << P.first << " ->";
13220b57cec5SDimitry Andric       for (unsigned I : P.second)
13230b57cec5SDimitry Andric         dbgs() << ' ' << I;
13240b57cec5SDimitry Andric       dbgs() << '\n';
13250b57cec5SDimitry Andric     }
13260b57cec5SDimitry Andric   });
13270b57cec5SDimitry Andric 
13280b57cec5SDimitry Andric   // Select the definition points, and generate the assignment between
13290b57cec5SDimitry Andric   // these points and the uses.
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric   // For each candidate offset, keep a pair CandData consisting of
13320b57cec5SDimitry Andric   // the total number of ranges containing that candidate, and the
13330b57cec5SDimitry Andric   // vector of corresponding RangeTree nodes.
13340b57cec5SDimitry Andric   using CandData = std::pair<unsigned, SmallVector<RangeTree::Node*,8>>;
13350b57cec5SDimitry Andric   std::map<int32_t, CandData> CandMap;
13360b57cec5SDimitry Andric 
13370b57cec5SDimitry Andric   RangeTree Tree;
13380b57cec5SDimitry Andric   for (const OffsetRange &R : Ranges)
13390b57cec5SDimitry Andric     Tree.add(R);
13400b57cec5SDimitry Andric   SmallVector<RangeTree::Node*,8> Nodes;
13410b57cec5SDimitry Andric   Tree.order(Nodes);
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric   auto MaxAlign = [](const SmallVectorImpl<RangeTree::Node*> &Nodes,
13440b57cec5SDimitry Andric                      uint8_t Align, uint8_t Offset) {
13450b57cec5SDimitry Andric     for (RangeTree::Node *N : Nodes) {
13460b57cec5SDimitry Andric       if (N->Range.Align <= Align || N->Range.Offset < Offset)
13470b57cec5SDimitry Andric         continue;
13480b57cec5SDimitry Andric       if ((N->Range.Offset - Offset) % Align != 0)
13490b57cec5SDimitry Andric         continue;
13500b57cec5SDimitry Andric       Align = N->Range.Align;
13510b57cec5SDimitry Andric       Offset = N->Range.Offset;
13520b57cec5SDimitry Andric     }
13530b57cec5SDimitry Andric     return std::make_pair(Align, Offset);
13540b57cec5SDimitry Andric   };
13550b57cec5SDimitry Andric 
13560b57cec5SDimitry Andric   // Construct the set of all potential definition points from the endpoints
13570b57cec5SDimitry Andric   // of the ranges. If a given endpoint also belongs to a different range,
13580b57cec5SDimitry Andric   // but with a higher alignment, also consider the more-highly-aligned
13590b57cec5SDimitry Andric   // value of this endpoint.
13600b57cec5SDimitry Andric   std::set<int32_t> CandSet;
13610b57cec5SDimitry Andric   for (RangeTree::Node *N : Nodes) {
13620b57cec5SDimitry Andric     const OffsetRange &R = N->Range;
13630b57cec5SDimitry Andric     auto P0 = MaxAlign(Tree.nodesWith(R.Min, false), R.Align, R.Offset);
13640b57cec5SDimitry Andric     CandSet.insert(R.Min);
13650b57cec5SDimitry Andric     if (R.Align < P0.first)
13660b57cec5SDimitry Andric       CandSet.insert(adjustUp(R.Min, P0.first, P0.second));
13670b57cec5SDimitry Andric     auto P1 = MaxAlign(Tree.nodesWith(R.Max, false), R.Align, R.Offset);
13680b57cec5SDimitry Andric     CandSet.insert(R.Max);
13690b57cec5SDimitry Andric     if (R.Align < P1.first)
13700b57cec5SDimitry Andric       CandSet.insert(adjustDown(R.Max, P1.first, P1.second));
13710b57cec5SDimitry Andric   }
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric   // Build the assignment map: candidate C -> { list of extender indexes }.
13740b57cec5SDimitry Andric   // This has to be done iteratively:
13750b57cec5SDimitry Andric   // - pick the candidate that covers the maximum number of extenders,
13760b57cec5SDimitry Andric   // - add the candidate to the map,
13770b57cec5SDimitry Andric   // - remove the extenders from the pool.
13780b57cec5SDimitry Andric   while (true) {
13790b57cec5SDimitry Andric     using CMap = std::map<int32_t,unsigned>;
13800b57cec5SDimitry Andric     CMap Counts;
13810b57cec5SDimitry Andric     for (auto It = CandSet.begin(), Et = CandSet.end(); It != Et; ) {
13820b57cec5SDimitry Andric       auto &&V = Tree.nodesWith(*It);
13830b57cec5SDimitry Andric       unsigned N = std::accumulate(V.begin(), V.end(), 0u,
13840b57cec5SDimitry Andric                     [](unsigned Acc, const RangeTree::Node *N) {
13850b57cec5SDimitry Andric                       return Acc + N->Count;
13860b57cec5SDimitry Andric                     });
13870b57cec5SDimitry Andric       if (N != 0)
13880b57cec5SDimitry Andric         Counts.insert({*It, N});
13890b57cec5SDimitry Andric       It = (N != 0) ? std::next(It) : CandSet.erase(It);
13900b57cec5SDimitry Andric     }
13910b57cec5SDimitry Andric     if (Counts.empty())
13920b57cec5SDimitry Andric       break;
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric     // Find the best candidate with respect to the number of extenders covered.
13950fca6ea1SDimitry Andric     auto BestIt = llvm::max_element(
13960fca6ea1SDimitry Andric         Counts, [](const CMap::value_type &A, const CMap::value_type &B) {
13970fca6ea1SDimitry Andric           return A.second < B.second || (A.second == B.second && A < B);
13980b57cec5SDimitry Andric         });
13990b57cec5SDimitry Andric     int32_t Best = BestIt->first;
14000b57cec5SDimitry Andric     ExtValue BestV(ER, Best);
14010b57cec5SDimitry Andric     for (RangeTree::Node *N : Tree.nodesWith(Best)) {
14020b57cec5SDimitry Andric       for (unsigned I : RangeMap[N->Range])
14030b57cec5SDimitry Andric         IMap[{BestV,Extenders[I].Expr}].insert(I);
14040b57cec5SDimitry Andric       Tree.erase(N);
14050b57cec5SDimitry Andric     }
14060b57cec5SDimitry Andric   }
14070b57cec5SDimitry Andric 
14080b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "IMap (before fixup) = " << PrintIMap(IMap, *HRI));
14090b57cec5SDimitry Andric 
14100b57cec5SDimitry Andric   // There is some ambiguity in what initializer should be used, if the
14110b57cec5SDimitry Andric   // descriptor's subexpression is non-trivial: it can be the entire
14120b57cec5SDimitry Andric   // subexpression (which is what has been done so far), or it can be
14130b57cec5SDimitry Andric   // the extender's value itself, if all corresponding extenders have the
14140b57cec5SDimitry Andric   // exact value of the initializer (i.e. require offset of 0).
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric   // To reduce the number of initializers, merge such special cases.
14170b57cec5SDimitry Andric   for (std::pair<const ExtenderInit,IndexList> &P : IMap) {
14180b57cec5SDimitry Andric     // Skip trivial initializers.
14190b57cec5SDimitry Andric     if (P.first.second.trivial())
14200b57cec5SDimitry Andric       continue;
14210b57cec5SDimitry Andric     // If the corresponding trivial initializer does not exist, skip this
14220b57cec5SDimitry Andric     // entry.
14230b57cec5SDimitry Andric     const ExtValue &EV = P.first.first;
14240b57cec5SDimitry Andric     AssignmentMap::iterator F = IMap.find({EV, ExtExpr()});
14250b57cec5SDimitry Andric     if (F == IMap.end())
14260b57cec5SDimitry Andric       continue;
14270b57cec5SDimitry Andric 
14280b57cec5SDimitry Andric     // Finally, check if all extenders have the same value as the initializer.
14290b57cec5SDimitry Andric     // Make sure that extenders that are a part of a stack address are not
14300b57cec5SDimitry Andric     // merged with those that aren't. Stack addresses need an offset field
14310b57cec5SDimitry Andric     // (to be used by frame index elimination), while non-stack expressions
14320b57cec5SDimitry Andric     // can be replaced with forms (such as rr) that do not have such a field.
14330b57cec5SDimitry Andric     // Example:
14340b57cec5SDimitry Andric     //
14350b57cec5SDimitry Andric     // Collected 3 extenders
14360b57cec5SDimitry Andric     //  =2. imm:0  off:32968  bb#2: %7 = ## + __ << 0, def
14370b57cec5SDimitry Andric     //   0. imm:0  off:267  bb#0: __ = ## + SS#1 << 0
14380b57cec5SDimitry Andric     //   1. imm:0  off:267  bb#1: __ = ## + SS#1 << 0
14390b57cec5SDimitry Andric     // Ranges
14400b57cec5SDimitry Andric     //   0. [-756,267]a1+0
14410b57cec5SDimitry Andric     //   1. [-756,267]a1+0
14420b57cec5SDimitry Andric     //   2. [201,65735]a1+0
14430b57cec5SDimitry Andric     // RangeMap
14440b57cec5SDimitry Andric     //   [-756,267]a1+0 -> 0 1
14450b57cec5SDimitry Andric     //   [201,65735]a1+0 -> 2
14460b57cec5SDimitry Andric     // IMap (before fixup) = {
14470b57cec5SDimitry Andric     //   [imm:0  off:267, ## + __ << 0] -> { 2 }
14480b57cec5SDimitry Andric     //   [imm:0  off:267, ## + SS#1 << 0] -> { 0 1 }
14490b57cec5SDimitry Andric     // }
14500b57cec5SDimitry Andric     // IMap (after fixup) = {
14510b57cec5SDimitry Andric     //   [imm:0  off:267, ## + __ << 0] -> { 2 0 1 }
14520b57cec5SDimitry Andric     //   [imm:0  off:267, ## + SS#1 << 0] -> { }
14530b57cec5SDimitry Andric     // }
14540b57cec5SDimitry Andric     // Inserted def in bb#0 for initializer: [imm:0  off:267, ## + __ << 0]
14550b57cec5SDimitry Andric     //   %12:intregs = A2_tfrsi 267
14560b57cec5SDimitry Andric     //
14570b57cec5SDimitry Andric     // The result was
14580b57cec5SDimitry Andric     //   %12:intregs = A2_tfrsi 267
14590b57cec5SDimitry Andric     //   S4_pstorerbt_rr %3, %12, %stack.1, 0, killed %4
14600b57cec5SDimitry Andric     // Which became
14610b57cec5SDimitry Andric     //   r0 = #267
14620b57cec5SDimitry Andric     //   if (p0.new) memb(r0+r29<<#4) = r2
14630b57cec5SDimitry Andric 
14640b57cec5SDimitry Andric     bool IsStack = any_of(F->second, [this](unsigned I) {
14650b57cec5SDimitry Andric                       return Extenders[I].Expr.Rs.isSlot();
14660b57cec5SDimitry Andric                    });
14670b57cec5SDimitry Andric     auto SameValue = [&EV,this,IsStack](unsigned I) {
14680b57cec5SDimitry Andric       const ExtDesc &ED = Extenders[I];
14690b57cec5SDimitry Andric       return ED.Expr.Rs.isSlot() == IsStack &&
14700b57cec5SDimitry Andric              ExtValue(ED).Offset == EV.Offset;
14710b57cec5SDimitry Andric     };
14720b57cec5SDimitry Andric     if (all_of(P.second, SameValue)) {
14730b57cec5SDimitry Andric       F->second.insert(P.second.begin(), P.second.end());
14740b57cec5SDimitry Andric       P.second.clear();
14750b57cec5SDimitry Andric     }
14760b57cec5SDimitry Andric   }
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "IMap (after fixup) = " << PrintIMap(IMap, *HRI));
14790b57cec5SDimitry Andric }
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric void HCE::calculatePlacement(const ExtenderInit &ExtI, const IndexList &Refs,
14820b57cec5SDimitry Andric       LocDefList &Defs) {
14830b57cec5SDimitry Andric   if (Refs.empty())
14840b57cec5SDimitry Andric     return;
14850b57cec5SDimitry Andric 
14860b57cec5SDimitry Andric   // The placement calculation is somewhat simple right now: it finds a
14870b57cec5SDimitry Andric   // single location for the def that dominates all refs. Since this may
14880b57cec5SDimitry Andric   // place the def far from the uses, producing several locations for
14890b57cec5SDimitry Andric   // defs that collectively dominate all refs could be better.
14900b57cec5SDimitry Andric   // For now only do the single one.
14910b57cec5SDimitry Andric   DenseSet<MachineBasicBlock*> Blocks;
14920b57cec5SDimitry Andric   DenseSet<MachineInstr*> RefMIs;
14930b57cec5SDimitry Andric   const ExtDesc &ED0 = Extenders[Refs[0]];
14940b57cec5SDimitry Andric   MachineBasicBlock *DomB = ED0.UseMI->getParent();
14950b57cec5SDimitry Andric   RefMIs.insert(ED0.UseMI);
14960b57cec5SDimitry Andric   Blocks.insert(DomB);
14970b57cec5SDimitry Andric   for (unsigned i = 1, e = Refs.size(); i != e; ++i) {
14980b57cec5SDimitry Andric     const ExtDesc &ED = Extenders[Refs[i]];
14990b57cec5SDimitry Andric     MachineBasicBlock *MBB = ED.UseMI->getParent();
15000b57cec5SDimitry Andric     RefMIs.insert(ED.UseMI);
15010b57cec5SDimitry Andric     DomB = MDT->findNearestCommonDominator(DomB, MBB);
15020b57cec5SDimitry Andric     Blocks.insert(MBB);
15030b57cec5SDimitry Andric   }
15040b57cec5SDimitry Andric 
15050b57cec5SDimitry Andric #ifndef NDEBUG
15060b57cec5SDimitry Andric   // The block DomB should be dominated by the def of each register used
15070b57cec5SDimitry Andric   // in the initializer.
15080b57cec5SDimitry Andric   Register Rs = ExtI.second.Rs;  // Only one reg allowed now.
15090b57cec5SDimitry Andric   const MachineInstr *DefI = Rs.isVReg() ? MRI->getVRegDef(Rs.Reg) : nullptr;
15100b57cec5SDimitry Andric 
15110b57cec5SDimitry Andric   // This should be guaranteed given that the entire expression is used
15120b57cec5SDimitry Andric   // at each instruction in Refs. Add an assertion just in case.
15130b57cec5SDimitry Andric   assert(!DefI || MDT->dominates(DefI->getParent(), DomB));
15140b57cec5SDimitry Andric #endif
15150b57cec5SDimitry Andric 
15160b57cec5SDimitry Andric   MachineBasicBlock::iterator It;
15170b57cec5SDimitry Andric   if (Blocks.count(DomB)) {
15180b57cec5SDimitry Andric     // Try to find the latest possible location for the def.
15190b57cec5SDimitry Andric     MachineBasicBlock::iterator End = DomB->end();
15200b57cec5SDimitry Andric     for (It = DomB->begin(); It != End; ++It)
15210b57cec5SDimitry Andric       if (RefMIs.count(&*It))
15220b57cec5SDimitry Andric         break;
15230b57cec5SDimitry Andric     assert(It != End && "Should have found a ref in DomB");
15240b57cec5SDimitry Andric   } else {
15250b57cec5SDimitry Andric     // DomB does not contain any refs.
15260b57cec5SDimitry Andric     It = DomB->getFirstTerminator();
15270b57cec5SDimitry Andric   }
15280b57cec5SDimitry Andric   Loc DefLoc(DomB, It);
15290b57cec5SDimitry Andric   Defs.emplace_back(DefLoc, Refs);
15300b57cec5SDimitry Andric }
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric HCE::Register HCE::insertInitializer(Loc DefL, const ExtenderInit &ExtI) {
15338bcb0991SDimitry Andric   llvm::Register DefR = MRI->createVirtualRegister(&Hexagon::IntRegsRegClass);
15340b57cec5SDimitry Andric   MachineBasicBlock &MBB = *DefL.Block;
15350b57cec5SDimitry Andric   MachineBasicBlock::iterator At = DefL.At;
15360b57cec5SDimitry Andric   DebugLoc dl = DefL.Block->findDebugLoc(DefL.At);
15370b57cec5SDimitry Andric   const ExtValue &EV = ExtI.first;
15380b57cec5SDimitry Andric   MachineOperand ExtOp(EV);
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric   const ExtExpr &Ex = ExtI.second;
15410b57cec5SDimitry Andric   const MachineInstr *InitI = nullptr;
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric   if (Ex.Rs.isSlot()) {
15440b57cec5SDimitry Andric     assert(Ex.S == 0 && "Cannot have a shift of a stack slot");
15450b57cec5SDimitry Andric     assert(!Ex.Neg && "Cannot subtract a stack slot");
15460b57cec5SDimitry Andric     // DefR = PS_fi Rb,##EV
15470b57cec5SDimitry Andric     InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::PS_fi), DefR)
15480b57cec5SDimitry Andric               .add(MachineOperand(Ex.Rs))
15490b57cec5SDimitry Andric               .add(ExtOp);
15500b57cec5SDimitry Andric   } else {
15510b57cec5SDimitry Andric     assert((Ex.Rs.Reg == 0 || Ex.Rs.isVReg()) && "Expecting virtual register");
15520b57cec5SDimitry Andric     if (Ex.trivial()) {
15530b57cec5SDimitry Andric       // DefR = ##EV
15540b57cec5SDimitry Andric       InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_tfrsi), DefR)
15550b57cec5SDimitry Andric                 .add(ExtOp);
15560b57cec5SDimitry Andric     } else if (Ex.S == 0) {
15570b57cec5SDimitry Andric       if (Ex.Neg) {
15580b57cec5SDimitry Andric         // DefR = sub(##EV,Rb)
15590b57cec5SDimitry Andric         InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_subri), DefR)
15600b57cec5SDimitry Andric                   .add(ExtOp)
15610b57cec5SDimitry Andric                   .add(MachineOperand(Ex.Rs));
15620b57cec5SDimitry Andric       } else {
15630b57cec5SDimitry Andric         // DefR = add(Rb,##EV)
15640b57cec5SDimitry Andric         InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_addi), DefR)
15650b57cec5SDimitry Andric                   .add(MachineOperand(Ex.Rs))
15660b57cec5SDimitry Andric                   .add(ExtOp);
15670b57cec5SDimitry Andric       }
15680b57cec5SDimitry Andric     } else {
15695ffd83dbSDimitry Andric       if (HST->useCompound()) {
15700b57cec5SDimitry Andric         unsigned NewOpc = Ex.Neg ? Hexagon::S4_subi_asl_ri
15710b57cec5SDimitry Andric                                  : Hexagon::S4_addi_asl_ri;
15720b57cec5SDimitry Andric         // DefR = add(##EV,asl(Rb,S))
15730b57cec5SDimitry Andric         InitI = BuildMI(MBB, At, dl, HII->get(NewOpc), DefR)
15740b57cec5SDimitry Andric                   .add(ExtOp)
15750b57cec5SDimitry Andric                   .add(MachineOperand(Ex.Rs))
15760b57cec5SDimitry Andric                   .addImm(Ex.S);
15775ffd83dbSDimitry Andric       } else {
15785ffd83dbSDimitry Andric         // No compounds are available. It is not clear whether we should
15795ffd83dbSDimitry Andric         // even process such extenders where the initializer cannot be
15805ffd83dbSDimitry Andric         // a single instruction, but do it for now.
158104eeddc0SDimitry Andric         llvm::Register TmpR = MRI->createVirtualRegister(&Hexagon::IntRegsRegClass);
15825ffd83dbSDimitry Andric         BuildMI(MBB, At, dl, HII->get(Hexagon::S2_asl_i_r), TmpR)
15835ffd83dbSDimitry Andric           .add(MachineOperand(Ex.Rs))
15845ffd83dbSDimitry Andric           .addImm(Ex.S);
15855ffd83dbSDimitry Andric         if (Ex.Neg)
15865ffd83dbSDimitry Andric           InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_subri), DefR)
15875ffd83dbSDimitry Andric                     .add(ExtOp)
15885ffd83dbSDimitry Andric                     .add(MachineOperand(Register(TmpR, 0)));
15895ffd83dbSDimitry Andric         else
15905ffd83dbSDimitry Andric           InitI = BuildMI(MBB, At, dl, HII->get(Hexagon::A2_addi), DefR)
15915ffd83dbSDimitry Andric                     .add(MachineOperand(Register(TmpR, 0)))
15925ffd83dbSDimitry Andric                     .add(ExtOp);
15935ffd83dbSDimitry Andric       }
15940b57cec5SDimitry Andric     }
15950b57cec5SDimitry Andric   }
15960b57cec5SDimitry Andric 
15970b57cec5SDimitry Andric   assert(InitI);
15980b57cec5SDimitry Andric   (void)InitI;
15990b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Inserted def in bb#" << MBB.getNumber()
16000b57cec5SDimitry Andric                     << " for initializer: " << PrintInit(ExtI, *HRI) << "\n  "
16010b57cec5SDimitry Andric                     << *InitI);
16020b57cec5SDimitry Andric   return { DefR, 0 };
16030b57cec5SDimitry Andric }
16040b57cec5SDimitry Andric 
16050b57cec5SDimitry Andric // Replace the extender at index Idx with the register ExtR.
16060b57cec5SDimitry Andric bool HCE::replaceInstrExact(const ExtDesc &ED, Register ExtR) {
16070b57cec5SDimitry Andric   MachineInstr &MI = *ED.UseMI;
16080b57cec5SDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
16090b57cec5SDimitry Andric   MachineBasicBlock::iterator At = MI.getIterator();
16100b57cec5SDimitry Andric   DebugLoc dl = MI.getDebugLoc();
16110b57cec5SDimitry Andric   unsigned ExtOpc = MI.getOpcode();
16120b57cec5SDimitry Andric 
16130b57cec5SDimitry Andric   // With a few exceptions, direct replacement amounts to creating an
16140b57cec5SDimitry Andric   // instruction with a corresponding register opcode, with all operands
16150b57cec5SDimitry Andric   // the same, except for the register used in place of the extender.
16160b57cec5SDimitry Andric   unsigned RegOpc = getDirectRegReplacement(ExtOpc);
16170b57cec5SDimitry Andric 
16180b57cec5SDimitry Andric   if (RegOpc == TargetOpcode::REG_SEQUENCE) {
16190b57cec5SDimitry Andric     if (ExtOpc == Hexagon::A4_combineri)
16200b57cec5SDimitry Andric       BuildMI(MBB, At, dl, HII->get(RegOpc))
16210b57cec5SDimitry Andric         .add(MI.getOperand(0))
16220b57cec5SDimitry Andric         .add(MI.getOperand(1))
16230b57cec5SDimitry Andric         .addImm(Hexagon::isub_hi)
16240b57cec5SDimitry Andric         .add(MachineOperand(ExtR))
16250b57cec5SDimitry Andric         .addImm(Hexagon::isub_lo);
16260b57cec5SDimitry Andric     else if (ExtOpc == Hexagon::A4_combineir)
16270b57cec5SDimitry Andric       BuildMI(MBB, At, dl, HII->get(RegOpc))
16280b57cec5SDimitry Andric         .add(MI.getOperand(0))
16290b57cec5SDimitry Andric         .add(MachineOperand(ExtR))
16300b57cec5SDimitry Andric         .addImm(Hexagon::isub_hi)
16310b57cec5SDimitry Andric         .add(MI.getOperand(2))
16320b57cec5SDimitry Andric         .addImm(Hexagon::isub_lo);
16330b57cec5SDimitry Andric     else
16340b57cec5SDimitry Andric       llvm_unreachable("Unexpected opcode became REG_SEQUENCE");
16350b57cec5SDimitry Andric     MBB.erase(MI);
16360b57cec5SDimitry Andric     return true;
16370b57cec5SDimitry Andric   }
16380b57cec5SDimitry Andric   if (ExtOpc == Hexagon::C2_cmpgei || ExtOpc == Hexagon::C2_cmpgeui) {
16390b57cec5SDimitry Andric     unsigned NewOpc = ExtOpc == Hexagon::C2_cmpgei ? Hexagon::C2_cmplt
16400b57cec5SDimitry Andric                                                    : Hexagon::C2_cmpltu;
16410b57cec5SDimitry Andric     BuildMI(MBB, At, dl, HII->get(NewOpc))
16420b57cec5SDimitry Andric       .add(MI.getOperand(0))
16430b57cec5SDimitry Andric       .add(MachineOperand(ExtR))
16440b57cec5SDimitry Andric       .add(MI.getOperand(1));
16450b57cec5SDimitry Andric     MBB.erase(MI);
16460b57cec5SDimitry Andric     return true;
16470b57cec5SDimitry Andric   }
16480b57cec5SDimitry Andric 
16490b57cec5SDimitry Andric   if (RegOpc != 0) {
16500b57cec5SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(RegOpc));
16510b57cec5SDimitry Andric     unsigned RegN = ED.OpNum;
16520b57cec5SDimitry Andric     // Copy all operands except the one that has the extender.
16530b57cec5SDimitry Andric     for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
16540b57cec5SDimitry Andric       if (i != RegN)
16550b57cec5SDimitry Andric         MIB.add(MI.getOperand(i));
16560b57cec5SDimitry Andric       else
16570b57cec5SDimitry Andric         MIB.add(MachineOperand(ExtR));
16580b57cec5SDimitry Andric     }
16590b57cec5SDimitry Andric     MIB.cloneMemRefs(MI);
16600b57cec5SDimitry Andric     MBB.erase(MI);
16610b57cec5SDimitry Andric     return true;
16620b57cec5SDimitry Andric   }
16630b57cec5SDimitry Andric 
1664480093f4SDimitry Andric   if (MI.mayLoadOrStore() && !isStoreImmediate(ExtOpc)) {
16650b57cec5SDimitry Andric     // For memory instructions, there is an asymmetry in the addressing
16660b57cec5SDimitry Andric     // modes. Addressing modes allowing extenders can be replaced with
16670b57cec5SDimitry Andric     // addressing modes that use registers, but the order of operands
16680b57cec5SDimitry Andric     // (or even their number) may be different.
16690b57cec5SDimitry Andric     // Replacements:
16700b57cec5SDimitry Andric     //   BaseImmOffset (io)  -> BaseRegOffset (rr)
16710b57cec5SDimitry Andric     //   BaseLongOffset (ur) -> BaseRegOffset (rr)
16720b57cec5SDimitry Andric     unsigned RegOpc, Shift;
16730b57cec5SDimitry Andric     unsigned AM = HII->getAddrMode(MI);
16740b57cec5SDimitry Andric     if (AM == HexagonII::BaseImmOffset) {
16750b57cec5SDimitry Andric       RegOpc = HII->changeAddrMode_io_rr(ExtOpc);
16760b57cec5SDimitry Andric       Shift = 0;
16770b57cec5SDimitry Andric     } else if (AM == HexagonII::BaseLongOffset) {
16780b57cec5SDimitry Andric       // Loads:  Rd = L4_loadri_ur Rs, S, ##
16790b57cec5SDimitry Andric       // Stores: S4_storeri_ur Rs, S, ##, Rt
16800b57cec5SDimitry Andric       RegOpc = HII->changeAddrMode_ur_rr(ExtOpc);
16810b57cec5SDimitry Andric       Shift = MI.getOperand(MI.mayLoad() ? 2 : 1).getImm();
16820b57cec5SDimitry Andric     } else {
16830b57cec5SDimitry Andric       llvm_unreachable("Unexpected addressing mode");
16840b57cec5SDimitry Andric     }
16850b57cec5SDimitry Andric #ifndef NDEBUG
16860b57cec5SDimitry Andric     if (RegOpc == -1u) {
16870b57cec5SDimitry Andric       dbgs() << "\nExtOpc: " << HII->getName(ExtOpc) << " has no rr version\n";
16880b57cec5SDimitry Andric       llvm_unreachable("No corresponding rr instruction");
16890b57cec5SDimitry Andric     }
16900b57cec5SDimitry Andric #endif
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric     unsigned BaseP, OffP;
16930b57cec5SDimitry Andric     HII->getBaseAndOffsetPosition(MI, BaseP, OffP);
16940b57cec5SDimitry Andric 
16950b57cec5SDimitry Andric     // Build an rr instruction: (RegOff + RegBase<<0)
16960b57cec5SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(RegOpc));
16970b57cec5SDimitry Andric     // First, add the def for loads.
16980b57cec5SDimitry Andric     if (MI.mayLoad())
16990b57cec5SDimitry Andric       MIB.add(getLoadResultOp(MI));
17000b57cec5SDimitry Andric     // Handle possible predication.
17010b57cec5SDimitry Andric     if (HII->isPredicated(MI))
17020b57cec5SDimitry Andric       MIB.add(getPredicateOp(MI));
17030b57cec5SDimitry Andric     // Build the address.
17040b57cec5SDimitry Andric     MIB.add(MachineOperand(ExtR));      // RegOff
17050b57cec5SDimitry Andric     MIB.add(MI.getOperand(BaseP));      // RegBase
17060b57cec5SDimitry Andric     MIB.addImm(Shift);                  // << Shift
17070b57cec5SDimitry Andric     // Add the stored value for stores.
17080b57cec5SDimitry Andric     if (MI.mayStore())
17090b57cec5SDimitry Andric       MIB.add(getStoredValueOp(MI));
17100b57cec5SDimitry Andric     MIB.cloneMemRefs(MI);
17110b57cec5SDimitry Andric     MBB.erase(MI);
17120b57cec5SDimitry Andric     return true;
17130b57cec5SDimitry Andric   }
17140b57cec5SDimitry Andric 
17150b57cec5SDimitry Andric #ifndef NDEBUG
17160b57cec5SDimitry Andric   dbgs() << '\n' << MI;
17170b57cec5SDimitry Andric #endif
17180b57cec5SDimitry Andric   llvm_unreachable("Unhandled exact replacement");
17190b57cec5SDimitry Andric   return false;
17200b57cec5SDimitry Andric }
17210b57cec5SDimitry Andric 
17220b57cec5SDimitry Andric // Replace the extender ED with a form corresponding to the initializer ExtI.
17230b57cec5SDimitry Andric bool HCE::replaceInstrExpr(const ExtDesc &ED, const ExtenderInit &ExtI,
17240b57cec5SDimitry Andric       Register ExtR, int32_t &Diff) {
17250b57cec5SDimitry Andric   MachineInstr &MI = *ED.UseMI;
17260b57cec5SDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
17270b57cec5SDimitry Andric   MachineBasicBlock::iterator At = MI.getIterator();
17280b57cec5SDimitry Andric   DebugLoc dl = MI.getDebugLoc();
17290b57cec5SDimitry Andric   unsigned ExtOpc = MI.getOpcode();
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric   if (ExtOpc == Hexagon::A2_tfrsi) {
17320b57cec5SDimitry Andric     // A2_tfrsi is a special case: it's replaced with A2_addi, which introduces
17330b57cec5SDimitry Andric     // another range. One range is the one that's common to all tfrsi's uses,
17340b57cec5SDimitry Andric     // this one is the range of immediates in A2_addi. When calculating ranges,
17350b57cec5SDimitry Andric     // the addi's 16-bit argument was included, so now we need to make it such
17360b57cec5SDimitry Andric     // that the produced value is in the range for the uses alone.
17370b57cec5SDimitry Andric     // Most of the time, simply adding Diff will make the addi produce exact
17380b57cec5SDimitry Andric     // result, but if Diff is outside of the 16-bit range, some adjustment
17390b57cec5SDimitry Andric     // will be needed.
17400b57cec5SDimitry Andric     unsigned IdxOpc = getRegOffOpcode(ExtOpc);
17410b57cec5SDimitry Andric     assert(IdxOpc == Hexagon::A2_addi);
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric     // Clamp Diff to the 16 bit range.
17440b57cec5SDimitry Andric     int32_t D = isInt<16>(Diff) ? Diff : (Diff > 0 ? 32767 : -32768);
17450b57cec5SDimitry Andric     if (Diff > 32767) {
17460b57cec5SDimitry Andric       // Split Diff into two values: one that is close to min/max int16,
17470b57cec5SDimitry Andric       // and the other being the rest, and such that both have the same
17480b57cec5SDimitry Andric       // "alignment" as Diff.
17490b57cec5SDimitry Andric       uint32_t UD = Diff;
17500b57cec5SDimitry Andric       OffsetRange R = getOffsetRange(MI.getOperand(0));
175106c3fb27SDimitry Andric       uint32_t A = std::min<uint32_t>(R.Align, 1u << llvm::countr_zero(UD));
17520b57cec5SDimitry Andric       D &= ~(A-1);
17530b57cec5SDimitry Andric     }
17540b57cec5SDimitry Andric     BuildMI(MBB, At, dl, HII->get(IdxOpc))
17550b57cec5SDimitry Andric       .add(MI.getOperand(0))
17560b57cec5SDimitry Andric       .add(MachineOperand(ExtR))
17570b57cec5SDimitry Andric       .addImm(D);
17580b57cec5SDimitry Andric     Diff -= D;
17590b57cec5SDimitry Andric #ifndef NDEBUG
17600b57cec5SDimitry Andric     // Make sure the output is within allowable range for uses.
17610b57cec5SDimitry Andric     // "Diff" is a difference in the "opposite direction", i.e. Ext - DefV,
17620b57cec5SDimitry Andric     // not DefV - Ext, as the getOffsetRange would calculate.
17630b57cec5SDimitry Andric     OffsetRange Uses = getOffsetRange(MI.getOperand(0));
17640b57cec5SDimitry Andric     if (!Uses.contains(-Diff))
17650b57cec5SDimitry Andric       dbgs() << "Diff: " << -Diff << " out of range " << Uses
17660b57cec5SDimitry Andric              << " for " << MI;
17670b57cec5SDimitry Andric     assert(Uses.contains(-Diff));
17680b57cec5SDimitry Andric #endif
17690b57cec5SDimitry Andric     MBB.erase(MI);
17700b57cec5SDimitry Andric     return true;
17710b57cec5SDimitry Andric   }
17720b57cec5SDimitry Andric 
17730b57cec5SDimitry Andric   const ExtValue &EV = ExtI.first; (void)EV;
17740b57cec5SDimitry Andric   const ExtExpr &Ex = ExtI.second; (void)Ex;
17750b57cec5SDimitry Andric 
17760b57cec5SDimitry Andric   if (ExtOpc == Hexagon::A2_addi || ExtOpc == Hexagon::A2_subri) {
17770b57cec5SDimitry Andric     // If addi/subri are replaced with the exactly matching initializer,
17780b57cec5SDimitry Andric     // they amount to COPY.
17790b57cec5SDimitry Andric     // Check that the initializer is an exact match (for simplicity).
17800b57cec5SDimitry Andric #ifndef NDEBUG
17810b57cec5SDimitry Andric     bool IsAddi = ExtOpc == Hexagon::A2_addi;
17820b57cec5SDimitry Andric     const MachineOperand &RegOp = MI.getOperand(IsAddi ? 1 : 2);
17830b57cec5SDimitry Andric     const MachineOperand &ImmOp = MI.getOperand(IsAddi ? 2 : 1);
17840b57cec5SDimitry Andric     assert(Ex.Rs == RegOp && EV == ImmOp && Ex.Neg != IsAddi &&
17850b57cec5SDimitry Andric            "Initializer mismatch");
17860b57cec5SDimitry Andric #endif
17870b57cec5SDimitry Andric     BuildMI(MBB, At, dl, HII->get(TargetOpcode::COPY))
17880b57cec5SDimitry Andric       .add(MI.getOperand(0))
17890b57cec5SDimitry Andric       .add(MachineOperand(ExtR));
17900b57cec5SDimitry Andric     Diff = 0;
17910b57cec5SDimitry Andric     MBB.erase(MI);
17920b57cec5SDimitry Andric     return true;
17930b57cec5SDimitry Andric   }
17940b57cec5SDimitry Andric   if (ExtOpc == Hexagon::M2_accii || ExtOpc == Hexagon::M2_naccii ||
17950b57cec5SDimitry Andric       ExtOpc == Hexagon::S4_addaddi || ExtOpc == Hexagon::S4_subaddi) {
17960b57cec5SDimitry Andric     // M2_accii:    add(Rt,add(Rs,V)) (tied)
17970b57cec5SDimitry Andric     // M2_naccii:   sub(Rt,add(Rs,V))
17980b57cec5SDimitry Andric     // S4_addaddi:  add(Rt,add(Rs,V))
17990b57cec5SDimitry Andric     // S4_subaddi:  add(Rt,sub(V,Rs))
18000b57cec5SDimitry Andric     // Check that Rs and V match the initializer expression. The Rs+V is the
18010b57cec5SDimitry Andric     // combination that is considered "subexpression" for V, although Rx+V
18020b57cec5SDimitry Andric     // would also be valid.
18030b57cec5SDimitry Andric #ifndef NDEBUG
18040b57cec5SDimitry Andric     bool IsSub = ExtOpc == Hexagon::S4_subaddi;
18050b57cec5SDimitry Andric     Register Rs = MI.getOperand(IsSub ? 3 : 2);
18060b57cec5SDimitry Andric     ExtValue V = MI.getOperand(IsSub ? 2 : 3);
18070b57cec5SDimitry Andric     assert(EV == V && Rs == Ex.Rs && IsSub == Ex.Neg && "Initializer mismatch");
18080b57cec5SDimitry Andric #endif
18090b57cec5SDimitry Andric     unsigned NewOpc = ExtOpc == Hexagon::M2_naccii ? Hexagon::A2_sub
18100b57cec5SDimitry Andric                                                    : Hexagon::A2_add;
18110b57cec5SDimitry Andric     BuildMI(MBB, At, dl, HII->get(NewOpc))
18120b57cec5SDimitry Andric       .add(MI.getOperand(0))
18130b57cec5SDimitry Andric       .add(MI.getOperand(1))
18140b57cec5SDimitry Andric       .add(MachineOperand(ExtR));
18150b57cec5SDimitry Andric     MBB.erase(MI);
18160b57cec5SDimitry Andric     return true;
18170b57cec5SDimitry Andric   }
18180b57cec5SDimitry Andric 
1819480093f4SDimitry Andric   if (MI.mayLoadOrStore()) {
18200b57cec5SDimitry Andric     unsigned IdxOpc = getRegOffOpcode(ExtOpc);
18210b57cec5SDimitry Andric     assert(IdxOpc && "Expecting indexed opcode");
18220b57cec5SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MBB, At, dl, HII->get(IdxOpc));
18230b57cec5SDimitry Andric     // Construct the new indexed instruction.
18240b57cec5SDimitry Andric     // First, add the def for loads.
18250b57cec5SDimitry Andric     if (MI.mayLoad())
18260b57cec5SDimitry Andric       MIB.add(getLoadResultOp(MI));
18270b57cec5SDimitry Andric     // Handle possible predication.
18280b57cec5SDimitry Andric     if (HII->isPredicated(MI))
18290b57cec5SDimitry Andric       MIB.add(getPredicateOp(MI));
18300b57cec5SDimitry Andric     // Build the address.
18310b57cec5SDimitry Andric     MIB.add(MachineOperand(ExtR));
18320b57cec5SDimitry Andric     MIB.addImm(Diff);
18330b57cec5SDimitry Andric     // Add the stored value for stores.
18340b57cec5SDimitry Andric     if (MI.mayStore())
18350b57cec5SDimitry Andric       MIB.add(getStoredValueOp(MI));
18360b57cec5SDimitry Andric     MIB.cloneMemRefs(MI);
18370b57cec5SDimitry Andric     MBB.erase(MI);
18380b57cec5SDimitry Andric     return true;
18390b57cec5SDimitry Andric   }
18400b57cec5SDimitry Andric 
18410b57cec5SDimitry Andric #ifndef NDEBUG
18420b57cec5SDimitry Andric   dbgs() << '\n' << PrintInit(ExtI, *HRI) << "  " << MI;
18430b57cec5SDimitry Andric #endif
18440b57cec5SDimitry Andric   llvm_unreachable("Unhandled expr replacement");
18450b57cec5SDimitry Andric   return false;
18460b57cec5SDimitry Andric }
18470b57cec5SDimitry Andric 
18480b57cec5SDimitry Andric bool HCE::replaceInstr(unsigned Idx, Register ExtR, const ExtenderInit &ExtI) {
18490b57cec5SDimitry Andric   if (ReplaceLimit.getNumOccurrences()) {
18500b57cec5SDimitry Andric     if (ReplaceLimit <= ReplaceCounter)
18510b57cec5SDimitry Andric       return false;
18520b57cec5SDimitry Andric     ++ReplaceCounter;
18530b57cec5SDimitry Andric   }
18540b57cec5SDimitry Andric   const ExtDesc &ED = Extenders[Idx];
18550b57cec5SDimitry Andric   assert((!ED.IsDef || ED.Rd.Reg != 0) && "Missing Rd for def");
18560b57cec5SDimitry Andric   const ExtValue &DefV = ExtI.first;
18570b57cec5SDimitry Andric   assert(ExtRoot(ExtValue(ED)) == ExtRoot(DefV) && "Extender root mismatch");
18580b57cec5SDimitry Andric   const ExtExpr &DefEx = ExtI.second;
18590b57cec5SDimitry Andric 
18600b57cec5SDimitry Andric   ExtValue EV(ED);
18610b57cec5SDimitry Andric   int32_t Diff = EV.Offset - DefV.Offset;
18620b57cec5SDimitry Andric   const MachineInstr &MI = *ED.UseMI;
18630b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << __func__ << " Idx:" << Idx << " ExtR:"
18640b57cec5SDimitry Andric                     << PrintRegister(ExtR, *HRI) << " Diff:" << Diff << '\n');
18650b57cec5SDimitry Andric 
18660b57cec5SDimitry Andric   // These two addressing modes must be converted into indexed forms
18670b57cec5SDimitry Andric   // regardless of what the initializer looks like.
18680b57cec5SDimitry Andric   bool IsAbs = false, IsAbsSet = false;
1869480093f4SDimitry Andric   if (MI.mayLoadOrStore()) {
18700b57cec5SDimitry Andric     unsigned AM = HII->getAddrMode(MI);
18710b57cec5SDimitry Andric     IsAbs = AM == HexagonII::Absolute;
18720b57cec5SDimitry Andric     IsAbsSet = AM == HexagonII::AbsoluteSet;
18730b57cec5SDimitry Andric   }
18740b57cec5SDimitry Andric 
18750b57cec5SDimitry Andric   // If it's a def, remember all operands that need to be updated.
18760b57cec5SDimitry Andric   // If ED is a def, and Diff is not 0, then all uses of the register Rd
18770b57cec5SDimitry Andric   // defined by ED must be in the form (Rd, imm), i.e. the immediate offset
18780b57cec5SDimitry Andric   // must follow the Rd in the operand list.
18790b57cec5SDimitry Andric   std::vector<std::pair<MachineInstr*,unsigned>> RegOps;
18800b57cec5SDimitry Andric   if (ED.IsDef && Diff != 0) {
18810b57cec5SDimitry Andric     for (MachineOperand &Op : MRI->use_operands(ED.Rd.Reg)) {
18820b57cec5SDimitry Andric       MachineInstr &UI = *Op.getParent();
18830b57cec5SDimitry Andric       RegOps.push_back({&UI, getOperandIndex(UI, Op)});
18840b57cec5SDimitry Andric     }
18850b57cec5SDimitry Andric   }
18860b57cec5SDimitry Andric 
18870b57cec5SDimitry Andric   // Replace the instruction.
18880b57cec5SDimitry Andric   bool Replaced = false;
18890b57cec5SDimitry Andric   if (Diff == 0 && DefEx.trivial() && !IsAbs && !IsAbsSet)
18900b57cec5SDimitry Andric     Replaced = replaceInstrExact(ED, ExtR);
18910b57cec5SDimitry Andric   else
18920b57cec5SDimitry Andric     Replaced = replaceInstrExpr(ED, ExtI, ExtR, Diff);
18930b57cec5SDimitry Andric 
18940b57cec5SDimitry Andric   if (Diff != 0 && Replaced && ED.IsDef) {
18950b57cec5SDimitry Andric     // Update offsets of the def's uses.
18960b57cec5SDimitry Andric     for (std::pair<MachineInstr*,unsigned> P : RegOps) {
18970b57cec5SDimitry Andric       unsigned J = P.second;
18980b57cec5SDimitry Andric       assert(P.first->getNumOperands() > J+1 &&
18990b57cec5SDimitry Andric              P.first->getOperand(J+1).isImm());
19000b57cec5SDimitry Andric       MachineOperand &ImmOp = P.first->getOperand(J+1);
19010b57cec5SDimitry Andric       ImmOp.setImm(ImmOp.getImm() + Diff);
19020b57cec5SDimitry Andric     }
19030b57cec5SDimitry Andric     // If it was an absolute-set instruction, the "set" part has been removed.
19040b57cec5SDimitry Andric     // ExtR will now be the register with the extended value, and since all
19050b57cec5SDimitry Andric     // users of Rd have been updated, all that needs to be done is to replace
19060b57cec5SDimitry Andric     // Rd with ExtR.
19070b57cec5SDimitry Andric     if (IsAbsSet) {
19080b57cec5SDimitry Andric       assert(ED.Rd.Sub == 0 && ExtR.Sub == 0);
19090b57cec5SDimitry Andric       MRI->replaceRegWith(ED.Rd.Reg, ExtR.Reg);
19100b57cec5SDimitry Andric     }
19110b57cec5SDimitry Andric   }
19120b57cec5SDimitry Andric 
19130b57cec5SDimitry Andric   return Replaced;
19140b57cec5SDimitry Andric }
19150b57cec5SDimitry Andric 
19160b57cec5SDimitry Andric bool HCE::replaceExtenders(const AssignmentMap &IMap) {
19170b57cec5SDimitry Andric   LocDefList Defs;
19180b57cec5SDimitry Andric   bool Changed = false;
19190b57cec5SDimitry Andric 
1920480093f4SDimitry Andric   for (const std::pair<const ExtenderInit, IndexList> &P : IMap) {
19210b57cec5SDimitry Andric     const IndexList &Idxs = P.second;
19220b57cec5SDimitry Andric     if (Idxs.size() < CountThreshold)
19230b57cec5SDimitry Andric       continue;
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric     Defs.clear();
19260b57cec5SDimitry Andric     calculatePlacement(P.first, Idxs, Defs);
19270b57cec5SDimitry Andric     for (const std::pair<Loc,IndexList> &Q : Defs) {
19280b57cec5SDimitry Andric       Register DefR = insertInitializer(Q.first, P.first);
19290b57cec5SDimitry Andric       NewRegs.push_back(DefR.Reg);
19300b57cec5SDimitry Andric       for (unsigned I : Q.second)
19310b57cec5SDimitry Andric         Changed |= replaceInstr(I, DefR, P.first);
19320b57cec5SDimitry Andric     }
19330b57cec5SDimitry Andric   }
19340b57cec5SDimitry Andric   return Changed;
19350b57cec5SDimitry Andric }
19360b57cec5SDimitry Andric 
19370b57cec5SDimitry Andric unsigned HCE::getOperandIndex(const MachineInstr &MI,
19380b57cec5SDimitry Andric       const MachineOperand &Op) const {
19390b57cec5SDimitry Andric   for (unsigned i = 0, n = MI.getNumOperands(); i != n; ++i)
19400b57cec5SDimitry Andric     if (&MI.getOperand(i) == &Op)
19410b57cec5SDimitry Andric       return i;
19420b57cec5SDimitry Andric   llvm_unreachable("Not an operand of MI");
19430b57cec5SDimitry Andric }
19440b57cec5SDimitry Andric 
19450b57cec5SDimitry Andric const MachineOperand &HCE::getPredicateOp(const MachineInstr &MI) const {
19460b57cec5SDimitry Andric   assert(HII->isPredicated(MI));
19470b57cec5SDimitry Andric   for (const MachineOperand &Op : MI.operands()) {
19480b57cec5SDimitry Andric     if (!Op.isReg() || !Op.isUse() ||
19490b57cec5SDimitry Andric         MRI->getRegClass(Op.getReg()) != &Hexagon::PredRegsRegClass)
19500b57cec5SDimitry Andric       continue;
19510b57cec5SDimitry Andric     assert(Op.getSubReg() == 0 && "Predicate register with a subregister");
19520b57cec5SDimitry Andric     return Op;
19530b57cec5SDimitry Andric   }
19540b57cec5SDimitry Andric   llvm_unreachable("Predicate operand not found");
19550b57cec5SDimitry Andric }
19560b57cec5SDimitry Andric 
19570b57cec5SDimitry Andric const MachineOperand &HCE::getLoadResultOp(const MachineInstr &MI) const {
19580b57cec5SDimitry Andric   assert(MI.mayLoad());
19590b57cec5SDimitry Andric   return MI.getOperand(0);
19600b57cec5SDimitry Andric }
19610b57cec5SDimitry Andric 
19620b57cec5SDimitry Andric const MachineOperand &HCE::getStoredValueOp(const MachineInstr &MI) const {
19630b57cec5SDimitry Andric   assert(MI.mayStore());
19640b57cec5SDimitry Andric   return MI.getOperand(MI.getNumExplicitOperands()-1);
19650b57cec5SDimitry Andric }
19660b57cec5SDimitry Andric 
19670b57cec5SDimitry Andric bool HCE::runOnMachineFunction(MachineFunction &MF) {
19680b57cec5SDimitry Andric   if (skipFunction(MF.getFunction()))
19690b57cec5SDimitry Andric     return false;
19700b57cec5SDimitry Andric   if (MF.getFunction().hasPersonalityFn()) {
19710b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << getPassName() << ": skipping " << MF.getName()
19720b57cec5SDimitry Andric                       << " due to exception handling\n");
19730b57cec5SDimitry Andric     return false;
19740b57cec5SDimitry Andric   }
19750b57cec5SDimitry Andric   LLVM_DEBUG(MF.print(dbgs() << "Before " << getPassName() << '\n', nullptr));
19760b57cec5SDimitry Andric 
19775ffd83dbSDimitry Andric   HST = &MF.getSubtarget<HexagonSubtarget>();
19785ffd83dbSDimitry Andric   HII = HST->getInstrInfo();
19795ffd83dbSDimitry Andric   HRI = HST->getRegisterInfo();
19800fca6ea1SDimitry Andric   MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
19810b57cec5SDimitry Andric   MRI = &MF.getRegInfo();
19820b57cec5SDimitry Andric   AssignmentMap IMap;
19830b57cec5SDimitry Andric 
19840b57cec5SDimitry Andric   collect(MF);
19850b57cec5SDimitry Andric   llvm::sort(Extenders, [this](const ExtDesc &A, const ExtDesc &B) {
19860b57cec5SDimitry Andric     ExtValue VA(A), VB(B);
19870b57cec5SDimitry Andric     if (VA != VB)
19880b57cec5SDimitry Andric       return VA < VB;
19890b57cec5SDimitry Andric     const MachineInstr *MA = A.UseMI;
19900b57cec5SDimitry Andric     const MachineInstr *MB = B.UseMI;
19910b57cec5SDimitry Andric     if (MA == MB) {
19920b57cec5SDimitry Andric       // If it's the same instruction, compare operand numbers.
19930b57cec5SDimitry Andric       return A.OpNum < B.OpNum;
19940b57cec5SDimitry Andric     }
19950b57cec5SDimitry Andric 
19960b57cec5SDimitry Andric     const MachineBasicBlock *BA = MA->getParent();
19970b57cec5SDimitry Andric     const MachineBasicBlock *BB = MB->getParent();
19980b57cec5SDimitry Andric     assert(BA->getNumber() != -1 && BB->getNumber() != -1);
19990b57cec5SDimitry Andric     if (BA != BB)
20000b57cec5SDimitry Andric       return BA->getNumber() < BB->getNumber();
20010b57cec5SDimitry Andric     return MDT->dominates(MA, MB);
20020b57cec5SDimitry Andric   });
20030b57cec5SDimitry Andric 
20040b57cec5SDimitry Andric   bool Changed = false;
20050b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Collected " << Extenders.size() << " extenders\n");
20060b57cec5SDimitry Andric   for (unsigned I = 0, E = Extenders.size(); I != E; ) {
20070b57cec5SDimitry Andric     unsigned B = I;
20080b57cec5SDimitry Andric     const ExtRoot &T = Extenders[B].getOp();
20090b57cec5SDimitry Andric     while (I != E && ExtRoot(Extenders[I].getOp()) == T)
20100b57cec5SDimitry Andric       ++I;
20110b57cec5SDimitry Andric 
20120b57cec5SDimitry Andric     IMap.clear();
20130b57cec5SDimitry Andric     assignInits(T, B, I, IMap);
20140b57cec5SDimitry Andric     Changed |= replaceExtenders(IMap);
20150b57cec5SDimitry Andric   }
20160b57cec5SDimitry Andric 
20170b57cec5SDimitry Andric   LLVM_DEBUG({
20180b57cec5SDimitry Andric     if (Changed)
20190b57cec5SDimitry Andric       MF.print(dbgs() << "After " << getPassName() << '\n', nullptr);
20200b57cec5SDimitry Andric     else
20210b57cec5SDimitry Andric       dbgs() << "No changes\n";
20220b57cec5SDimitry Andric   });
20230b57cec5SDimitry Andric   return Changed;
20240b57cec5SDimitry Andric }
20250b57cec5SDimitry Andric 
20260b57cec5SDimitry Andric FunctionPass *llvm::createHexagonConstExtenders() {
20270b57cec5SDimitry Andric   return new HexagonConstExtenders();
20280b57cec5SDimitry Andric }
2029