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