1 /*
  2  * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_C1_C1_VALUEMAP_HPP
 26 #define SHARE_C1_C1_VALUEMAP_HPP
 27 
 28 #include "c1/c1_Instruction.hpp"
 29 #include "c1/c1_ValueSet.hpp"
 30 #include "memory/allocation.hpp"
 31 
 32 class ValueMapEntry: public CompilationResourceObj {
 33  private:
 34   intx           _hash;
 35   Value          _value;
 36   int            _nesting;
 37   ValueMapEntry* _next;
 38 
 39  public:
 40   ValueMapEntry(intx hash, Value value, int nesting, ValueMapEntry* next)
 41     : _hash(hash)
 42     , _value(value)
 43     , _nesting(nesting)
 44     , _next(next)
 45   {
 46   }
 47 
 48   intx           hash()      { return _hash; }
 49   Value          value()     { return _value; }
 50   int            nesting()   { return _nesting; }
 51   ValueMapEntry* next()      { return _next; }
 52 
 53   void set_next(ValueMapEntry* next) { _next = next; }
 54 };
 55 
 56 typedef GrowableArray<ValueMapEntry*> ValueMapEntryArray;
 57 typedef GrowableArray<ValueMapEntry*> ValueMapEntryList;
 58 
 59 // ValueMap implements nested hash tables for value numbering.  It
 60 // maintains a set _killed_values which represents the instructions
 61 // which have been killed so far and an array of linked lists of
 62 // ValueMapEntries names _entries.  Each ValueMapEntry has a nesting
 63 // which indicates what ValueMap nesting it belongs to.  Higher
 64 // nesting values are always before lower values in the linked list.
 65 // This allows cloning of parent ValueMaps by simply copying the heads
 66 // of the list.  _entry_count represents the number of reachable
 67 // entries in the ValueMap.  A ValueMap is only allowed to mutate
 68 // ValueMapEntries with the same nesting level.  Adding or removing
 69 // entries at the current nesting level requires updating
 70 // _entry_count.  Elements in the parent's list that get killed can be
 71 // skipped if they are at the head of the list by simply moving to the
 72 // next element in the list and decrementing _entry_count.
 73 
 74 class ValueMap: public CompilationResourceObj {
 75  private:
 76   int           _nesting;
 77   ValueMapEntryArray _entries;
 78   ValueSet      _killed_values;
 79   int           _entry_count;
 80 
 81   int           nesting()                        { return _nesting; }
 82   bool          is_local_value_numbering()       { return _nesting == 0; }
 83   bool          is_global_value_numbering()      { return _nesting > 0; }
 84 
 85   int           entry_count()                    { return _entry_count; }
 86   int           size()                           { return _entries.length(); }
 87   ValueMapEntry* entry_at(int i)                 { return _entries.at(i); }
 88 
 89   // calculates the index of a hash value in a hash table of size n
 90   int           entry_index(intx hash, int n)    { return (unsigned int)hash % n; }
 91 
 92   // if entry_count > size_threshold, the size of the hash table is increased
 93   int           size_threshold()                 { return size(); }
 94 
 95   // management of the killed-bitset for global value numbering
 96   void          kill_value(Value v)              { if (is_global_value_numbering()) _killed_values.put(v); }
 97   bool          is_killed(Value v)               { if (is_global_value_numbering()) return _killed_values.contains(v); else return false; }
 98 
 99   // helper functions
100   void          increase_table_size();
101 
102 #ifndef PRODUCT
103   static int _number_of_finds;
104   static int _number_of_hits;
105   static int _number_of_kills;
106 #endif // PRODUCT
107 
108  public:
109   // creation
110   ValueMap();                // empty value map
111   ValueMap(ValueMap* old);   // value map with increased nesting
112 
113   // manipulation
114   Value find_insert(Value x);
115 
116   void kill_memory();
117   void kill_field(ciField* field, bool all_offsets);
118   void kill_array(ValueType* type);
119   void kill_map(ValueMap* map);
120   void kill_all();
121 
122 #ifndef PRODUCT
123   // debugging/printing
124   void print();
125 
126   static void reset_statistics();
127   static void print_statistics();
128 #endif
129 };
130 
131 typedef GrowableArray<ValueMap*> ValueMapArray;
132 
133 class ValueNumberingVisitor: public InstructionVisitor {
134  protected:
135   // called by visitor functions for instructions that kill values
136   virtual void kill_memory() = 0;
137   virtual void kill_field(ciField* field, bool all_offsets) = 0;
138   virtual void kill_array(ValueType* type) = 0;
139 
140   // visitor functions
141   void do_StoreField     (StoreField*      x) {
142     if (x->is_init_point() ||  // putstatic is an initialization point so treat it as a wide kill
143         // This is actually too strict and the JMM doesn't require
144         // this in all cases (e.g. load a; volatile store b; load a)
145         // but possible future optimizations might require this.
146         x->field()->is_volatile()) {
147       kill_memory();
148     } else {
149       kill_field(x->field(), x->needs_patching());
150       if (x->enclosing_field() != nullptr) {
151         kill_field(x->enclosing_field(), true);
152       }
153     }
154   }
155   void do_StoreIndexed   (StoreIndexed*    x) { kill_array(x->type()); }
156   void do_MonitorEnter   (MonitorEnter*    x) { kill_memory(); }
157   void do_MonitorExit    (MonitorExit*     x) { kill_memory(); }
158   void do_Invoke         (Invoke*          x) { kill_memory(); }
159   void do_UnsafePut      (UnsafePut*       x) { kill_memory(); }
160   void do_UnsafeGetAndSet(UnsafeGetAndSet* x) { kill_memory(); }
161   void do_UnsafeGet      (UnsafeGet*       x) {
162     if (x->is_volatile()) { // the JMM requires this
163       kill_memory();
164     }
165   }
166   void do_Intrinsic      (Intrinsic*       x) { if (!x->preserves_state()) kill_memory(); }
167 
168   void do_Phi            (Phi*             x) { /* nothing to do */ }
169   void do_Local          (Local*           x) { /* nothing to do */ }
170   void do_Constant       (Constant*        x) {
171     if (x->kills_memory()) {
172       assert(x->can_trap(), "already linked");
173       kill_memory();
174     }
175   }
176   void do_LoadField      (LoadField*       x) {
177     if (x->is_init_point() ||         // getstatic is an initialization point so treat it as a wide kill
178         x->field()->is_volatile()) {  // the JMM requires this
179       kill_memory();
180     }
181   }
182   void do_ArrayLength    (ArrayLength*     x) { /* nothing to do */ }
183   void do_LoadIndexed    (LoadIndexed*     x) { /* nothing to do */ }
184   void do_NegateOp       (NegateOp*        x) { /* nothing to do */ }
185   void do_ArithmeticOp   (ArithmeticOp*    x) { /* nothing to do */ }
186   void do_ShiftOp        (ShiftOp*         x) { /* nothing to do */ }
187   void do_LogicOp        (LogicOp*         x) { /* nothing to do */ }
188   void do_CompareOp      (CompareOp*       x) { /* nothing to do */ }
189   void do_IfOp           (IfOp*            x) { /* nothing to do */ }
190   void do_Convert        (Convert*         x) { /* nothing to do */ }
191   void do_NullCheck      (NullCheck*       x) { /* nothing to do */ }
192   void do_TypeCast       (TypeCast*        x) { /* nothing to do */ }
193   void do_NewInstance    (NewInstance*     x) { /* nothing to do */ }
194   void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ }
195   void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ }
196   void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ }
197   void do_CheckCast      (CheckCast*       x) { /* nothing to do */ }
198   void do_InstanceOf     (InstanceOf*      x) { /* nothing to do */ }
199   void do_BlockBegin     (BlockBegin*      x) { /* nothing to do */ }
200   void do_Goto           (Goto*            x) { /* nothing to do */ }
201   void do_If             (If*              x) { /* nothing to do */ }
202   void do_TableSwitch    (TableSwitch*     x) { /* nothing to do */ }
203   void do_LookupSwitch   (LookupSwitch*    x) { /* nothing to do */ }
204   void do_Return         (Return*          x) { /* nothing to do */ }
205   void do_Throw          (Throw*           x) { /* nothing to do */ }
206   void do_Base           (Base*            x) { /* nothing to do */ }
207   void do_OsrEntry       (OsrEntry*        x) { /* nothing to do */ }
208   void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
209   void do_RoundFP        (RoundFP*         x) { /* nothing to do */ }
210   void do_ProfileCall    (ProfileCall*     x) { /* nothing to do */ }
211   void do_ProfileReturnType (ProfileReturnType*  x) { /* nothing to do */ }
212   void do_ProfileACmpTypes(ProfileACmpTypes*  x) { /* nothing to do */ }
213   void do_ProfileInvoke  (ProfileInvoke*   x) { /* nothing to do */ };
214   void do_RuntimeCall    (RuntimeCall*     x) { /* nothing to do */ };
215   void do_MemBar         (MemBar*          x) { /* nothing to do */ };
216   void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
217 #ifdef ASSERT
218   void do_Assert         (Assert*          x) { /* nothing to do */ };
219 #endif
220 };
221 
222 
223 class ValueNumberingEffects: public ValueNumberingVisitor {
224  private:
225   ValueMap*     _map;
226 
227  public:
228   // implementation for abstract methods of ValueNumberingVisitor
229   void          kill_memory()                                 { _map->kill_memory(); }
230   void          kill_field(ciField* field, bool all_offsets)  { _map->kill_field(field, all_offsets); }
231   void          kill_array(ValueType* type)                   { _map->kill_array(type); }
232 
233   ValueNumberingEffects(ValueMap* map): _map(map) {}
234 };
235 
236 
237 class GlobalValueNumbering: public ValueNumberingVisitor {
238  private:
239   Compilation*  _compilation;     // compilation data
240   ValueMap*     _current_map;     // value map of current block
241   ValueMapArray _value_maps;      // list of value maps for all blocks
242   ValueSet      _processed_values;  // marker for instructions that were already processed
243   bool          _has_substitutions; // set to true when substitutions must be resolved
244 
245  public:
246   // accessors
247   Compilation*  compilation() const              { return _compilation; }
248   ValueMap*     current_map()                    { return _current_map; }
249   ValueMap*     value_map_of(BlockBegin* block)  { return _value_maps.at(block->linear_scan_number()); }
250   void          set_value_map_of(BlockBegin* block, ValueMap* map) { assert(value_map_of(block) == nullptr, ""); _value_maps.at_put(block->linear_scan_number(), map); }
251 
252   bool          is_processed(Value v)            { return _processed_values.contains(v); }
253   void          set_processed(Value v)           { _processed_values.put(v); }
254 
255   // implementation for abstract methods of ValueNumberingVisitor
256   void          kill_memory()                                 { current_map()->kill_memory(); }
257   void          kill_field(ciField* field, bool all_offsets)  { current_map()->kill_field(field, all_offsets); }
258   void          kill_array(ValueType* type)                   { current_map()->kill_array(type); }
259 
260   // main entry point that performs global value numbering
261   GlobalValueNumbering(IR* ir);
262   void          substitute(Instruction* instr);  // substitute instruction if it is contained in current value map
263 };
264 
265 #endif // SHARE_C1_C1_VALUEMAP_HPP