| OLD | NEW |
| 1 //===- subzero/src/IceTargetLowering.h - Lowering interface -----*- C++ -*-===// | 1 //===- subzero/src/IceTargetLowering.h - Lowering interface -----*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 // | 9 /// |
| 10 // This file declares the TargetLowering, LoweringContext, and | 10 /// \file |
| 11 // TargetDataLowering classes. TargetLowering is an abstract class | 11 /// This file declares the TargetLowering, LoweringContext, and |
| 12 // used to drive the translation/lowering process. LoweringContext | 12 /// TargetDataLowering classes. TargetLowering is an abstract class |
| 13 // maintains a context for lowering each instruction, offering | 13 /// used to drive the translation/lowering process. LoweringContext |
| 14 // conveniences such as iterating over non-deleted instructions. | 14 /// maintains a context for lowering each instruction, offering |
| 15 // TargetDataLowering is an abstract class used to drive the | 15 /// conveniences such as iterating over non-deleted instructions. |
| 16 // lowering/emission of global initializers, external global | 16 /// TargetDataLowering is an abstract class used to drive the |
| 17 // declarations, and internal constant pools. | 17 /// lowering/emission of global initializers, external global |
| 18 // | 18 /// declarations, and internal constant pools. |
| 19 /// |
| 19 //===----------------------------------------------------------------------===// | 20 //===----------------------------------------------------------------------===// |
| 20 | 21 |
| 21 #ifndef SUBZERO_SRC_ICETARGETLOWERING_H | 22 #ifndef SUBZERO_SRC_ICETARGETLOWERING_H |
| 22 #define SUBZERO_SRC_ICETARGETLOWERING_H | 23 #define SUBZERO_SRC_ICETARGETLOWERING_H |
| 23 | 24 |
| 24 #include "IceDefs.h" | 25 #include "IceDefs.h" |
| 25 #include "IceInst.h" // for the names of the Inst subtypes | 26 #include "IceInst.h" // for the names of the Inst subtypes |
| 26 #include "IceOperand.h" | 27 #include "IceOperand.h" |
| 27 #include "IceTypes.h" | 28 #include "IceTypes.h" |
| 28 | 29 |
| 29 namespace Ice { | 30 namespace Ice { |
| 30 | 31 |
| 31 // LoweringContext makes it easy to iterate through non-deleted | 32 /// LoweringContext makes it easy to iterate through non-deleted |
| 32 // instructions in a node, and insert new (lowered) instructions at | 33 /// instructions in a node, and insert new (lowered) instructions at |
| 33 // the current point. Along with the instruction list container and | 34 /// the current point. Along with the instruction list container and |
| 34 // associated iterators, it holds the current node, which is needed | 35 /// associated iterators, it holds the current node, which is needed |
| 35 // when inserting new instructions in order to track whether variables | 36 /// when inserting new instructions in order to track whether variables |
| 36 // are used as single-block or multi-block. | 37 /// are used as single-block or multi-block. |
| 37 class LoweringContext { | 38 class LoweringContext { |
| 38 LoweringContext(const LoweringContext &) = delete; | 39 LoweringContext(const LoweringContext &) = delete; |
| 39 LoweringContext &operator=(const LoweringContext &) = delete; | 40 LoweringContext &operator=(const LoweringContext &) = delete; |
| 40 | 41 |
| 41 public: | 42 public: |
| 42 LoweringContext() = default; | 43 LoweringContext() = default; |
| 43 ~LoweringContext() = default; | 44 ~LoweringContext() = default; |
| 44 void init(CfgNode *Node); | 45 void init(CfgNode *Node); |
| 45 Inst *getNextInst() const { | 46 Inst *getNextInst() const { |
| 46 if (Next == End) | 47 if (Next == End) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 59 InstList::iterator getNext() const { return Next; } | 60 InstList::iterator getNext() const { return Next; } |
| 60 InstList::iterator getEnd() const { return End; } | 61 InstList::iterator getEnd() const { return End; } |
| 61 void insert(Inst *Inst); | 62 void insert(Inst *Inst); |
| 62 Inst *getLastInserted() const; | 63 Inst *getLastInserted() const; |
| 63 void advanceCur() { Cur = Next; } | 64 void advanceCur() { Cur = Next; } |
| 64 void advanceNext() { advanceForward(Next); } | 65 void advanceNext() { advanceForward(Next); } |
| 65 void rewind(); | 66 void rewind(); |
| 66 void setInsertPoint(const InstList::iterator &Position) { Next = Position; } | 67 void setInsertPoint(const InstList::iterator &Position) { Next = Position; } |
| 67 | 68 |
| 68 private: | 69 private: |
| 69 // Node is the argument to Inst::updateVars(). | 70 /// Node is the argument to Inst::updateVars(). |
| 70 CfgNode *Node = nullptr; | 71 CfgNode *Node = nullptr; |
| 71 Inst *LastInserted = nullptr; | 72 Inst *LastInserted = nullptr; |
| 72 // Cur points to the current instruction being considered. It is | 73 /// Cur points to the current instruction being considered. It is |
| 73 // guaranteed to point to a non-deleted instruction, or to be End. | 74 /// guaranteed to point to a non-deleted instruction, or to be End. |
| 74 InstList::iterator Cur; | 75 InstList::iterator Cur; |
| 75 // Next doubles as a pointer to the next valid instruction (if any), | 76 /// Next doubles as a pointer to the next valid instruction (if any), |
| 76 // and the new-instruction insertion point. It is also updated for | 77 /// and the new-instruction insertion point. It is also updated for |
| 77 // the caller in case the lowering consumes more than one high-level | 78 /// the caller in case the lowering consumes more than one high-level |
| 78 // instruction. It is guaranteed to point to a non-deleted | 79 /// instruction. It is guaranteed to point to a non-deleted |
| 79 // instruction after Cur, or to be End. TODO: Consider separating | 80 /// instruction after Cur, or to be End. TODO: Consider separating |
| 80 // the notion of "next valid instruction" and "new instruction | 81 /// the notion of "next valid instruction" and "new instruction |
| 81 // insertion point", to avoid confusion when previously-deleted | 82 /// insertion point", to avoid confusion when previously-deleted |
| 82 // instructions come between the two points. | 83 /// instructions come between the two points. |
| 83 InstList::iterator Next; | 84 InstList::iterator Next; |
| 84 // Begin is a copy of Insts.begin(), used if iterators are moved backward. | 85 /// Begin is a copy of Insts.begin(), used if iterators are moved backward. |
| 85 InstList::iterator Begin; | 86 InstList::iterator Begin; |
| 86 // End is a copy of Insts.end(), used if Next needs to be advanced. | 87 /// End is a copy of Insts.end(), used if Next needs to be advanced. |
| 87 InstList::iterator End; | 88 InstList::iterator End; |
| 88 | 89 |
| 89 void skipDeleted(InstList::iterator &I) const; | 90 void skipDeleted(InstList::iterator &I) const; |
| 90 void advanceForward(InstList::iterator &I) const; | 91 void advanceForward(InstList::iterator &I) const; |
| 91 }; | 92 }; |
| 92 | 93 |
| 93 class TargetLowering { | 94 class TargetLowering { |
| 94 TargetLowering() = delete; | 95 TargetLowering() = delete; |
| 95 TargetLowering(const TargetLowering &) = delete; | 96 TargetLowering(const TargetLowering &) = delete; |
| 96 TargetLowering &operator=(const TargetLowering &) = delete; | 97 TargetLowering &operator=(const TargetLowering &) = delete; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 122 virtual void translateO0() { | 123 virtual void translateO0() { |
| 123 Func->setError("Target doesn't specify O0 lowering steps."); | 124 Func->setError("Target doesn't specify O0 lowering steps."); |
| 124 } | 125 } |
| 125 virtual void translateO1() { | 126 virtual void translateO1() { |
| 126 Func->setError("Target doesn't specify O1 lowering steps."); | 127 Func->setError("Target doesn't specify O1 lowering steps."); |
| 127 } | 128 } |
| 128 virtual void translateO2() { | 129 virtual void translateO2() { |
| 129 Func->setError("Target doesn't specify O2 lowering steps."); | 130 Func->setError("Target doesn't specify O2 lowering steps."); |
| 130 } | 131 } |
| 131 | 132 |
| 132 // Tries to do address mode optimization on a single instruction. | 133 /// Tries to do address mode optimization on a single instruction. |
| 133 void doAddressOpt(); | 134 void doAddressOpt(); |
| 134 // Randomly insert NOPs. | 135 /// Randomly insert NOPs. |
| 135 void doNopInsertion(); | 136 void doNopInsertion(); |
| 136 // Lowers a single non-Phi instruction. | 137 /// Lowers a single non-Phi instruction. |
| 137 void lower(); | 138 void lower(); |
| 138 // Does preliminary lowering of the set of Phi instructions in the | 139 /// Does preliminary lowering of the set of Phi instructions in the |
| 139 // current node. The main intention is to do what's needed to keep | 140 /// current node. The main intention is to do what's needed to keep |
| 140 // the unlowered Phi instructions consistent with the lowered | 141 /// the unlowered Phi instructions consistent with the lowered |
| 141 // non-Phi instructions, e.g. to lower 64-bit operands on a 32-bit | 142 /// non-Phi instructions, e.g. to lower 64-bit operands on a 32-bit |
| 142 // target. | 143 /// target. |
| 143 virtual void prelowerPhis() {} | 144 virtual void prelowerPhis() {} |
| 144 // Lowers a list of "parallel" assignment instructions representing | 145 /// Lowers a list of "parallel" assignment instructions representing |
| 145 // a topological sort of the Phi instructions. | 146 /// a topological sort of the Phi instructions. |
| 146 virtual void lowerPhiAssignments(CfgNode *Node, | 147 virtual void lowerPhiAssignments(CfgNode *Node, |
| 147 const AssignList &Assignments) = 0; | 148 const AssignList &Assignments) = 0; |
| 148 // Tries to do branch optimization on a single instruction. Returns | 149 /// Tries to do branch optimization on a single instruction. Returns |
| 149 // true if some optimization was done. | 150 /// true if some optimization was done. |
| 150 virtual bool doBranchOpt(Inst * /*I*/, const CfgNode * /*NextNode*/) { | 151 virtual bool doBranchOpt(Inst * /*I*/, const CfgNode * /*NextNode*/) { |
| 151 return false; | 152 return false; |
| 152 } | 153 } |
| 153 | 154 |
| 154 virtual SizeT getNumRegisters() const = 0; | 155 virtual SizeT getNumRegisters() const = 0; |
| 155 // Returns a variable pre-colored to the specified physical | 156 /// Returns a variable pre-colored to the specified physical |
| 156 // register. This is generally used to get very direct access to | 157 /// register. This is generally used to get very direct access to |
| 157 // the register such as in the prolog or epilog or for marking | 158 /// the register such as in the prolog or epilog or for marking |
| 158 // scratch registers as killed by a call. If a Type is not | 159 /// scratch registers as killed by a call. If a Type is not |
| 159 // provided, a target-specific default type is used. | 160 /// provided, a target-specific default type is used. |
| 160 virtual Variable *getPhysicalRegister(SizeT RegNum, | 161 virtual Variable *getPhysicalRegister(SizeT RegNum, |
| 161 Type Ty = IceType_void) = 0; | 162 Type Ty = IceType_void) = 0; |
| 162 // Returns a printable name for the register. | 163 /// Returns a printable name for the register. |
| 163 virtual IceString getRegName(SizeT RegNum, Type Ty) const = 0; | 164 virtual IceString getRegName(SizeT RegNum, Type Ty) const = 0; |
| 164 | 165 |
| 165 virtual bool hasFramePointer() const { return false; } | 166 virtual bool hasFramePointer() const { return false; } |
| 166 virtual SizeT getFrameOrStackReg() const = 0; | 167 virtual SizeT getFrameOrStackReg() const = 0; |
| 167 virtual size_t typeWidthInBytesOnStack(Type Ty) const = 0; | 168 virtual size_t typeWidthInBytesOnStack(Type Ty) const = 0; |
| 168 | 169 |
| 169 bool hasComputedFrame() const { return HasComputedFrame; } | 170 bool hasComputedFrame() const { return HasComputedFrame; } |
| 170 // Returns true if this function calls a function that has the | 171 /// Returns true if this function calls a function that has the |
| 171 // "returns twice" attribute. | 172 /// "returns twice" attribute. |
| 172 bool callsReturnsTwice() const { return CallsReturnsTwice; } | 173 bool callsReturnsTwice() const { return CallsReturnsTwice; } |
| 173 void setCallsReturnsTwice(bool RetTwice) { CallsReturnsTwice = RetTwice; } | 174 void setCallsReturnsTwice(bool RetTwice) { CallsReturnsTwice = RetTwice; } |
| 174 int32_t getStackAdjustment() const { return StackAdjustment; } | 175 int32_t getStackAdjustment() const { return StackAdjustment; } |
| 175 void updateStackAdjustment(int32_t Offset) { StackAdjustment += Offset; } | 176 void updateStackAdjustment(int32_t Offset) { StackAdjustment += Offset; } |
| 176 void resetStackAdjustment() { StackAdjustment = 0; } | 177 void resetStackAdjustment() { StackAdjustment = 0; } |
| 177 SizeT makeNextLabelNumber() { return NextLabelNumber++; } | 178 SizeT makeNextLabelNumber() { return NextLabelNumber++; } |
| 178 LoweringContext &getContext() { return Context; } | 179 LoweringContext &getContext() { return Context; } |
| 179 | 180 |
| 180 enum RegSet { | 181 enum RegSet { |
| 181 RegSet_None = 0, | 182 RegSet_None = 0, |
| 182 RegSet_CallerSave = 1 << 0, | 183 RegSet_CallerSave = 1 << 0, |
| 183 RegSet_CalleeSave = 1 << 1, | 184 RegSet_CalleeSave = 1 << 1, |
| 184 RegSet_StackPointer = 1 << 2, | 185 RegSet_StackPointer = 1 << 2, |
| 185 RegSet_FramePointer = 1 << 3, | 186 RegSet_FramePointer = 1 << 3, |
| 186 RegSet_All = ~RegSet_None | 187 RegSet_All = ~RegSet_None |
| 187 }; | 188 }; |
| 188 typedef uint32_t RegSetMask; | 189 typedef uint32_t RegSetMask; |
| 189 | 190 |
| 190 virtual llvm::SmallBitVector getRegisterSet(RegSetMask Include, | 191 virtual llvm::SmallBitVector getRegisterSet(RegSetMask Include, |
| 191 RegSetMask Exclude) const = 0; | 192 RegSetMask Exclude) const = 0; |
| 192 virtual const llvm::SmallBitVector &getRegisterSetForType(Type Ty) const = 0; | 193 virtual const llvm::SmallBitVector &getRegisterSetForType(Type Ty) const = 0; |
| 193 void regAlloc(RegAllocKind Kind); | 194 void regAlloc(RegAllocKind Kind); |
| 194 | 195 |
| 195 virtual void makeRandomRegisterPermutation( | 196 virtual void makeRandomRegisterPermutation( |
| 196 llvm::SmallVectorImpl<int32_t> &Permutation, | 197 llvm::SmallVectorImpl<int32_t> &Permutation, |
| 197 const llvm::SmallBitVector &ExcludeRegisters) const = 0; | 198 const llvm::SmallBitVector &ExcludeRegisters) const = 0; |
| 198 | 199 |
| 199 // Save/restore any mutable state for the situation where code | 200 /// Save/restore any mutable state for the situation where code |
| 200 // emission needs multiple passes, such as sandboxing or relaxation. | 201 /// emission needs multiple passes, such as sandboxing or relaxation. |
| 201 // Subclasses may provide their own implementation, but should be | 202 /// Subclasses may provide their own implementation, but should be |
| 202 // sure to also call the parent class's methods. | 203 /// sure to also call the parent class's methods. |
| 203 virtual void snapshotEmitState() { | 204 virtual void snapshotEmitState() { |
| 204 SnapshotStackAdjustment = StackAdjustment; | 205 SnapshotStackAdjustment = StackAdjustment; |
| 205 } | 206 } |
| 206 virtual void rollbackEmitState() { | 207 virtual void rollbackEmitState() { |
| 207 StackAdjustment = SnapshotStackAdjustment; | 208 StackAdjustment = SnapshotStackAdjustment; |
| 208 } | 209 } |
| 209 | 210 |
| 210 virtual void emitVariable(const Variable *Var) const = 0; | 211 virtual void emitVariable(const Variable *Var) const = 0; |
| 211 | 212 |
| 212 void emitWithoutPrefix(const ConstantRelocatable *CR) const; | 213 void emitWithoutPrefix(const ConstantRelocatable *CR) const; |
| 213 void emit(const ConstantRelocatable *CR) const; | 214 void emit(const ConstantRelocatable *CR) const; |
| 214 virtual const char *getConstantPrefix() const = 0; | 215 virtual const char *getConstantPrefix() const = 0; |
| 215 | 216 |
| 216 virtual void emit(const ConstantUndef *C) const = 0; | 217 virtual void emit(const ConstantUndef *C) const = 0; |
| 217 virtual void emit(const ConstantInteger32 *C) const = 0; | 218 virtual void emit(const ConstantInteger32 *C) const = 0; |
| 218 virtual void emit(const ConstantInteger64 *C) const = 0; | 219 virtual void emit(const ConstantInteger64 *C) const = 0; |
| 219 virtual void emit(const ConstantFloat *C) const = 0; | 220 virtual void emit(const ConstantFloat *C) const = 0; |
| 220 virtual void emit(const ConstantDouble *C) const = 0; | 221 virtual void emit(const ConstantDouble *C) const = 0; |
| 221 | 222 |
| 222 // Performs target-specific argument lowering. | 223 /// Performs target-specific argument lowering. |
| 223 virtual void lowerArguments() = 0; | 224 virtual void lowerArguments() = 0; |
| 224 | 225 |
| 225 virtual void initNodeForLowering(CfgNode *) {} | 226 virtual void initNodeForLowering(CfgNode *) {} |
| 226 virtual void addProlog(CfgNode *Node) = 0; | 227 virtual void addProlog(CfgNode *Node) = 0; |
| 227 virtual void addEpilog(CfgNode *Node) = 0; | 228 virtual void addEpilog(CfgNode *Node) = 0; |
| 228 | 229 |
| 229 virtual ~TargetLowering() = default; | 230 virtual ~TargetLowering() = default; |
| 230 | 231 |
| 231 protected: | 232 protected: |
| 232 explicit TargetLowering(Cfg *Func); | 233 explicit TargetLowering(Cfg *Func); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 246 virtual void lowerRet(const InstRet *Inst) = 0; | 247 virtual void lowerRet(const InstRet *Inst) = 0; |
| 247 virtual void lowerSelect(const InstSelect *Inst) = 0; | 248 virtual void lowerSelect(const InstSelect *Inst) = 0; |
| 248 virtual void lowerStore(const InstStore *Inst) = 0; | 249 virtual void lowerStore(const InstStore *Inst) = 0; |
| 249 virtual void lowerSwitch(const InstSwitch *Inst) = 0; | 250 virtual void lowerSwitch(const InstSwitch *Inst) = 0; |
| 250 virtual void lowerUnreachable(const InstUnreachable *Inst) = 0; | 251 virtual void lowerUnreachable(const InstUnreachable *Inst) = 0; |
| 251 virtual void lowerOther(const Inst *Instr); | 252 virtual void lowerOther(const Inst *Instr); |
| 252 | 253 |
| 253 virtual void doAddressOptLoad() {} | 254 virtual void doAddressOptLoad() {} |
| 254 virtual void doAddressOptStore() {} | 255 virtual void doAddressOptStore() {} |
| 255 virtual void randomlyInsertNop(float Probability) = 0; | 256 virtual void randomlyInsertNop(float Probability) = 0; |
| 256 // This gives the target an opportunity to post-process the lowered | 257 /// This gives the target an opportunity to post-process the lowered |
| 257 // expansion before returning. | 258 /// expansion before returning. |
| 258 virtual void postLower() {} | 259 virtual void postLower() {} |
| 259 | 260 |
| 260 // Find two-address non-SSA instructions and set the DestNonKillable flag | 261 /// Find two-address non-SSA instructions and set the DestNonKillable flag |
| 261 // to keep liveness analysis consistent. | 262 /// to keep liveness analysis consistent. |
| 262 void inferTwoAddress(); | 263 void inferTwoAddress(); |
| 263 | 264 |
| 264 // Make a pass over the Cfg to determine which variables need stack slots | 265 /// Make a pass over the Cfg to determine which variables need stack slots |
| 265 // and place them in a sorted list (SortedSpilledVariables). Among those, | 266 /// and place them in a sorted list (SortedSpilledVariables). Among those, |
| 266 // vars, classify the spill variables as local to the basic block vs | 267 /// vars, classify the spill variables as local to the basic block vs |
| 267 // global (multi-block) in order to compute the parameters GlobalsSize | 268 /// global (multi-block) in order to compute the parameters GlobalsSize |
| 268 // and SpillAreaSizeBytes (represents locals or general vars if the | 269 /// and SpillAreaSizeBytes (represents locals or general vars if the |
| 269 // coalescing of locals is disallowed) along with alignments required | 270 /// coalescing of locals is disallowed) along with alignments required |
| 270 // for variables in each area. We rely on accurate VMetadata in order to | 271 /// for variables in each area. We rely on accurate VMetadata in order to |
| 271 // classify a variable as global vs local (otherwise the variable is | 272 /// classify a variable as global vs local (otherwise the variable is |
| 272 // conservatively global). The in-args should be initialized to 0. | 273 /// conservatively global). The in-args should be initialized to 0. |
| 273 // | 274 /// |
| 274 // This is only a pre-pass and the actual stack slot assignment is | 275 /// This is only a pre-pass and the actual stack slot assignment is |
| 275 // handled separately. | 276 /// handled separately. |
| 276 // | 277 /// |
| 277 // There may be target-specific Variable types, which will be handled | 278 /// There may be target-specific Variable types, which will be handled |
| 278 // by TargetVarHook. If the TargetVarHook returns true, then the variable | 279 /// by TargetVarHook. If the TargetVarHook returns true, then the variable |
| 279 // is skipped and not considered with the rest of the spilled variables. | 280 /// is skipped and not considered with the rest of the spilled variables. |
| 280 void getVarStackSlotParams(VarList &SortedSpilledVariables, | 281 void getVarStackSlotParams(VarList &SortedSpilledVariables, |
| 281 llvm::SmallBitVector &RegsUsed, | 282 llvm::SmallBitVector &RegsUsed, |
| 282 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, | 283 size_t *GlobalsSize, size_t *SpillAreaSizeBytes, |
| 283 uint32_t *SpillAreaAlignmentBytes, | 284 uint32_t *SpillAreaAlignmentBytes, |
| 284 uint32_t *LocalsSlotsAlignmentBytes, | 285 uint32_t *LocalsSlotsAlignmentBytes, |
| 285 std::function<bool(Variable *)> TargetVarHook); | 286 std::function<bool(Variable *)> TargetVarHook); |
| 286 | 287 |
| 287 // Calculate the amount of padding needed to align the local and global | 288 /// Calculate the amount of padding needed to align the local and global |
| 288 // areas to the required alignment. This assumes the globals/locals layout | 289 /// areas to the required alignment. This assumes the globals/locals layout |
| 289 // used by getVarStackSlotParams and assignVarStackSlots. | 290 /// used by getVarStackSlotParams and assignVarStackSlots. |
| 290 void alignStackSpillAreas(uint32_t SpillAreaStartOffset, | 291 void alignStackSpillAreas(uint32_t SpillAreaStartOffset, |
| 291 uint32_t SpillAreaAlignmentBytes, | 292 uint32_t SpillAreaAlignmentBytes, |
| 292 size_t GlobalsSize, | 293 size_t GlobalsSize, |
| 293 uint32_t LocalsSlotsAlignmentBytes, | 294 uint32_t LocalsSlotsAlignmentBytes, |
| 294 uint32_t *SpillAreaPaddingBytes, | 295 uint32_t *SpillAreaPaddingBytes, |
| 295 uint32_t *LocalsSlotsPaddingBytes); | 296 uint32_t *LocalsSlotsPaddingBytes); |
| 296 | 297 |
| 297 // Make a pass through the SortedSpilledVariables and actually assign | 298 /// Make a pass through the SortedSpilledVariables and actually assign |
| 298 // stack slots. SpillAreaPaddingBytes takes into account stack alignment | 299 /// stack slots. SpillAreaPaddingBytes takes into account stack alignment |
| 299 // padding. The SpillArea starts after that amount of padding. | 300 /// padding. The SpillArea starts after that amount of padding. |
| 300 // This matches the scheme in getVarStackSlotParams, where there may | 301 /// This matches the scheme in getVarStackSlotParams, where there may |
| 301 // be a separate multi-block global var spill area and a local var | 302 /// be a separate multi-block global var spill area and a local var |
| 302 // spill area. | 303 /// spill area. |
| 303 void assignVarStackSlots(VarList &SortedSpilledVariables, | 304 void assignVarStackSlots(VarList &SortedSpilledVariables, |
| 304 size_t SpillAreaPaddingBytes, | 305 size_t SpillAreaPaddingBytes, |
| 305 size_t SpillAreaSizeBytes, | 306 size_t SpillAreaSizeBytes, |
| 306 size_t GlobalsAndSubsequentPaddingSize, | 307 size_t GlobalsAndSubsequentPaddingSize, |
| 307 bool UsesFramePointer); | 308 bool UsesFramePointer); |
| 308 | 309 |
| 309 // Sort the variables in Source based on required alignment. | 310 /// Sort the variables in Source based on required alignment. |
| 310 // The variables with the largest alignment need are placed in the front | 311 /// The variables with the largest alignment need are placed in the front |
| 311 // of the Dest list. | 312 /// of the Dest list. |
| 312 void sortVarsByAlignment(VarList &Dest, const VarList &Source) const; | 313 void sortVarsByAlignment(VarList &Dest, const VarList &Source) const; |
| 313 | 314 |
| 314 // Make a call to an external helper function. | 315 /// Make a call to an external helper function. |
| 315 InstCall *makeHelperCall(const IceString &Name, Variable *Dest, | 316 InstCall *makeHelperCall(const IceString &Name, Variable *Dest, |
| 316 SizeT MaxSrcs); | 317 SizeT MaxSrcs); |
| 317 | 318 |
| 318 void | 319 void |
| 319 _bundle_lock(InstBundleLock::Option BundleOption = InstBundleLock::Opt_None) { | 320 _bundle_lock(InstBundleLock::Option BundleOption = InstBundleLock::Opt_None) { |
| 320 Context.insert(InstBundleLock::create(Func, BundleOption)); | 321 Context.insert(InstBundleLock::create(Func, BundleOption)); |
| 321 } | 322 } |
| 322 void _bundle_unlock() { Context.insert(InstBundleUnlock::create(Func)); } | 323 void _bundle_unlock() { Context.insert(InstBundleUnlock::create(Func)); } |
| 323 | 324 |
| 324 Cfg *Func; | 325 Cfg *Func; |
| 325 GlobalContext *Ctx; | 326 GlobalContext *Ctx; |
| 326 bool HasComputedFrame = false; | 327 bool HasComputedFrame = false; |
| 327 bool CallsReturnsTwice = false; | 328 bool CallsReturnsTwice = false; |
| 328 // StackAdjustment keeps track of the current stack offset from its | 329 /// StackAdjustment keeps track of the current stack offset from its |
| 329 // natural location, as arguments are pushed for a function call. | 330 /// natural location, as arguments are pushed for a function call. |
| 330 int32_t StackAdjustment = 0; | 331 int32_t StackAdjustment = 0; |
| 331 SizeT NextLabelNumber = 0; | 332 SizeT NextLabelNumber = 0; |
| 332 LoweringContext Context; | 333 LoweringContext Context; |
| 333 | 334 |
| 334 // Runtime helper function names | 335 // Runtime helper function names |
| 335 const static constexpr char *H_bitcast_16xi1_i16 = "__Sz_bitcast_16xi1_i16"; | 336 const static constexpr char *H_bitcast_16xi1_i16 = "__Sz_bitcast_16xi1_i16"; |
| 336 const static constexpr char *H_bitcast_8xi1_i8 = "__Sz_bitcast_8xi1_i8"; | 337 const static constexpr char *H_bitcast_8xi1_i8 = "__Sz_bitcast_8xi1_i8"; |
| 337 const static constexpr char *H_bitcast_i16_16xi1 = "__Sz_bitcast_i16_16xi1"; | 338 const static constexpr char *H_bitcast_i16_16xi1 = "__Sz_bitcast_i16_16xi1"; |
| 338 const static constexpr char *H_bitcast_i8_8xi1 = "__Sz_bitcast_i8_8xi1"; | 339 const static constexpr char *H_bitcast_i8_8xi1 = "__Sz_bitcast_i8_8xi1"; |
| 339 const static constexpr char *H_call_ctpop_i32 = "__popcountsi2"; | 340 const static constexpr char *H_call_ctpop_i32 = "__popcountsi2"; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 366 const static constexpr char *H_uitofp_i32_f64 = "__Sz_uitofp_i32_f64"; | 367 const static constexpr char *H_uitofp_i32_f64 = "__Sz_uitofp_i32_f64"; |
| 367 const static constexpr char *H_uitofp_i64_f32 = "__Sz_uitofp_i64_f32"; | 368 const static constexpr char *H_uitofp_i64_f32 = "__Sz_uitofp_i64_f32"; |
| 368 const static constexpr char *H_uitofp_i64_f64 = "__Sz_uitofp_i64_f64"; | 369 const static constexpr char *H_uitofp_i64_f64 = "__Sz_uitofp_i64_f64"; |
| 369 const static constexpr char *H_urem_i32 = "__umodsi3"; | 370 const static constexpr char *H_urem_i32 = "__umodsi3"; |
| 370 const static constexpr char *H_urem_i64 = "__umoddi3"; | 371 const static constexpr char *H_urem_i64 = "__umoddi3"; |
| 371 | 372 |
| 372 private: | 373 private: |
| 373 int32_t SnapshotStackAdjustment = 0; | 374 int32_t SnapshotStackAdjustment = 0; |
| 374 }; | 375 }; |
| 375 | 376 |
| 376 // TargetDataLowering is used for "lowering" data including initializers | 377 /// TargetDataLowering is used for "lowering" data including initializers |
| 377 // for global variables, and the internal constant pools. It is separated | 378 /// for global variables, and the internal constant pools. It is separated |
| 378 // out from TargetLowering because it does not require a Cfg. | 379 /// out from TargetLowering because it does not require a Cfg. |
| 379 class TargetDataLowering { | 380 class TargetDataLowering { |
| 380 TargetDataLowering() = delete; | 381 TargetDataLowering() = delete; |
| 381 TargetDataLowering(const TargetDataLowering &) = delete; | 382 TargetDataLowering(const TargetDataLowering &) = delete; |
| 382 TargetDataLowering &operator=(const TargetDataLowering &) = delete; | 383 TargetDataLowering &operator=(const TargetDataLowering &) = delete; |
| 383 | 384 |
| 384 public: | 385 public: |
| 385 static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx); | 386 static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx); |
| 386 virtual ~TargetDataLowering(); | 387 virtual ~TargetDataLowering(); |
| 387 | 388 |
| 388 virtual void lowerGlobals(const VariableDeclarationList &Vars, | 389 virtual void lowerGlobals(const VariableDeclarationList &Vars, |
| 389 const IceString &SectionSuffix) = 0; | 390 const IceString &SectionSuffix) = 0; |
| 390 virtual void lowerConstants() = 0; | 391 virtual void lowerConstants() = 0; |
| 391 | 392 |
| 392 protected: | 393 protected: |
| 393 void emitGlobal(const VariableDeclaration &Var, | 394 void emitGlobal(const VariableDeclaration &Var, |
| 394 const IceString &SectionSuffix); | 395 const IceString &SectionSuffix); |
| 395 | 396 |
| 396 // For now, we assume .long is the right directive for emitting 4 byte | 397 /// For now, we assume .long is the right directive for emitting 4 byte |
| 397 // emit global relocations. However, LLVM MIPS usually uses .4byte instead. | 398 /// emit global relocations. However, LLVM MIPS usually uses .4byte instead. |
| 398 // Perhaps there is some difference when the location is unaligned. | 399 /// Perhaps there is some difference when the location is unaligned. |
| 399 static const char *getEmit32Directive() { return ".long"; } | 400 static const char *getEmit32Directive() { return ".long"; } |
| 400 | 401 |
| 401 explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {} | 402 explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {} |
| 402 GlobalContext *Ctx; | 403 GlobalContext *Ctx; |
| 403 }; | 404 }; |
| 404 | 405 |
| 405 // TargetHeaderLowering is used to "lower" the header of an output file. | 406 /// TargetHeaderLowering is used to "lower" the header of an output file. |
| 406 // It writes out the target-specific header attributes. E.g., for ARM | 407 /// It writes out the target-specific header attributes. E.g., for ARM |
| 407 // this writes out the build attributes (float ABI, etc.). | 408 /// this writes out the build attributes (float ABI, etc.). |
| 408 class TargetHeaderLowering { | 409 class TargetHeaderLowering { |
| 409 TargetHeaderLowering() = delete; | 410 TargetHeaderLowering() = delete; |
| 410 TargetHeaderLowering(const TargetHeaderLowering &) = delete; | 411 TargetHeaderLowering(const TargetHeaderLowering &) = delete; |
| 411 TargetHeaderLowering &operator=(const TargetHeaderLowering &) = delete; | 412 TargetHeaderLowering &operator=(const TargetHeaderLowering &) = delete; |
| 412 | 413 |
| 413 public: | 414 public: |
| 414 static std::unique_ptr<TargetHeaderLowering> | 415 static std::unique_ptr<TargetHeaderLowering> |
| 415 createLowering(GlobalContext *Ctx); | 416 createLowering(GlobalContext *Ctx); |
| 416 virtual ~TargetHeaderLowering(); | 417 virtual ~TargetHeaderLowering(); |
| 417 | 418 |
| 418 virtual void lower() {} | 419 virtual void lower() {} |
| 419 | 420 |
| 420 protected: | 421 protected: |
| 421 explicit TargetHeaderLowering(GlobalContext *Ctx) : Ctx(Ctx) {} | 422 explicit TargetHeaderLowering(GlobalContext *Ctx) : Ctx(Ctx) {} |
| 422 GlobalContext *Ctx; | 423 GlobalContext *Ctx; |
| 423 }; | 424 }; |
| 424 | 425 |
| 425 } // end of namespace Ice | 426 } // end of namespace Ice |
| 426 | 427 |
| 427 #endif // SUBZERO_SRC_ICETARGETLOWERING_H | 428 #endif // SUBZERO_SRC_ICETARGETLOWERING_H |
| OLD | NEW |