xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceTargetLowering.h (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceTargetLowering.h - Lowering interface -----*- C++ -*-===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Declares the TargetLowering, LoweringContext, and TargetDataLowering
12*03ce13f7SAndroid Build Coastguard Worker /// classes.
13*03ce13f7SAndroid Build Coastguard Worker ///
14*03ce13f7SAndroid Build Coastguard Worker /// TargetLowering is an abstract class used to drive the translation/lowering
15*03ce13f7SAndroid Build Coastguard Worker /// process. LoweringContext maintains a context for lowering each instruction,
16*03ce13f7SAndroid Build Coastguard Worker /// offering conveniences such as iterating over non-deleted instructions.
17*03ce13f7SAndroid Build Coastguard Worker /// TargetDataLowering is an abstract class used to drive the lowering/emission
18*03ce13f7SAndroid Build Coastguard Worker /// of global initializers, external global declarations, and internal constant
19*03ce13f7SAndroid Build Coastguard Worker /// pools.
20*03ce13f7SAndroid Build Coastguard Worker ///
21*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
22*03ce13f7SAndroid Build Coastguard Worker 
23*03ce13f7SAndroid Build Coastguard Worker #ifndef SUBZERO_SRC_ICETARGETLOWERING_H
24*03ce13f7SAndroid Build Coastguard Worker #define SUBZERO_SRC_ICETARGETLOWERING_H
25*03ce13f7SAndroid Build Coastguard Worker 
26*03ce13f7SAndroid Build Coastguard Worker #include "IceBitVector.h"
27*03ce13f7SAndroid Build Coastguard Worker #include "IceCfgNode.h"
28*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h"
29*03ce13f7SAndroid Build Coastguard Worker #include "IceInst.h" // for the names of the Inst subtypes
30*03ce13f7SAndroid Build Coastguard Worker #include "IceOperand.h"
31*03ce13f7SAndroid Build Coastguard Worker #include "IceRegAlloc.h"
32*03ce13f7SAndroid Build Coastguard Worker #include "IceTypes.h"
33*03ce13f7SAndroid Build Coastguard Worker 
34*03ce13f7SAndroid Build Coastguard Worker #include <utility>
35*03ce13f7SAndroid Build Coastguard Worker 
36*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
37*03ce13f7SAndroid Build Coastguard Worker 
38*03ce13f7SAndroid Build Coastguard Worker // UnimplementedError is defined as a macro so that we can get actual line
39*03ce13f7SAndroid Build Coastguard Worker // numbers.
40*03ce13f7SAndroid Build Coastguard Worker #define UnimplementedError(Flags)                                              \
41*03ce13f7SAndroid Build Coastguard Worker   do {                                                                         \
42*03ce13f7SAndroid Build Coastguard Worker     if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) {         \
43*03ce13f7SAndroid Build Coastguard Worker       /* Use llvm_unreachable instead of report_fatal_error, which gives       \
44*03ce13f7SAndroid Build Coastguard Worker          better stack traces. */                                               \
45*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable("Not yet implemented");                                 \
46*03ce13f7SAndroid Build Coastguard Worker       abort();                                                                 \
47*03ce13f7SAndroid Build Coastguard Worker     }                                                                          \
48*03ce13f7SAndroid Build Coastguard Worker   } while (0)
49*03ce13f7SAndroid Build Coastguard Worker 
50*03ce13f7SAndroid Build Coastguard Worker // UnimplementedLoweringError is similar in style to UnimplementedError.  Given
51*03ce13f7SAndroid Build Coastguard Worker // a TargetLowering object pointer and an Inst pointer, it adds appropriate
52*03ce13f7SAndroid Build Coastguard Worker // FakeDef and FakeUse instructions to try maintain liveness consistency.
53*03ce13f7SAndroid Build Coastguard Worker #define UnimplementedLoweringError(Target, Instr)                              \
54*03ce13f7SAndroid Build Coastguard Worker   do {                                                                         \
55*03ce13f7SAndroid Build Coastguard Worker     if (getFlags().getSkipUnimplemented()) {                                   \
56*03ce13f7SAndroid Build Coastguard Worker       (Target)->addFakeDefUses(Instr);                                         \
57*03ce13f7SAndroid Build Coastguard Worker     } else {                                                                   \
58*03ce13f7SAndroid Build Coastguard Worker       /* Use llvm_unreachable instead of report_fatal_error, which gives       \
59*03ce13f7SAndroid Build Coastguard Worker          better stack traces. */                                               \
60*03ce13f7SAndroid Build Coastguard Worker       llvm_unreachable(                                                        \
61*03ce13f7SAndroid Build Coastguard Worker           (std::string("Not yet implemented: ") + Instr->getInstName())        \
62*03ce13f7SAndroid Build Coastguard Worker               .c_str());                                                       \
63*03ce13f7SAndroid Build Coastguard Worker       abort();                                                                 \
64*03ce13f7SAndroid Build Coastguard Worker     }                                                                          \
65*03ce13f7SAndroid Build Coastguard Worker   } while (0)
66*03ce13f7SAndroid Build Coastguard Worker 
67*03ce13f7SAndroid Build Coastguard Worker /// LoweringContext makes it easy to iterate through non-deleted instructions in
68*03ce13f7SAndroid Build Coastguard Worker /// a node, and insert new (lowered) instructions at the current point. Along
69*03ce13f7SAndroid Build Coastguard Worker /// with the instruction list container and associated iterators, it holds the
70*03ce13f7SAndroid Build Coastguard Worker /// current node, which is needed when inserting new instructions in order to
71*03ce13f7SAndroid Build Coastguard Worker /// track whether variables are used as single-block or multi-block.
72*03ce13f7SAndroid Build Coastguard Worker class LoweringContext {
73*03ce13f7SAndroid Build Coastguard Worker   LoweringContext(const LoweringContext &) = delete;
74*03ce13f7SAndroid Build Coastguard Worker   LoweringContext &operator=(const LoweringContext &) = delete;
75*03ce13f7SAndroid Build Coastguard Worker 
76*03ce13f7SAndroid Build Coastguard Worker public:
77*03ce13f7SAndroid Build Coastguard Worker   LoweringContext() = default;
78*03ce13f7SAndroid Build Coastguard Worker   ~LoweringContext() = default;
79*03ce13f7SAndroid Build Coastguard Worker   void init(CfgNode *Node);
getNextInst()80*03ce13f7SAndroid Build Coastguard Worker   Inst *getNextInst() const {
81*03ce13f7SAndroid Build Coastguard Worker     if (Next == End)
82*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
83*03ce13f7SAndroid Build Coastguard Worker     return iteratorToInst(Next);
84*03ce13f7SAndroid Build Coastguard Worker   }
getNextInst(InstList::iterator & Iter)85*03ce13f7SAndroid Build Coastguard Worker   Inst *getNextInst(InstList::iterator &Iter) const {
86*03ce13f7SAndroid Build Coastguard Worker     advanceForward(Iter);
87*03ce13f7SAndroid Build Coastguard Worker     if (Iter == End)
88*03ce13f7SAndroid Build Coastguard Worker       return nullptr;
89*03ce13f7SAndroid Build Coastguard Worker     return iteratorToInst(Iter);
90*03ce13f7SAndroid Build Coastguard Worker   }
getNode()91*03ce13f7SAndroid Build Coastguard Worker   CfgNode *getNode() const { return Node; }
atEnd()92*03ce13f7SAndroid Build Coastguard Worker   bool atEnd() const { return Cur == End; }
getCur()93*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator getCur() const { return Cur; }
getNext()94*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator getNext() const { return Next; }
getEnd()95*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator getEnd() const { return End; }
96*03ce13f7SAndroid Build Coastguard Worker   void insert(Inst *Instr);
insert(Args &&...A)97*03ce13f7SAndroid Build Coastguard Worker   template <typename Inst, typename... Args> Inst *insert(Args &&...A) {
98*03ce13f7SAndroid Build Coastguard Worker     auto *New = Inst::create(Node->getCfg(), std::forward<Args>(A)...);
99*03ce13f7SAndroid Build Coastguard Worker     insert(New);
100*03ce13f7SAndroid Build Coastguard Worker     return New;
101*03ce13f7SAndroid Build Coastguard Worker   }
102*03ce13f7SAndroid Build Coastguard Worker   Inst *getLastInserted() const;
advanceCur()103*03ce13f7SAndroid Build Coastguard Worker   void advanceCur() { Cur = Next; }
advanceNext()104*03ce13f7SAndroid Build Coastguard Worker   void advanceNext() { advanceForward(Next); }
setCur(InstList::iterator C)105*03ce13f7SAndroid Build Coastguard Worker   void setCur(InstList::iterator C) { Cur = C; }
setNext(InstList::iterator N)106*03ce13f7SAndroid Build Coastguard Worker   void setNext(InstList::iterator N) { Next = N; }
107*03ce13f7SAndroid Build Coastguard Worker   void rewind();
setInsertPoint(const InstList::iterator & Position)108*03ce13f7SAndroid Build Coastguard Worker   void setInsertPoint(const InstList::iterator &Position) { Next = Position; }
109*03ce13f7SAndroid Build Coastguard Worker   void availabilityReset();
110*03ce13f7SAndroid Build Coastguard Worker   void availabilityUpdate();
111*03ce13f7SAndroid Build Coastguard Worker   Variable *availabilityGet(Operand *Src) const;
112*03ce13f7SAndroid Build Coastguard Worker 
113*03ce13f7SAndroid Build Coastguard Worker private:
114*03ce13f7SAndroid Build Coastguard Worker   /// Node is the argument to Inst::updateVars().
115*03ce13f7SAndroid Build Coastguard Worker   CfgNode *Node = nullptr;
116*03ce13f7SAndroid Build Coastguard Worker   Inst *LastInserted = nullptr;
117*03ce13f7SAndroid Build Coastguard Worker   /// Cur points to the current instruction being considered. It is guaranteed
118*03ce13f7SAndroid Build Coastguard Worker   /// to point to a non-deleted instruction, or to be End.
119*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator Cur;
120*03ce13f7SAndroid Build Coastguard Worker   /// Next doubles as a pointer to the next valid instruction (if any), and the
121*03ce13f7SAndroid Build Coastguard Worker   /// new-instruction insertion point. It is also updated for the caller in case
122*03ce13f7SAndroid Build Coastguard Worker   /// the lowering consumes more than one high-level instruction. It is
123*03ce13f7SAndroid Build Coastguard Worker   /// guaranteed to point to a non-deleted instruction after Cur, or to be End.
124*03ce13f7SAndroid Build Coastguard Worker   // TODO: Consider separating the notion of "next valid instruction" and "new
125*03ce13f7SAndroid Build Coastguard Worker   // instruction insertion point", to avoid confusion when previously-deleted
126*03ce13f7SAndroid Build Coastguard Worker   // instructions come between the two points.
127*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator Next;
128*03ce13f7SAndroid Build Coastguard Worker   /// Begin is a copy of Insts.begin(), used if iterators are moved backward.
129*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator Begin;
130*03ce13f7SAndroid Build Coastguard Worker   /// End is a copy of Insts.end(), used if Next needs to be advanced.
131*03ce13f7SAndroid Build Coastguard Worker   InstList::iterator End;
132*03ce13f7SAndroid Build Coastguard Worker   /// LastDest and LastSrc capture the parameters of the last "Dest=Src" simple
133*03ce13f7SAndroid Build Coastguard Worker   /// assignment inserted (provided Src is a variable).  This is used for simple
134*03ce13f7SAndroid Build Coastguard Worker   /// availability analysis.
135*03ce13f7SAndroid Build Coastguard Worker   Variable *LastDest = nullptr;
136*03ce13f7SAndroid Build Coastguard Worker   Variable *LastSrc = nullptr;
137*03ce13f7SAndroid Build Coastguard Worker 
138*03ce13f7SAndroid Build Coastguard Worker   void skipDeleted(InstList::iterator &I) const;
139*03ce13f7SAndroid Build Coastguard Worker   void advanceForward(InstList::iterator &I) const;
140*03ce13f7SAndroid Build Coastguard Worker };
141*03ce13f7SAndroid Build Coastguard Worker 
142*03ce13f7SAndroid Build Coastguard Worker /// A helper class to advance the LoweringContext at each loop iteration.
143*03ce13f7SAndroid Build Coastguard Worker class PostIncrLoweringContext {
144*03ce13f7SAndroid Build Coastguard Worker   PostIncrLoweringContext() = delete;
145*03ce13f7SAndroid Build Coastguard Worker   PostIncrLoweringContext(const PostIncrLoweringContext &) = delete;
146*03ce13f7SAndroid Build Coastguard Worker   PostIncrLoweringContext &operator=(const PostIncrLoweringContext &) = delete;
147*03ce13f7SAndroid Build Coastguard Worker 
148*03ce13f7SAndroid Build Coastguard Worker public:
PostIncrLoweringContext(LoweringContext & Context)149*03ce13f7SAndroid Build Coastguard Worker   explicit PostIncrLoweringContext(LoweringContext &Context)
150*03ce13f7SAndroid Build Coastguard Worker       : Context(Context) {}
~PostIncrLoweringContext()151*03ce13f7SAndroid Build Coastguard Worker   ~PostIncrLoweringContext() {
152*03ce13f7SAndroid Build Coastguard Worker     Context.advanceCur();
153*03ce13f7SAndroid Build Coastguard Worker     Context.advanceNext();
154*03ce13f7SAndroid Build Coastguard Worker   }
155*03ce13f7SAndroid Build Coastguard Worker 
156*03ce13f7SAndroid Build Coastguard Worker private:
157*03ce13f7SAndroid Build Coastguard Worker   LoweringContext &Context;
158*03ce13f7SAndroid Build Coastguard Worker };
159*03ce13f7SAndroid Build Coastguard Worker 
160*03ce13f7SAndroid Build Coastguard Worker /// TargetLowering is the base class for all backends in Subzero. In addition to
161*03ce13f7SAndroid Build Coastguard Worker /// implementing the abstract methods in this class, each concrete target must
162*03ce13f7SAndroid Build Coastguard Worker /// also implement a named constructor in its own namespace. For instance, for
163*03ce13f7SAndroid Build Coastguard Worker /// X8632 we have:
164*03ce13f7SAndroid Build Coastguard Worker ///
165*03ce13f7SAndroid Build Coastguard Worker ///  namespace X8632 {
166*03ce13f7SAndroid Build Coastguard Worker ///    void createTargetLowering(Cfg *Func);
167*03ce13f7SAndroid Build Coastguard Worker ///  }
168*03ce13f7SAndroid Build Coastguard Worker class TargetLowering {
169*03ce13f7SAndroid Build Coastguard Worker   TargetLowering() = delete;
170*03ce13f7SAndroid Build Coastguard Worker   TargetLowering(const TargetLowering &) = delete;
171*03ce13f7SAndroid Build Coastguard Worker   TargetLowering &operator=(const TargetLowering &) = delete;
172*03ce13f7SAndroid Build Coastguard Worker 
173*03ce13f7SAndroid Build Coastguard Worker public:
174*03ce13f7SAndroid Build Coastguard Worker   static void staticInit(GlobalContext *Ctx);
175*03ce13f7SAndroid Build Coastguard Worker   // Each target must define a public static method:
176*03ce13f7SAndroid Build Coastguard Worker   //   static void staticInit(GlobalContext *Ctx);
177*03ce13f7SAndroid Build Coastguard Worker   static bool shouldBePooled(const class Constant *C);
178*03ce13f7SAndroid Build Coastguard Worker   static Type getPointerType();
179*03ce13f7SAndroid Build Coastguard Worker 
180*03ce13f7SAndroid Build Coastguard Worker   static std::unique_ptr<TargetLowering> createLowering(TargetArch Target,
181*03ce13f7SAndroid Build Coastguard Worker                                                         Cfg *Func);
182*03ce13f7SAndroid Build Coastguard Worker 
183*03ce13f7SAndroid Build Coastguard Worker   virtual std::unique_ptr<Assembler> createAssembler() const = 0;
184*03ce13f7SAndroid Build Coastguard Worker 
translate()185*03ce13f7SAndroid Build Coastguard Worker   void translate() {
186*03ce13f7SAndroid Build Coastguard Worker     switch (Func->getOptLevel()) {
187*03ce13f7SAndroid Build Coastguard Worker     case Opt_m1:
188*03ce13f7SAndroid Build Coastguard Worker       translateOm1();
189*03ce13f7SAndroid Build Coastguard Worker       break;
190*03ce13f7SAndroid Build Coastguard Worker     case Opt_0:
191*03ce13f7SAndroid Build Coastguard Worker       translateO0();
192*03ce13f7SAndroid Build Coastguard Worker       break;
193*03ce13f7SAndroid Build Coastguard Worker     case Opt_1:
194*03ce13f7SAndroid Build Coastguard Worker       translateO1();
195*03ce13f7SAndroid Build Coastguard Worker       break;
196*03ce13f7SAndroid Build Coastguard Worker     case Opt_2:
197*03ce13f7SAndroid Build Coastguard Worker       translateO2();
198*03ce13f7SAndroid Build Coastguard Worker       break;
199*03ce13f7SAndroid Build Coastguard Worker     }
200*03ce13f7SAndroid Build Coastguard Worker   }
translateOm1()201*03ce13f7SAndroid Build Coastguard Worker   virtual void translateOm1() {
202*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Target doesn't specify Om1 lowering steps.");
203*03ce13f7SAndroid Build Coastguard Worker   }
translateO0()204*03ce13f7SAndroid Build Coastguard Worker   virtual void translateO0() {
205*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Target doesn't specify O0 lowering steps.");
206*03ce13f7SAndroid Build Coastguard Worker   }
translateO1()207*03ce13f7SAndroid Build Coastguard Worker   virtual void translateO1() {
208*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Target doesn't specify O1 lowering steps.");
209*03ce13f7SAndroid Build Coastguard Worker   }
translateO2()210*03ce13f7SAndroid Build Coastguard Worker   virtual void translateO2() {
211*03ce13f7SAndroid Build Coastguard Worker     Func->setError("Target doesn't specify O2 lowering steps.");
212*03ce13f7SAndroid Build Coastguard Worker   }
213*03ce13f7SAndroid Build Coastguard Worker 
214*03ce13f7SAndroid Build Coastguard Worker   /// Generates calls to intrinsics for operations the Target can't handle.
215*03ce13f7SAndroid Build Coastguard Worker   void genTargetHelperCalls();
216*03ce13f7SAndroid Build Coastguard Worker   /// Tries to do address mode optimization on a single instruction.
217*03ce13f7SAndroid Build Coastguard Worker   void doAddressOpt();
218*03ce13f7SAndroid Build Coastguard Worker   /// Lowers a single non-Phi instruction.
219*03ce13f7SAndroid Build Coastguard Worker   void lower();
220*03ce13f7SAndroid Build Coastguard Worker   /// Inserts and lowers a single high-level instruction at a specific insertion
221*03ce13f7SAndroid Build Coastguard Worker   /// point.
222*03ce13f7SAndroid Build Coastguard Worker   void lowerInst(CfgNode *Node, InstList::iterator Next, InstHighLevel *Instr);
223*03ce13f7SAndroid Build Coastguard Worker   /// Does preliminary lowering of the set of Phi instructions in the current
224*03ce13f7SAndroid Build Coastguard Worker   /// node. The main intention is to do what's needed to keep the unlowered Phi
225*03ce13f7SAndroid Build Coastguard Worker   /// instructions consistent with the lowered non-Phi instructions, e.g. to
226*03ce13f7SAndroid Build Coastguard Worker   /// lower 64-bit operands on a 32-bit target.
prelowerPhis()227*03ce13f7SAndroid Build Coastguard Worker   virtual void prelowerPhis() {}
228*03ce13f7SAndroid Build Coastguard Worker   /// Tries to do branch optimization on a single instruction. Returns true if
229*03ce13f7SAndroid Build Coastguard Worker   /// some optimization was done.
doBranchOpt(Inst *,const CfgNode *)230*03ce13f7SAndroid Build Coastguard Worker   virtual bool doBranchOpt(Inst * /*I*/, const CfgNode * /*NextNode*/) {
231*03ce13f7SAndroid Build Coastguard Worker     return false;
232*03ce13f7SAndroid Build Coastguard Worker   }
233*03ce13f7SAndroid Build Coastguard Worker 
234*03ce13f7SAndroid Build Coastguard Worker   virtual SizeT getNumRegisters() const = 0;
235*03ce13f7SAndroid Build Coastguard Worker   /// Returns a variable pre-colored to the specified physical register. This is
236*03ce13f7SAndroid Build Coastguard Worker   /// generally used to get very direct access to the register such as in the
237*03ce13f7SAndroid Build Coastguard Worker   /// prolog or epilog or for marking scratch registers as killed by a call. If
238*03ce13f7SAndroid Build Coastguard Worker   /// a Type is not provided, a target-specific default type is used.
239*03ce13f7SAndroid Build Coastguard Worker   virtual Variable *getPhysicalRegister(RegNumT RegNum,
240*03ce13f7SAndroid Build Coastguard Worker                                         Type Ty = IceType_void) = 0;
241*03ce13f7SAndroid Build Coastguard Worker   /// Returns a printable name for the register.
242*03ce13f7SAndroid Build Coastguard Worker   virtual const char *getRegName(RegNumT RegNum, Type Ty) const = 0;
243*03ce13f7SAndroid Build Coastguard Worker 
hasFramePointer()244*03ce13f7SAndroid Build Coastguard Worker   virtual bool hasFramePointer() const { return false; }
245*03ce13f7SAndroid Build Coastguard Worker   virtual void setHasFramePointer() = 0;
246*03ce13f7SAndroid Build Coastguard Worker   virtual RegNumT getStackReg() const = 0;
247*03ce13f7SAndroid Build Coastguard Worker   virtual RegNumT getFrameReg() const = 0;
248*03ce13f7SAndroid Build Coastguard Worker   virtual RegNumT getFrameOrStackReg() const = 0;
249*03ce13f7SAndroid Build Coastguard Worker   virtual size_t typeWidthInBytesOnStack(Type Ty) const = 0;
250*03ce13f7SAndroid Build Coastguard Worker   virtual uint32_t getStackAlignment() const = 0;
needsStackPointerAlignment()251*03ce13f7SAndroid Build Coastguard Worker   virtual bool needsStackPointerAlignment() const { return false; }
252*03ce13f7SAndroid Build Coastguard Worker   virtual void reserveFixedAllocaArea(size_t Size, size_t Align) = 0;
253*03ce13f7SAndroid Build Coastguard Worker   virtual int32_t getFrameFixedAllocaOffset() const = 0;
maxOutArgsSizeBytes()254*03ce13f7SAndroid Build Coastguard Worker   virtual uint32_t maxOutArgsSizeBytes() const { return 0; }
255*03ce13f7SAndroid Build Coastguard Worker   // Addressing relative to frame pointer differs in MIPS compared to X86/ARM
256*03ce13f7SAndroid Build Coastguard Worker   // since MIPS decrements its stack pointer prior to saving it in the frame
257*03ce13f7SAndroid Build Coastguard Worker   // pointer register.
getFramePointerOffset(uint32_t CurrentOffset,uint32_t Size)258*03ce13f7SAndroid Build Coastguard Worker   virtual uint32_t getFramePointerOffset(uint32_t CurrentOffset,
259*03ce13f7SAndroid Build Coastguard Worker                                          uint32_t Size) const {
260*03ce13f7SAndroid Build Coastguard Worker     return -(CurrentOffset + Size);
261*03ce13f7SAndroid Build Coastguard Worker   }
262*03ce13f7SAndroid Build Coastguard Worker   /// Return whether a 64-bit Variable should be split into a Variable64On32.
263*03ce13f7SAndroid Build Coastguard Worker   virtual bool shouldSplitToVariable64On32(Type Ty) const = 0;
264*03ce13f7SAndroid Build Coastguard Worker 
265*03ce13f7SAndroid Build Coastguard Worker   /// Return whether a Vector Variable should be split into a VariableVecOn32.
shouldSplitToVariableVecOn32(Type Ty)266*03ce13f7SAndroid Build Coastguard Worker   virtual bool shouldSplitToVariableVecOn32(Type Ty) const {
267*03ce13f7SAndroid Build Coastguard Worker     (void)Ty;
268*03ce13f7SAndroid Build Coastguard Worker     return false;
269*03ce13f7SAndroid Build Coastguard Worker   }
270*03ce13f7SAndroid Build Coastguard Worker 
hasComputedFrame()271*03ce13f7SAndroid Build Coastguard Worker   bool hasComputedFrame() const { return HasComputedFrame; }
272*03ce13f7SAndroid Build Coastguard Worker   /// Returns true if this function calls a function that has the "returns
273*03ce13f7SAndroid Build Coastguard Worker   /// twice" attribute.
callsReturnsTwice()274*03ce13f7SAndroid Build Coastguard Worker   bool callsReturnsTwice() const { return CallsReturnsTwice; }
setCallsReturnsTwice(bool RetTwice)275*03ce13f7SAndroid Build Coastguard Worker   void setCallsReturnsTwice(bool RetTwice) { CallsReturnsTwice = RetTwice; }
makeNextLabelNumber()276*03ce13f7SAndroid Build Coastguard Worker   SizeT makeNextLabelNumber() { return NextLabelNumber++; }
makeNextJumpTableNumber()277*03ce13f7SAndroid Build Coastguard Worker   SizeT makeNextJumpTableNumber() { return NextJumpTableNumber++; }
getContext()278*03ce13f7SAndroid Build Coastguard Worker   LoweringContext &getContext() { return Context; }
getFunc()279*03ce13f7SAndroid Build Coastguard Worker   Cfg *getFunc() const { return Func; }
getGlobalContext()280*03ce13f7SAndroid Build Coastguard Worker   GlobalContext *getGlobalContext() const { return Ctx; }
281*03ce13f7SAndroid Build Coastguard Worker 
282*03ce13f7SAndroid Build Coastguard Worker   enum RegSet {
283*03ce13f7SAndroid Build Coastguard Worker     RegSet_None = 0,
284*03ce13f7SAndroid Build Coastguard Worker     RegSet_CallerSave = 1 << 0,
285*03ce13f7SAndroid Build Coastguard Worker     RegSet_CalleeSave = 1 << 1,
286*03ce13f7SAndroid Build Coastguard Worker     RegSet_StackPointer = 1 << 2,
287*03ce13f7SAndroid Build Coastguard Worker     RegSet_FramePointer = 1 << 3,
288*03ce13f7SAndroid Build Coastguard Worker     RegSet_All = ~RegSet_None
289*03ce13f7SAndroid Build Coastguard Worker   };
290*03ce13f7SAndroid Build Coastguard Worker   using RegSetMask = uint32_t;
291*03ce13f7SAndroid Build Coastguard Worker 
292*03ce13f7SAndroid Build Coastguard Worker   virtual SmallBitVector getRegisterSet(RegSetMask Include,
293*03ce13f7SAndroid Build Coastguard Worker                                         RegSetMask Exclude) const = 0;
294*03ce13f7SAndroid Build Coastguard Worker   /// Get the set of physical registers available for the specified Variable's
295*03ce13f7SAndroid Build Coastguard Worker   /// register class, applying register restrictions from the command line.
296*03ce13f7SAndroid Build Coastguard Worker   virtual const SmallBitVector &
297*03ce13f7SAndroid Build Coastguard Worker   getRegistersForVariable(const Variable *Var) const = 0;
298*03ce13f7SAndroid Build Coastguard Worker   /// Get the set of *all* physical registers available for the specified
299*03ce13f7SAndroid Build Coastguard Worker   /// Variable's register class, *not* applying register restrictions from the
300*03ce13f7SAndroid Build Coastguard Worker   /// command line.
301*03ce13f7SAndroid Build Coastguard Worker   virtual const SmallBitVector &
302*03ce13f7SAndroid Build Coastguard Worker   getAllRegistersForVariable(const Variable *Var) const = 0;
303*03ce13f7SAndroid Build Coastguard Worker   virtual const SmallBitVector &getAliasesForRegister(RegNumT) const = 0;
304*03ce13f7SAndroid Build Coastguard Worker 
305*03ce13f7SAndroid Build Coastguard Worker   void regAlloc(RegAllocKind Kind);
306*03ce13f7SAndroid Build Coastguard Worker   void postRegallocSplitting(const SmallBitVector &RegMask);
307*03ce13f7SAndroid Build Coastguard Worker 
308*03ce13f7SAndroid Build Coastguard Worker   /// Get the minimum number of clusters required for a jump table to be
309*03ce13f7SAndroid Build Coastguard Worker   /// considered.
310*03ce13f7SAndroid Build Coastguard Worker   virtual SizeT getMinJumpTableSize() const = 0;
311*03ce13f7SAndroid Build Coastguard Worker   virtual void emitJumpTable(const Cfg *Func,
312*03ce13f7SAndroid Build Coastguard Worker                              const InstJumpTable *JumpTable) const = 0;
313*03ce13f7SAndroid Build Coastguard Worker 
314*03ce13f7SAndroid Build Coastguard Worker   virtual void emitVariable(const Variable *Var) const = 0;
315*03ce13f7SAndroid Build Coastguard Worker 
316*03ce13f7SAndroid Build Coastguard Worker   void emitWithoutPrefix(const ConstantRelocatable *CR,
317*03ce13f7SAndroid Build Coastguard Worker                          const char *Suffix = "") const;
318*03ce13f7SAndroid Build Coastguard Worker 
319*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantInteger32 *C) const = 0;
320*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantInteger64 *C) const = 0;
321*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantFloat *C) const = 0;
322*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantDouble *C) const = 0;
323*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantUndef *C) const = 0;
324*03ce13f7SAndroid Build Coastguard Worker   virtual void emit(const ConstantRelocatable *CR) const = 0;
325*03ce13f7SAndroid Build Coastguard Worker 
326*03ce13f7SAndroid Build Coastguard Worker   /// Performs target-specific argument lowering.
327*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerArguments() = 0;
328*03ce13f7SAndroid Build Coastguard Worker 
initNodeForLowering(CfgNode *)329*03ce13f7SAndroid Build Coastguard Worker   virtual void initNodeForLowering(CfgNode *) {}
330*03ce13f7SAndroid Build Coastguard Worker   virtual void addProlog(CfgNode *Node) = 0;
331*03ce13f7SAndroid Build Coastguard Worker   virtual void addEpilog(CfgNode *Node) = 0;
332*03ce13f7SAndroid Build Coastguard Worker 
333*03ce13f7SAndroid Build Coastguard Worker   /// Create a properly-typed "mov" instruction.  This is primarily for local
334*03ce13f7SAndroid Build Coastguard Worker   /// variable splitting.
createLoweredMove(Variable * Dest,Variable * SrcVar)335*03ce13f7SAndroid Build Coastguard Worker   virtual Inst *createLoweredMove(Variable *Dest, Variable *SrcVar) {
336*03ce13f7SAndroid Build Coastguard Worker     // TODO(stichnot): make pure virtual by implementing for all targets
337*03ce13f7SAndroid Build Coastguard Worker     (void)Dest;
338*03ce13f7SAndroid Build Coastguard Worker     (void)SrcVar;
339*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("createLoweredMove() unimplemented");
340*03ce13f7SAndroid Build Coastguard Worker     return nullptr;
341*03ce13f7SAndroid Build Coastguard Worker   }
342*03ce13f7SAndroid Build Coastguard Worker 
343*03ce13f7SAndroid Build Coastguard Worker   virtual ~TargetLowering() = default;
344*03ce13f7SAndroid Build Coastguard Worker 
345*03ce13f7SAndroid Build Coastguard Worker private:
346*03ce13f7SAndroid Build Coastguard Worker   /// This indicates whether we are in the genTargetHelperCalls phase, and
347*03ce13f7SAndroid Build Coastguard Worker   /// therefore can do things like scalarization.
348*03ce13f7SAndroid Build Coastguard Worker   bool GeneratingTargetHelpers = false;
349*03ce13f7SAndroid Build Coastguard Worker 
350*03ce13f7SAndroid Build Coastguard Worker protected:
351*03ce13f7SAndroid Build Coastguard Worker   explicit TargetLowering(Cfg *Func);
352*03ce13f7SAndroid Build Coastguard Worker   // Applies command line filters to TypeToRegisterSet array.
353*03ce13f7SAndroid Build Coastguard Worker   static void filterTypeToRegisterSet(
354*03ce13f7SAndroid Build Coastguard Worker       GlobalContext *Ctx, int32_t NumRegs, SmallBitVector TypeToRegisterSet[],
355*03ce13f7SAndroid Build Coastguard Worker       size_t TypeToRegisterSetSize,
356*03ce13f7SAndroid Build Coastguard Worker       std::function<std::string(RegNumT)> getRegName,
357*03ce13f7SAndroid Build Coastguard Worker       std::function<const char *(RegClass)> getRegClassName);
358*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerAlloca(const InstAlloca *Instr) = 0;
359*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerArithmetic(const InstArithmetic *Instr) = 0;
360*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerAssign(const InstAssign *Instr) = 0;
361*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerBr(const InstBr *Instr) = 0;
362*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerBreakpoint(const InstBreakpoint *Instr) = 0;
363*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerCall(const InstCall *Instr) = 0;
364*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerCast(const InstCast *Instr) = 0;
365*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerFcmp(const InstFcmp *Instr) = 0;
366*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerExtractElement(const InstExtractElement *Instr) = 0;
367*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerIcmp(const InstIcmp *Instr) = 0;
368*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerInsertElement(const InstInsertElement *Instr) = 0;
369*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerIntrinsic(const InstIntrinsic *Instr) = 0;
370*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerLoad(const InstLoad *Instr) = 0;
371*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerPhi(const InstPhi *Instr) = 0;
372*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerRet(const InstRet *Instr) = 0;
373*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerSelect(const InstSelect *Instr) = 0;
374*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerShuffleVector(const InstShuffleVector *Instr) = 0;
375*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerStore(const InstStore *Instr) = 0;
376*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerSwitch(const InstSwitch *Instr) = 0;
377*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerUnreachable(const InstUnreachable *Instr) = 0;
378*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerOther(const Inst *Instr);
379*03ce13f7SAndroid Build Coastguard Worker 
380*03ce13f7SAndroid Build Coastguard Worker   virtual void genTargetHelperCallFor(Inst *Instr) = 0;
381*03ce13f7SAndroid Build Coastguard Worker   virtual uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) = 0;
382*03ce13f7SAndroid Build Coastguard Worker 
383*03ce13f7SAndroid Build Coastguard Worker   /// Opportunity to modify other instructions to help Address Optimization
doAddressOptOther()384*03ce13f7SAndroid Build Coastguard Worker   virtual void doAddressOptOther() {}
doAddressOptLoad()385*03ce13f7SAndroid Build Coastguard Worker   virtual void doAddressOptLoad() {}
doAddressOptStore()386*03ce13f7SAndroid Build Coastguard Worker   virtual void doAddressOptStore() {}
doAddressOptLoadSubVector()387*03ce13f7SAndroid Build Coastguard Worker   virtual void doAddressOptLoadSubVector() {}
doAddressOptStoreSubVector()388*03ce13f7SAndroid Build Coastguard Worker   virtual void doAddressOptStoreSubVector() {}
doMockBoundsCheck(Operand *)389*03ce13f7SAndroid Build Coastguard Worker   virtual void doMockBoundsCheck(Operand *) {}
390*03ce13f7SAndroid Build Coastguard Worker   /// This gives the target an opportunity to post-process the lowered expansion
391*03ce13f7SAndroid Build Coastguard Worker   /// before returning.
postLower()392*03ce13f7SAndroid Build Coastguard Worker   virtual void postLower() {}
393*03ce13f7SAndroid Build Coastguard Worker 
394*03ce13f7SAndroid Build Coastguard Worker   /// When the SkipUnimplemented flag is set, addFakeDefUses() gets invoked by
395*03ce13f7SAndroid Build Coastguard Worker   /// the UnimplementedLoweringError macro to insert fake uses of all the
396*03ce13f7SAndroid Build Coastguard Worker   /// instruction variables and a fake def of the instruction dest, in order to
397*03ce13f7SAndroid Build Coastguard Worker   /// preserve integrity of liveness analysis.
398*03ce13f7SAndroid Build Coastguard Worker   void addFakeDefUses(const Inst *Instr);
399*03ce13f7SAndroid Build Coastguard Worker 
400*03ce13f7SAndroid Build Coastguard Worker   /// Find (non-SSA) instructions where the Dest variable appears in some source
401*03ce13f7SAndroid Build Coastguard Worker   /// operand, and set the IsDestRedefined flag.  This keeps liveness analysis
402*03ce13f7SAndroid Build Coastguard Worker   /// consistent.
403*03ce13f7SAndroid Build Coastguard Worker   void markRedefinitions();
404*03ce13f7SAndroid Build Coastguard Worker 
405*03ce13f7SAndroid Build Coastguard Worker   /// Make a pass over the Cfg to determine which variables need stack slots and
406*03ce13f7SAndroid Build Coastguard Worker   /// place them in a sorted list (SortedSpilledVariables). Among those, vars,
407*03ce13f7SAndroid Build Coastguard Worker   /// classify the spill variables as local to the basic block vs global
408*03ce13f7SAndroid Build Coastguard Worker   /// (multi-block) in order to compute the parameters GlobalsSize and
409*03ce13f7SAndroid Build Coastguard Worker   /// SpillAreaSizeBytes (represents locals or general vars if the coalescing of
410*03ce13f7SAndroid Build Coastguard Worker   /// locals is disallowed) along with alignments required for variables in each
411*03ce13f7SAndroid Build Coastguard Worker   /// area. We rely on accurate VMetadata in order to classify a variable as
412*03ce13f7SAndroid Build Coastguard Worker   /// global vs local (otherwise the variable is conservatively global). The
413*03ce13f7SAndroid Build Coastguard Worker   /// in-args should be initialized to 0.
414*03ce13f7SAndroid Build Coastguard Worker   ///
415*03ce13f7SAndroid Build Coastguard Worker   /// This is only a pre-pass and the actual stack slot assignment is handled
416*03ce13f7SAndroid Build Coastguard Worker   /// separately.
417*03ce13f7SAndroid Build Coastguard Worker   ///
418*03ce13f7SAndroid Build Coastguard Worker   /// There may be target-specific Variable types, which will be handled by
419*03ce13f7SAndroid Build Coastguard Worker   /// TargetVarHook. If the TargetVarHook returns true, then the variable is
420*03ce13f7SAndroid Build Coastguard Worker   /// skipped and not considered with the rest of the spilled variables.
421*03ce13f7SAndroid Build Coastguard Worker   void getVarStackSlotParams(VarList &SortedSpilledVariables,
422*03ce13f7SAndroid Build Coastguard Worker                              SmallBitVector &RegsUsed, size_t *GlobalsSize,
423*03ce13f7SAndroid Build Coastguard Worker                              size_t *SpillAreaSizeBytes,
424*03ce13f7SAndroid Build Coastguard Worker                              uint32_t *SpillAreaAlignmentBytes,
425*03ce13f7SAndroid Build Coastguard Worker                              uint32_t *LocalsSlotsAlignmentBytes,
426*03ce13f7SAndroid Build Coastguard Worker                              std::function<bool(Variable *)> TargetVarHook);
427*03ce13f7SAndroid Build Coastguard Worker 
428*03ce13f7SAndroid Build Coastguard Worker   /// Calculate the amount of padding needed to align the local and global areas
429*03ce13f7SAndroid Build Coastguard Worker   /// to the required alignment. This assumes the globals/locals layout used by
430*03ce13f7SAndroid Build Coastguard Worker   /// getVarStackSlotParams and assignVarStackSlots.
431*03ce13f7SAndroid Build Coastguard Worker   void alignStackSpillAreas(uint32_t SpillAreaStartOffset,
432*03ce13f7SAndroid Build Coastguard Worker                             uint32_t SpillAreaAlignmentBytes,
433*03ce13f7SAndroid Build Coastguard Worker                             size_t GlobalsSize,
434*03ce13f7SAndroid Build Coastguard Worker                             uint32_t LocalsSlotsAlignmentBytes,
435*03ce13f7SAndroid Build Coastguard Worker                             uint32_t *SpillAreaPaddingBytes,
436*03ce13f7SAndroid Build Coastguard Worker                             uint32_t *LocalsSlotsPaddingBytes);
437*03ce13f7SAndroid Build Coastguard Worker 
438*03ce13f7SAndroid Build Coastguard Worker   /// Make a pass through the SortedSpilledVariables and actually assign stack
439*03ce13f7SAndroid Build Coastguard Worker   /// slots. SpillAreaPaddingBytes takes into account stack alignment padding.
440*03ce13f7SAndroid Build Coastguard Worker   /// The SpillArea starts after that amount of padding. This matches the scheme
441*03ce13f7SAndroid Build Coastguard Worker   /// in getVarStackSlotParams, where there may be a separate multi-block global
442*03ce13f7SAndroid Build Coastguard Worker   /// var spill area and a local var spill area.
443*03ce13f7SAndroid Build Coastguard Worker   void assignVarStackSlots(VarList &SortedSpilledVariables,
444*03ce13f7SAndroid Build Coastguard Worker                            size_t SpillAreaPaddingBytes,
445*03ce13f7SAndroid Build Coastguard Worker                            size_t SpillAreaSizeBytes,
446*03ce13f7SAndroid Build Coastguard Worker                            size_t GlobalsAndSubsequentPaddingSize,
447*03ce13f7SAndroid Build Coastguard Worker                            bool UsesFramePointer);
448*03ce13f7SAndroid Build Coastguard Worker 
449*03ce13f7SAndroid Build Coastguard Worker   /// Sort the variables in Source based on required alignment. The variables
450*03ce13f7SAndroid Build Coastguard Worker   /// with the largest alignment need are placed in the front of the Dest list.
451*03ce13f7SAndroid Build Coastguard Worker   void sortVarsByAlignment(VarList &Dest, const VarList &Source) const;
452*03ce13f7SAndroid Build Coastguard Worker 
453*03ce13f7SAndroid Build Coastguard Worker   InstCall *makeHelperCall(RuntimeHelper FuncID, Variable *Dest, SizeT MaxSrcs);
454*03ce13f7SAndroid Build Coastguard Worker 
_set_dest_redefined()455*03ce13f7SAndroid Build Coastguard Worker   void _set_dest_redefined() { Context.getLastInserted()->setDestRedefined(); }
456*03ce13f7SAndroid Build Coastguard Worker 
457*03ce13f7SAndroid Build Coastguard Worker   bool shouldOptimizeMemIntrins();
458*03ce13f7SAndroid Build Coastguard Worker 
459*03ce13f7SAndroid Build Coastguard Worker   void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest,
460*03ce13f7SAndroid Build Coastguard Worker                            Operand *Src0, Operand *Src1);
461*03ce13f7SAndroid Build Coastguard Worker 
462*03ce13f7SAndroid Build Coastguard Worker   /// Generalizes scalarizeArithmetic to support other instruction types.
463*03ce13f7SAndroid Build Coastguard Worker   ///
464*03ce13f7SAndroid Build Coastguard Worker   /// insertScalarInstruction is a function-like object with signature
465*03ce13f7SAndroid Build Coastguard Worker   /// (Variable *Dest, Variable *Src0, Variable *Src1) -> Instr *.
466*03ce13f7SAndroid Build Coastguard Worker   template <typename... Operands,
467*03ce13f7SAndroid Build Coastguard Worker             typename F = std::function<Inst *(Variable *, Operands *...)>>
scalarizeInstruction(Variable * Dest,F insertScalarInstruction,Operands * ...Srcs)468*03ce13f7SAndroid Build Coastguard Worker   void scalarizeInstruction(Variable *Dest, F insertScalarInstruction,
469*03ce13f7SAndroid Build Coastguard Worker                             Operands *...Srcs) {
470*03ce13f7SAndroid Build Coastguard Worker     assert(GeneratingTargetHelpers &&
471*03ce13f7SAndroid Build Coastguard Worker            "scalarizeInstruction called during incorrect phase");
472*03ce13f7SAndroid Build Coastguard Worker     const Type DestTy = Dest->getType();
473*03ce13f7SAndroid Build Coastguard Worker     assert(isVectorType(DestTy));
474*03ce13f7SAndroid Build Coastguard Worker     const Type DestElementTy = typeElementType(DestTy);
475*03ce13f7SAndroid Build Coastguard Worker     const SizeT NumElements = typeNumElements(DestTy);
476*03ce13f7SAndroid Build Coastguard Worker 
477*03ce13f7SAndroid Build Coastguard Worker     Variable *T = Func->makeVariable(DestTy);
478*03ce13f7SAndroid Build Coastguard Worker     if (auto *VarVecOn32 = llvm::dyn_cast<VariableVecOn32>(T)) {
479*03ce13f7SAndroid Build Coastguard Worker       VarVecOn32->initVecElement(Func);
480*03ce13f7SAndroid Build Coastguard Worker       auto *Undef = ConstantUndef::create(Ctx, DestTy);
481*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstAssign>(T, Undef);
482*03ce13f7SAndroid Build Coastguard Worker     } else {
483*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstFakeDef>(T);
484*03ce13f7SAndroid Build Coastguard Worker     }
485*03ce13f7SAndroid Build Coastguard Worker 
486*03ce13f7SAndroid Build Coastguard Worker     for (SizeT I = 0; I < NumElements; ++I) {
487*03ce13f7SAndroid Build Coastguard Worker       auto *Index = Ctx->getConstantInt32(I);
488*03ce13f7SAndroid Build Coastguard Worker 
489*03ce13f7SAndroid Build Coastguard Worker       auto makeExtractThunk = [this, Index, NumElements](Operand *Src) {
490*03ce13f7SAndroid Build Coastguard Worker         return [this, Index, NumElements, Src]() {
491*03ce13f7SAndroid Build Coastguard Worker           (void)NumElements;
492*03ce13f7SAndroid Build Coastguard Worker           assert(typeNumElements(Src->getType()) == NumElements);
493*03ce13f7SAndroid Build Coastguard Worker 
494*03ce13f7SAndroid Build Coastguard Worker           const auto ElementTy = typeElementType(Src->getType());
495*03ce13f7SAndroid Build Coastguard Worker           auto *Op = Func->makeVariable(ElementTy);
496*03ce13f7SAndroid Build Coastguard Worker           Context.insert<InstExtractElement>(Op, Src, Index);
497*03ce13f7SAndroid Build Coastguard Worker           return Op;
498*03ce13f7SAndroid Build Coastguard Worker         };
499*03ce13f7SAndroid Build Coastguard Worker       };
500*03ce13f7SAndroid Build Coastguard Worker 
501*03ce13f7SAndroid Build Coastguard Worker       // Perform the operation as a scalar operation.
502*03ce13f7SAndroid Build Coastguard Worker       auto *Res = Func->makeVariable(DestElementTy);
503*03ce13f7SAndroid Build Coastguard Worker       auto *Arith = applyToThunkedArgs(insertScalarInstruction, Res,
504*03ce13f7SAndroid Build Coastguard Worker                                        makeExtractThunk(Srcs)...);
505*03ce13f7SAndroid Build Coastguard Worker       genTargetHelperCallFor(Arith);
506*03ce13f7SAndroid Build Coastguard Worker 
507*03ce13f7SAndroid Build Coastguard Worker       Variable *DestT = Func->makeVariable(DestTy);
508*03ce13f7SAndroid Build Coastguard Worker       Context.insert<InstInsertElement>(DestT, T, Res, Index);
509*03ce13f7SAndroid Build Coastguard Worker       T = DestT;
510*03ce13f7SAndroid Build Coastguard Worker     }
511*03ce13f7SAndroid Build Coastguard Worker     Context.insert<InstAssign>(Dest, T);
512*03ce13f7SAndroid Build Coastguard Worker   }
513*03ce13f7SAndroid Build Coastguard Worker 
514*03ce13f7SAndroid Build Coastguard Worker   // applyToThunkedArgs is used by scalarizeInstruction. Ideally, we would just
515*03ce13f7SAndroid Build Coastguard Worker   // call insertScalarInstruction(Res, Srcs...), but C++ does not specify
516*03ce13f7SAndroid Build Coastguard Worker   // evaluation order which means this leads to an unpredictable final
517*03ce13f7SAndroid Build Coastguard Worker   // output. Instead, we wrap each of the Srcs in a thunk and these
518*03ce13f7SAndroid Build Coastguard Worker   // applyToThunkedArgs functions apply the thunks in a well defined order so we
519*03ce13f7SAndroid Build Coastguard Worker   // still get well-defined output.
applyToThunkedArgs(std::function<Inst * (Variable *,Variable *)> insertScalarInstruction,Variable * Res,std::function<Variable * ()> thunk0)520*03ce13f7SAndroid Build Coastguard Worker   Inst *applyToThunkedArgs(
521*03ce13f7SAndroid Build Coastguard Worker       std::function<Inst *(Variable *, Variable *)> insertScalarInstruction,
522*03ce13f7SAndroid Build Coastguard Worker       Variable *Res, std::function<Variable *()> thunk0) {
523*03ce13f7SAndroid Build Coastguard Worker     auto *Src0 = thunk0();
524*03ce13f7SAndroid Build Coastguard Worker     return insertScalarInstruction(Res, Src0);
525*03ce13f7SAndroid Build Coastguard Worker   }
526*03ce13f7SAndroid Build Coastguard Worker 
527*03ce13f7SAndroid Build Coastguard Worker   Inst *
applyToThunkedArgs(std::function<Inst * (Variable *,Variable *,Variable *)> insertScalarInstruction,Variable * Res,std::function<Variable * ()> thunk0,std::function<Variable * ()> thunk1)528*03ce13f7SAndroid Build Coastguard Worker   applyToThunkedArgs(std::function<Inst *(Variable *, Variable *, Variable *)>
529*03ce13f7SAndroid Build Coastguard Worker                          insertScalarInstruction,
530*03ce13f7SAndroid Build Coastguard Worker                      Variable *Res, std::function<Variable *()> thunk0,
531*03ce13f7SAndroid Build Coastguard Worker                      std::function<Variable *()> thunk1) {
532*03ce13f7SAndroid Build Coastguard Worker     auto *Src0 = thunk0();
533*03ce13f7SAndroid Build Coastguard Worker     auto *Src1 = thunk1();
534*03ce13f7SAndroid Build Coastguard Worker     return insertScalarInstruction(Res, Src0, Src1);
535*03ce13f7SAndroid Build Coastguard Worker   }
536*03ce13f7SAndroid Build Coastguard Worker 
applyToThunkedArgs(std::function<Inst * (Variable *,Variable *,Variable *,Variable *)> insertScalarInstruction,Variable * Res,std::function<Variable * ()> thunk0,std::function<Variable * ()> thunk1,std::function<Variable * ()> thunk2)537*03ce13f7SAndroid Build Coastguard Worker   Inst *applyToThunkedArgs(
538*03ce13f7SAndroid Build Coastguard Worker       std::function<Inst *(Variable *, Variable *, Variable *, Variable *)>
539*03ce13f7SAndroid Build Coastguard Worker           insertScalarInstruction,
540*03ce13f7SAndroid Build Coastguard Worker       Variable *Res, std::function<Variable *()> thunk0,
541*03ce13f7SAndroid Build Coastguard Worker       std::function<Variable *()> thunk1, std::function<Variable *()> thunk2) {
542*03ce13f7SAndroid Build Coastguard Worker     auto *Src0 = thunk0();
543*03ce13f7SAndroid Build Coastguard Worker     auto *Src1 = thunk1();
544*03ce13f7SAndroid Build Coastguard Worker     auto *Src2 = thunk2();
545*03ce13f7SAndroid Build Coastguard Worker     return insertScalarInstruction(Res, Src0, Src1, Src2);
546*03ce13f7SAndroid Build Coastguard Worker   }
547*03ce13f7SAndroid Build Coastguard Worker 
548*03ce13f7SAndroid Build Coastguard Worker   Cfg *Func;
549*03ce13f7SAndroid Build Coastguard Worker   GlobalContext *Ctx;
550*03ce13f7SAndroid Build Coastguard Worker   bool HasComputedFrame = false;
551*03ce13f7SAndroid Build Coastguard Worker   bool CallsReturnsTwice = false;
552*03ce13f7SAndroid Build Coastguard Worker   SizeT NextLabelNumber = 0;
553*03ce13f7SAndroid Build Coastguard Worker   SizeT NextJumpTableNumber = 0;
554*03ce13f7SAndroid Build Coastguard Worker   LoweringContext Context;
555*03ce13f7SAndroid Build Coastguard Worker };
556*03ce13f7SAndroid Build Coastguard Worker 
557*03ce13f7SAndroid Build Coastguard Worker /// TargetDataLowering is used for "lowering" data including initializers for
558*03ce13f7SAndroid Build Coastguard Worker /// global variables, and the internal constant pools. It is separated out from
559*03ce13f7SAndroid Build Coastguard Worker /// TargetLowering because it does not require a Cfg.
560*03ce13f7SAndroid Build Coastguard Worker class TargetDataLowering {
561*03ce13f7SAndroid Build Coastguard Worker   TargetDataLowering() = delete;
562*03ce13f7SAndroid Build Coastguard Worker   TargetDataLowering(const TargetDataLowering &) = delete;
563*03ce13f7SAndroid Build Coastguard Worker   TargetDataLowering &operator=(const TargetDataLowering &) = delete;
564*03ce13f7SAndroid Build Coastguard Worker 
565*03ce13f7SAndroid Build Coastguard Worker public:
566*03ce13f7SAndroid Build Coastguard Worker   static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx);
567*03ce13f7SAndroid Build Coastguard Worker   virtual ~TargetDataLowering();
568*03ce13f7SAndroid Build Coastguard Worker 
569*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerGlobals(const VariableDeclarationList &Vars,
570*03ce13f7SAndroid Build Coastguard Worker                             const std::string &SectionSuffix) = 0;
571*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerConstants() = 0;
572*03ce13f7SAndroid Build Coastguard Worker   virtual void lowerJumpTables() = 0;
emitTargetRODataSections()573*03ce13f7SAndroid Build Coastguard Worker   virtual void emitTargetRODataSections() {}
574*03ce13f7SAndroid Build Coastguard Worker 
575*03ce13f7SAndroid Build Coastguard Worker protected:
576*03ce13f7SAndroid Build Coastguard Worker   void emitGlobal(const VariableDeclaration &Var,
577*03ce13f7SAndroid Build Coastguard Worker                   const std::string &SectionSuffix);
578*03ce13f7SAndroid Build Coastguard Worker 
579*03ce13f7SAndroid Build Coastguard Worker   /// For now, we assume .long is the right directive for emitting 4 byte emit
580*03ce13f7SAndroid Build Coastguard Worker   /// global relocations. However, LLVM MIPS usually uses .4byte instead.
581*03ce13f7SAndroid Build Coastguard Worker   /// Perhaps there is some difference when the location is unaligned.
getEmit32Directive()582*03ce13f7SAndroid Build Coastguard Worker   static const char *getEmit32Directive() { return ".long"; }
583*03ce13f7SAndroid Build Coastguard Worker 
TargetDataLowering(GlobalContext * Ctx)584*03ce13f7SAndroid Build Coastguard Worker   explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
585*03ce13f7SAndroid Build Coastguard Worker   GlobalContext *Ctx;
586*03ce13f7SAndroid Build Coastguard Worker };
587*03ce13f7SAndroid Build Coastguard Worker 
588*03ce13f7SAndroid Build Coastguard Worker /// TargetHeaderLowering is used to "lower" the header of an output file. It
589*03ce13f7SAndroid Build Coastguard Worker /// writes out the target-specific header attributes. E.g., for ARM this writes
590*03ce13f7SAndroid Build Coastguard Worker /// out the build attributes (float ABI, etc.).
591*03ce13f7SAndroid Build Coastguard Worker class TargetHeaderLowering {
592*03ce13f7SAndroid Build Coastguard Worker   TargetHeaderLowering() = delete;
593*03ce13f7SAndroid Build Coastguard Worker   TargetHeaderLowering(const TargetHeaderLowering &) = delete;
594*03ce13f7SAndroid Build Coastguard Worker   TargetHeaderLowering &operator=(const TargetHeaderLowering &) = delete;
595*03ce13f7SAndroid Build Coastguard Worker 
596*03ce13f7SAndroid Build Coastguard Worker public:
597*03ce13f7SAndroid Build Coastguard Worker   static std::unique_ptr<TargetHeaderLowering>
598*03ce13f7SAndroid Build Coastguard Worker   createLowering(GlobalContext *Ctx);
599*03ce13f7SAndroid Build Coastguard Worker   virtual ~TargetHeaderLowering();
600*03ce13f7SAndroid Build Coastguard Worker 
lower()601*03ce13f7SAndroid Build Coastguard Worker   virtual void lower() {}
602*03ce13f7SAndroid Build Coastguard Worker 
603*03ce13f7SAndroid Build Coastguard Worker protected:
TargetHeaderLowering(GlobalContext * Ctx)604*03ce13f7SAndroid Build Coastguard Worker   explicit TargetHeaderLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
605*03ce13f7SAndroid Build Coastguard Worker   GlobalContext *Ctx;
606*03ce13f7SAndroid Build Coastguard Worker };
607*03ce13f7SAndroid Build Coastguard Worker 
608*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
609*03ce13f7SAndroid Build Coastguard Worker 
610*03ce13f7SAndroid Build Coastguard Worker #endif // SUBZERO_SRC_ICETARGETLOWERING_H
611