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