1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2012-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // Some utility classes and functions used throughout jit
27 
28 #if ! defined (octave_jit_util_h)
29 #define octave_jit_util_h 1
30 
31 #include "octave-config.h"
32 
33 #if defined (HAVE_LLVM)
34 
35 #include <stdexcept>
36 
37 #if defined (HAVE_LLVM_IR_DATALAYOUT_H) || defined (HAVE_LLVM_DATALAYOUT_H)
38 #  define HAVE_LLVM_DATALAYOUT
39 #endif
40 
41 // we don't want to include llvm headers here, as they require
42 // __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS be defined in the entire
43 // compilation unit
44 namespace llvm
45 {
46   class Value;
47   class Module;
48   class ExecutionEngine;
49   class Function;
50   class BasicBlock;
51   class LLVMContext;
52   class Type;
53   class StructType;
54   class FunctionType;
55   class Twine;
56   class GlobalValue;
57   class GlobalVariable;
58   class TerminatorInst;
59   class PHINode;
60   class TargetMachine;
61 
62   class ConstantFolder;
63 
64 #if defined  LLVM_IRBUILDER_HAS_TWO_TEMPLATE_ARGS
65 
66   class IRBuilderDefaultInserter;
67 
68   template <typename T, typename Inserter>
69   class IRBuilder;
70 
71   typedef IRBuilder<ConstantFolder, IRBuilderDefaultInserter>
72     IRBuilderD;
73 
74 #else
75 
76   template <bool preserveNames>
77   class IRBuilderDefaultInserter;
78 
79   template <bool preserveNames, typename T, typename Inserter>
80   class IRBuilder;
81 
82   typedef IRBuilder<true, ConstantFolder, IRBuilderDefaultInserter<true>>
83     IRBuilderD;
84 
85 #endif
86 }
87 
88 // some octave classes that are not (yet) in the octave namespace
89 class octave_base_value;
90 class octave_builtin;
91 class octave_value;
92 class tree;
93 class tree_expression;
94 
95 namespace octave
96 {
97   // thrown when we should give up on JIT and interpret
98   class jit_fail_exception : public std::runtime_error
99   {
100   public:
101 
jit_fail_exception(void)102     jit_fail_exception (void)
103       : std::runtime_error ("unknown"), m_known (false)
104     { }
105 
jit_fail_exception(const std::string & reason)106     jit_fail_exception (const std::string& reason)
107       : std::runtime_error (reason), m_known (true)
108     { }
109 
known(void)110     bool known (void) const { return m_known; }
111 
112   private:
113 
114     bool m_known;
115   };
116 
117   // llvm doesn't provide this, and it's really useful for debugging
118   std::ostream& operator<< (std::ostream& os, const llvm::Value& v);
119 
120   template <typename HOLDER_T, typename SUB_T>
121   class jit_internal_node;
122 
123   // jit_internal_list and jit_internal_node implement generic embedded doubly
124   // linked lists.  List items extend from jit_internal_list, and can be placed
125   // in nodes of type jit_internal_node.  We use CRTP twice.
126 
127   template <typename LIST_T, typename NODE_T>
128   class
129   jit_internal_list
130   {
131     friend class jit_internal_node<LIST_T, NODE_T>;
132 
133   public:
134 
jit_internal_list(void)135     jit_internal_list (void)
136       : m_use_head (0), m_use_tail (0), m_use_count (0)
137     { }
138 
~jit_internal_list(void)139     virtual ~jit_internal_list (void)
140     {
141       while (m_use_head)
142         m_use_head->stash_value (0);
143     }
144 
first_use(void)145     NODE_T * first_use (void) const { return m_use_head; }
146 
use_count(void)147     std::size_t use_count (void) const { return m_use_count; }
148 
149   private:
150 
151     NODE_T *m_use_head;
152     NODE_T *m_use_tail;
153     std::size_t m_use_count;
154   };
155 
156   // a node for internal linked lists
157   template <typename LIST_T, typename NODE_T>
158   class
159   jit_internal_node
160   {
161   public:
162 
163     typedef jit_internal_list<LIST_T, NODE_T> jit_ilist;
164 
jit_internal_node(void)165     jit_internal_node (void)
166       : m_value (nullptr), m_next (nullptr), m_prev (nullptr)
167     { }
168 
~jit_internal_node(void)169     ~jit_internal_node (void) { remove (); }
170 
value(void)171     LIST_T * value (void) const { return m_value; }
172 
stash_value(LIST_T * avalue)173     void stash_value (LIST_T *avalue)
174     {
175       remove ();
176 
177       m_value = avalue;
178 
179       if (m_value)
180         {
181           jit_ilist *ilist = m_value;
182           NODE_T *sthis = static_cast<NODE_T *> (this);
183           if (ilist->m_use_head)
184             {
185               ilist->m_use_tail->m_next = sthis;
186               m_prev = ilist->m_use_tail;
187             }
188           else
189             ilist->m_use_head = sthis;
190 
191           ilist->m_use_tail = sthis;
192           ++ilist->m_use_count;
193         }
194     }
195 
next(void)196     NODE_T * next (void) const { return m_next; }
197 
prev(void)198     NODE_T * prev (void) const { return m_prev; }
199 
200   private:
201 
remove(void)202     void remove (void)
203     {
204       if (m_value)
205         {
206           jit_ilist *ilist = m_value;
207           if (m_prev)
208             m_prev->m_next = m_next;
209           else
210             // we are the use_head
211             ilist->m_use_head = m_next;
212 
213           if (m_next)
214             m_next->m_prev = m_prev;
215           else
216             // we are the use tail
217             ilist->m_use_tail = m_prev;
218 
219           m_next = m_prev = 0;
220           --ilist->m_use_count;
221           m_value = 0;
222         }
223     }
224 
225     LIST_T *m_value;
226     NODE_T *m_next;
227     NODE_T *m_prev;
228   };
229 
230   // Use like: isa<jit_phi> (value)
231   // basically just a short cut type typing dyanmic_cast.
232   template <typename T, typename U>
isa(U * value)233   bool isa (U *value)
234   {
235     return dynamic_cast<T *> (value);
236   }
237 
238 }
239 
240 #endif
241 #endif
242