summaryrefslogtreecommitdiff
path: root/backend/src/ir/function.hpp
blob: 165bc6f71955a2db5cf47f2ad90d356f14527aae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/* 
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file function.hpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */
#ifndef __GBE_IR_FUNCTION_HPP__
#define __GBE_IR_FUNCTION_HPP__

#include "ir/immediate.hpp"
#include "ir/register.hpp"
#include "ir/instruction.hpp"
#include "ir/profile.hpp"
#include "sys/vector.hpp"
#include "sys/set.hpp"
#include "sys/alloc.hpp"

#include <ostream>

namespace gbe {
namespace ir {

  /*! Commonly used in the CFG */
  typedef set<BasicBlock*> BlockSet;

  /*! Function basic blocks really belong to a function since:
   *  1 - registers used in the basic blocks belongs to the function register
   *      file
   *  2 - branches point to basic blocks of the same function
   */
  class BasicBlock : public NonCopyable
  {
  public:
    /*! Empty basic block */
    BasicBlock(Function &fn);
    /*! Releases all the instructions */
    ~BasicBlock(void);
    /*! Append a new instruction in the stream */
    void append(Instruction &insn) {
      if (last != NULL) last->setSuccessor(&insn);
      if (first == NULL) first = &insn;
      insn.setParent(this);
      insn.setSuccessor(NULL);
      insn.setPredecessor(last);
      last = &insn;
    }
    /*! Apply the given functor on all instructions */
    template <typename T>
    INLINE void foreach(const T &functor) const {
      Instruction *curr = first;
      while (curr) {
        functor(*curr);
        curr = curr->getSuccessor();
      }
    }
    /*! Apply the given functor on all instructions (reverse order) */
    template <typename T>
    INLINE void rforeach(const T &functor) const {
      Instruction *curr = last;
      while (curr) {
        functor(*curr);
        curr = curr->getPredecessor();
      }
    }
    /*! Get the parent function */
    Function &getParent(void) { return fn; }
    const Function &getParent(void) const { return fn; }
    /*! Get the next and previous allocated block */
    BasicBlock *getNextBlock(void) const { return this->nextBlock; }
    BasicBlock *getPrevBlock(void) const { return this->prevBlock; }
    /*! Get the first and last instructions */
    Instruction *getFirstInstruction(void) const { return this->first; }
    Instruction *getLastInstruction(void) const { return this->last; }
    /*! Get successors and predecessors */
    const BlockSet &getSuccessorSet(void) const { return successors; }
    const BlockSet &getPredecessorSet(void) const { return predecessors; }
  private:
    friend class Function; //!< Owns the basic blocks
    BlockSet predecessors; //!< Incoming blocks
    BlockSet successors;   //!< Outgoing blocks
    BasicBlock *nextBlock; //!< Block allocated just after this one
    BasicBlock *prevBlock; //!< Block allocated just before this one
    Instruction *first;    //!< First instruction in the block
    Instruction *last;     //!< Last instruction in the block
    Function &fn;          //!< Function the block belongs to
    GBE_CLASS(BasicBlock);
  };

  /*! In fine, function inputs (arguments) can be pushed from the constant
   *  buffer if they are structures. Other arguments can be images (textures)
   *  and will also require special treatment.
   */
  struct FunctionInput
  {
    enum Type
    {
      GLOBAL_POINTER    = 0, // __global
      CONSTANT_POINTER  = 1, // __constant
      LOCAL_POINTER     = 2, // __local
      VALUE             = 3, // int, float
      STRUCTURE         = 4, // struct foo
      IMAGE             = 5  // image*d_t
    };
    /*! Create a function input */
    INLINE FunctionInput(Type type, Register reg, uint32_t elementSize = 0u) :
      type(type), reg(reg), elementSize(elementSize) {}
    Type type;            /*! Gives the type of argument we have */
    Register reg;         /*! Holds the argument */
    uint32_t elementSize; /*! Only for structure arguments */
  };

  /*! A function is no more that a set of declared registers and a set of
   *  basic blocks
   */
  class Function : public NonCopyable
  {
  public:
    /*! Create an empty function */
    Function(const std::string &name, Profile profile = PROFILE_OCL);
    /*! Release everything *including* the basic block pointers */
    ~Function(void);
    /*! Says if this is the top basic block (entry point) */
    INLINE bool isEntryBlock(const BasicBlock &bb) const {
      if (this->blockNum() == 0)
        return false;
      else
        return &bb == this->blocks[0];
    }
    /*! Get the function profile */
    INLINE Profile getProfile(void) const { return profile; }
    /*! Get a new valid register */
    INLINE Register newRegister(RegisterFamily family) {
      return this->file.append(family);
    }
    /*! Get the function name */
    const std::string &getName(void) const { return name; }
    /*! Extract the register from the register file */
    INLINE RegisterData getRegisterData(Register ID) const { return file.get(ID); }
    /*! Get the register family from the register itself */
    INLINE RegisterFamily getRegisterFamiy(Register ID) const {
      return this->getRegisterData(ID).family;
    }
    /*! Get the register index from the tuple vector */
    INLINE Register getRegister(Tuple ID, uint32_t which) const {
      return file.get(ID, which);
    }
    /*! Get the register file */
    INLINE const RegisterFile &getRegisterFile(void) const { return file; }
    /*! Get the given value ie immediate from the function */
    INLINE Immediate getImmediate(ImmediateIndex ID) const {
      GBE_ASSERT(ID < immediateNum());
      return immediates[ID];
    }
    /*! Create a new immediate and returns its index */
    INLINE ImmediateIndex newImmediate(const Immediate &imm) {
      const ImmediateIndex index(this->immediateNum());
      this->immediates.push_back(imm);
      return index;
    }
    /*! Fast allocation / deallocation of instructions */
    DECL_POOL(Instruction, insnPool);
    /*! Get input argument */
    INLINE const FunctionInput &getInput(uint32_t ID) const {
      GBE_ASSERT(ID < inputNum() && inputs[ID] != NULL);
      return *inputs[ID];
    }
    /*! Get input argument from the register (linear research). Return NULL if
     *  this is not an input argument
     */
    INLINE const FunctionInput *getInput(const Register &reg) const {
      for (auto it = inputs.begin(); it != inputs.end(); ++it)
        if ((*it)->reg == reg) return *it;
      return NULL;
    }
    /*! Get output register */
    INLINE Register getOutput(uint32_t ID) const {
      GBE_ASSERT(ID < outputNum());
      return outputs[ID];
    }
    /*! Get block ID */
    INLINE const BasicBlock &getBlock(uint32_t ID) const {
      GBE_ASSERT(ID < blockNum());
      GBE_ASSERT(blocks[ID] != NULL);
      return *blocks[ID];
    }
    /*! Get the first index of the special registers and number of them */
    uint32_t getFirstSpecialReg(void) const;
    uint32_t getSpecialRegNum(void) const;
    /*! Indicate if the given register is a special one */
    INLINE bool isSpecialReg(const Register &reg) const {
      const uint32_t ID = uint32_t(reg);
      const uint32_t firstID = this->getFirstSpecialReg();
      const uint32_t specialNum = this->getSpecialRegNum();
      return ID >= firstID && ID < firstID + specialNum;
    }
    /*! Create a new label (still not bound to a basic block) */
    LabelIndex newLabel(void);
    /*! Create the control flow graph */
    void computeCFG(void);
    /*! Number of registers in the register file */
    INLINE uint32_t regNum(void) const { return file.regNum(); }
    /*! Number of register tuples in the register file */
    INLINE uint32_t tupleNum(void) const { return file.tupleNum(); }
    /*! Number of labels in the function */
    INLINE uint32_t labelNum(void) const { return labels.size(); }
    /*! Number of immediate values in the function */
    INLINE uint32_t immediateNum(void) const { return immediates.size(); }
    /*! Get the number of input register */
    INLINE uint32_t inputNum(void) const { return inputs.size(); }
    /*! Get the number of output register */
    INLINE uint32_t outputNum(void) const { return outputs.size(); }
    /*! Number of blocks in the function */
    INLINE uint32_t blockNum(void) const { return blocks.size(); }
    /*! Output an immediate value in a stream */
    void outImmediate(std::ostream &out, ImmediateIndex index) const;
    /*! Apply the given functor on all basic blocks */
    template <typename T>
    INLINE void foreachBlock(const T &functor) const {
      for (auto it = blocks.begin(); it != blocks.end(); ++it)
        functor(**it);
    }
    /*! Apply the given functor on all instructions */
    template <typename T>
    INLINE void foreachInstruction(const T &functor) const {
      for (auto it = blocks.begin(); it != blocks.end(); ++it)
        (*it)->foreach(functor);
    }
  private:
    friend class Context;         //!< Can freely modify a function
    std::string name;             //!< Function name
    vector<FunctionInput*> inputs;//!< Input registers of the function
    vector<Register> outputs;     //!< Output registers of the function
    vector<BasicBlock*> labels;   //!< Each label points to a basic block
    vector<Immediate> immediates; //!< All immediate values in the function
    vector<BasicBlock*> blocks;   //!< All chained basic blocks
    RegisterFile file;            //!< RegisterDatas used by the instructions
    Profile profile;              //!< Current function profile
    GBE_CLASS(Function);          //!< Use gbe allocators
  };

  /*! Output the function string in the given stream */
  std::ostream &operator<< (std::ostream &out, const Function &fn);

} /* namespace ir */
} /* namespace gbe */

#endif /* __GBE_IR_FUNCTION_HPP__ */