1 /*
2  * Copyright (c) 1999, 2019, 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:
ValueMapEntry(intx hash,Value value,int nesting,ValueMapEntry * next)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 
hash()48   intx           hash()      { return _hash; }
value()49   Value          value()     { return _value; }
nesting()50   int            nesting()   { return _nesting; }
next()51   ValueMapEntry* next()      { return _next; }
52 
set_next(ValueMapEntry * next)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 
nesting()81   int           nesting()                        { return _nesting; }
is_local_value_numbering()82   bool          is_local_value_numbering()       { return _nesting == 0; }
is_global_value_numbering()83   bool          is_global_value_numbering()      { return _nesting > 0; }
84 
entry_count()85   int           entry_count()                    { return _entry_count; }
size()86   int           size()                           { return _entries.length(); }
entry_at(int i)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
entry_index(intx hash,int 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
size_threshold()93   int           size_threshold()                 { return size(); }
94 
95   // management of the killed-bitset for global value numbering
kill_value(Value v)96   void          kill_value(Value v)              { if (is_global_value_numbering()) _killed_values.put(v); }
is_killed(Value 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_exception();
120   void kill_map(ValueMap* map);
121   void kill_all();
122 
123 #ifndef PRODUCT
124   // debugging/printing
125   void print();
126 
127   static void reset_statistics();
128   static void print_statistics();
129 #endif
130 };
131 
132 typedef GrowableArray<ValueMap*> ValueMapArray;
133 
134 class ValueNumberingVisitor: public InstructionVisitor {
135  protected:
136   // called by visitor functions for instructions that kill values
137   virtual void kill_memory() = 0;
138   virtual void kill_field(ciField* field, bool all_offsets) = 0;
139   virtual void kill_array(ValueType* type) = 0;
140 
141   // visitor functions
do_StoreField(StoreField * x)142   void do_StoreField     (StoreField*      x) {
143     if (x->is_init_point() ||  // putstatic is an initialization point so treat it as a wide kill
144         // This is actually too strict and the JMM doesn't require
145         // this in all cases (e.g. load a; volatile store b; load a)
146         // but possible future optimizations might require this.
147         x->field()->is_volatile()) {
148       kill_memory();
149     } else {
150       kill_field(x->field(), x->needs_patching());
151     }
152   }
do_StoreIndexed(StoreIndexed * x)153   void do_StoreIndexed   (StoreIndexed*    x) { kill_array(x->type()); }
do_MonitorEnter(MonitorEnter * x)154   void do_MonitorEnter   (MonitorEnter*    x) { kill_memory(); }
do_MonitorExit(MonitorExit * x)155   void do_MonitorExit    (MonitorExit*     x) { kill_memory(); }
do_Invoke(Invoke * x)156   void do_Invoke         (Invoke*          x) { kill_memory(); }
do_UnsafePutRaw(UnsafePutRaw * x)157   void do_UnsafePutRaw   (UnsafePutRaw*    x) { kill_memory(); }
do_UnsafePutObject(UnsafePutObject * x)158   void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); }
do_UnsafeGetAndSetObject(UnsafeGetAndSetObject * x)159   void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { kill_memory(); }
do_UnsafeGetRaw(UnsafeGetRaw * x)160   void do_UnsafeGetRaw   (UnsafeGetRaw*    x) { /* nothing to do */ }
do_UnsafeGetObject(UnsafeGetObject * x)161   void do_UnsafeGetObject(UnsafeGetObject* x) {
162     if (x->is_volatile()) { // the JMM requires this
163       kill_memory();
164     }
165   }
do_Intrinsic(Intrinsic * x)166   void do_Intrinsic      (Intrinsic*       x) { if (!x->preserves_state()) kill_memory(); }
167 
do_Phi(Phi * x)168   void do_Phi            (Phi*             x) { /* nothing to do */ }
do_Local(Local * x)169   void do_Local          (Local*           x) { /* nothing to do */ }
do_Constant(Constant * x)170   void do_Constant       (Constant*        x) { /* nothing to do */ }
do_LoadField(LoadField * x)171   void do_LoadField      (LoadField*       x) {
172     if (x->is_init_point() ||         // getstatic is an initialization point so treat it as a wide kill
173         x->field()->is_volatile()) {  // the JMM requires this
174       kill_memory();
175     }
176   }
do_ArrayLength(ArrayLength * x)177   void do_ArrayLength    (ArrayLength*     x) { /* nothing to do */ }
do_LoadIndexed(LoadIndexed * x)178   void do_LoadIndexed    (LoadIndexed*     x) { /* nothing to do */ }
do_NegateOp(NegateOp * x)179   void do_NegateOp       (NegateOp*        x) { /* nothing to do */ }
do_ArithmeticOp(ArithmeticOp * x)180   void do_ArithmeticOp   (ArithmeticOp*    x) { /* nothing to do */ }
do_ShiftOp(ShiftOp * x)181   void do_ShiftOp        (ShiftOp*         x) { /* nothing to do */ }
do_LogicOp(LogicOp * x)182   void do_LogicOp        (LogicOp*         x) { /* nothing to do */ }
do_CompareOp(CompareOp * x)183   void do_CompareOp      (CompareOp*       x) { /* nothing to do */ }
do_IfOp(IfOp * x)184   void do_IfOp           (IfOp*            x) { /* nothing to do */ }
do_Convert(Convert * x)185   void do_Convert        (Convert*         x) { /* nothing to do */ }
do_NullCheck(NullCheck * x)186   void do_NullCheck      (NullCheck*       x) { /* nothing to do */ }
do_TypeCast(TypeCast * x)187   void do_TypeCast       (TypeCast*        x) { /* nothing to do */ }
do_NewInstance(NewInstance * x)188   void do_NewInstance    (NewInstance*     x) { /* nothing to do */ }
do_NewTypeArray(NewTypeArray * x)189   void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ }
do_NewObjectArray(NewObjectArray * x)190   void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ }
do_NewMultiArray(NewMultiArray * x)191   void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ }
do_CheckCast(CheckCast * x)192   void do_CheckCast      (CheckCast*       x) { /* nothing to do */ }
do_InstanceOf(InstanceOf * x)193   void do_InstanceOf     (InstanceOf*      x) { /* nothing to do */ }
do_BlockBegin(BlockBegin * x)194   void do_BlockBegin     (BlockBegin*      x) { /* nothing to do */ }
do_Goto(Goto * x)195   void do_Goto           (Goto*            x) { /* nothing to do */ }
do_If(If * x)196   void do_If             (If*              x) { /* nothing to do */ }
do_TableSwitch(TableSwitch * x)197   void do_TableSwitch    (TableSwitch*     x) { /* nothing to do */ }
do_LookupSwitch(LookupSwitch * x)198   void do_LookupSwitch   (LookupSwitch*    x) { /* nothing to do */ }
do_Return(Return * x)199   void do_Return         (Return*          x) { /* nothing to do */ }
do_Throw(Throw * x)200   void do_Throw          (Throw*           x) { /* nothing to do */ }
do_Base(Base * x)201   void do_Base           (Base*            x) { /* nothing to do */ }
do_OsrEntry(OsrEntry * x)202   void do_OsrEntry       (OsrEntry*        x) { /* nothing to do */ }
do_ExceptionObject(ExceptionObject * x)203   void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
do_RoundFP(RoundFP * x)204   void do_RoundFP        (RoundFP*         x) { /* nothing to do */ }
do_ProfileCall(ProfileCall * x)205   void do_ProfileCall    (ProfileCall*     x) { /* nothing to do */ }
do_ProfileReturnType(ProfileReturnType * x)206   void do_ProfileReturnType (ProfileReturnType*  x) { /* nothing to do */ }
do_ProfileInvoke(ProfileInvoke * x)207   void do_ProfileInvoke  (ProfileInvoke*   x) { /* nothing to do */ };
do_RuntimeCall(RuntimeCall * x)208   void do_RuntimeCall    (RuntimeCall*     x) { /* nothing to do */ };
do_MemBar(MemBar * x)209   void do_MemBar         (MemBar*          x) { /* nothing to do */ };
do_RangeCheckPredicate(RangeCheckPredicate * x)210   void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
211 #ifdef ASSERT
do_Assert(Assert * x)212   void do_Assert         (Assert*          x) { /* nothing to do */ };
213 #endif
214 };
215 
216 
217 class ValueNumberingEffects: public ValueNumberingVisitor {
218  private:
219   ValueMap*     _map;
220 
221  public:
222   // implementation for abstract methods of ValueNumberingVisitor
kill_memory()223   void          kill_memory()                                 { _map->kill_memory(); }
kill_field(ciField * field,bool all_offsets)224   void          kill_field(ciField* field, bool all_offsets)  { _map->kill_field(field, all_offsets); }
kill_array(ValueType * type)225   void          kill_array(ValueType* type)                   { _map->kill_array(type); }
226 
ValueNumberingEffects(ValueMap * map)227   ValueNumberingEffects(ValueMap* map): _map(map) {}
228 };
229 
230 
231 class GlobalValueNumbering: public ValueNumberingVisitor {
232  private:
233   Compilation*  _compilation;     // compilation data
234   ValueMap*     _current_map;     // value map of current block
235   ValueMapArray _value_maps;      // list of value maps for all blocks
236   ValueSet      _processed_values;  // marker for instructions that were already processed
237   bool          _has_substitutions; // set to true when substitutions must be resolved
238 
239  public:
240   // accessors
compilation() const241   Compilation*  compilation() const              { return _compilation; }
current_map()242   ValueMap*     current_map()                    { return _current_map; }
value_map_of(BlockBegin * block)243   ValueMap*     value_map_of(BlockBegin* block)  { return _value_maps.at(block->linear_scan_number()); }
set_value_map_of(BlockBegin * block,ValueMap * map)244   void          set_value_map_of(BlockBegin* block, ValueMap* map)   { assert(value_map_of(block) == NULL, ""); _value_maps.at_put(block->linear_scan_number(), map); }
245 
is_processed(Value v)246   bool          is_processed(Value v)            { return _processed_values.contains(v); }
set_processed(Value v)247   void          set_processed(Value v)           { _processed_values.put(v); }
248 
249   // implementation for abstract methods of ValueNumberingVisitor
kill_memory()250   void          kill_memory()                                 { current_map()->kill_memory(); }
kill_field(ciField * field,bool all_offsets)251   void          kill_field(ciField* field, bool all_offsets)  { current_map()->kill_field(field, all_offsets); }
kill_array(ValueType * type)252   void          kill_array(ValueType* type)                   { current_map()->kill_array(type); }
253 
254   // main entry point that performs global value numbering
255   GlobalValueNumbering(IR* ir);
256   void          substitute(Instruction* instr);  // substitute instruction if it is contained in current value map
257 };
258 
259 #endif // SHARE_C1_C1_VALUEMAP_HPP
260