src/share/vm/c1/c1_ValueMap.hpp

Thu, 21 Mar 2013 09:27:54 +0100

author
roland
date
Thu, 21 Mar 2013 09:27:54 +0100
changeset 4860
46f6f063b272
parent 4153
b9a9ed0f8eeb
child 4947
acadb114c818
permissions
-rw-r--r--

7153771: array bound check elimination for c1
Summary: when possible optimize out array bound checks, inserting predicates when needed.
Reviewed-by: never, kvn, twisti
Contributed-by: thomaswue <thomas.wuerthinger@oracle.com>

     1 /*
     2  * Copyright (c) 1999, 2012, 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  */
    25 #ifndef SHARE_VM_C1_C1_VALUEMAP_HPP
    26 #define SHARE_VM_C1_C1_VALUEMAP_HPP
    28 #include "c1/c1_Instruction.hpp"
    29 #include "c1/c1_ValueSet.hpp"
    30 #include "memory/allocation.hpp"
    32 class ValueMapEntry: public CompilationResourceObj {
    33  private:
    34   intx           _hash;
    35   Value          _value;
    36   int            _nesting;
    37   ValueMapEntry* _next;
    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   }
    48   intx           hash()      { return _hash; }
    49   Value          value()     { return _value; }
    50   int            nesting()   { return _nesting; }
    51   ValueMapEntry* next()      { return _next; }
    53   void set_next(ValueMapEntry* next) { _next = next; }
    54 };
    56 define_array(ValueMapEntryArray, ValueMapEntry*)
    57 define_stack(ValueMapEntryList, ValueMapEntryArray)
    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.
    74 class ValueMap: public CompilationResourceObj {
    75  private:
    76   int           _nesting;
    77   ValueMapEntryArray _entries;
    78   ValueSet      _killed_values;
    79   int           _entry_count;
    81   int           nesting()                        { return _nesting; }
    82   bool          is_local_value_numbering()       { return _nesting == 0; }
    83   bool          is_global_value_numbering()      { return _nesting > 0; }
    85   int           entry_count()                    { return _entry_count; }
    86   int           size()                           { return _entries.length(); }
    87   ValueMapEntry* entry_at(int i)                 { return _entries.at(i); }
    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; }
    92   // if entry_count > size_threshold, the size of the hash table is increased
    93   int           size_threshold()                 { return size(); }
    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; }
    99   // helper functions
   100   void          increase_table_size();
   102 #ifndef PRODUCT
   103   static int _number_of_finds;
   104   static int _number_of_hits;
   105   static int _number_of_kills;
   106 #endif // PRODUCT
   108  public:
   109   // creation
   110   ValueMap();                // empty value map
   111   ValueMap(ValueMap* old);   // value map with increased nesting
   113   // manipulation
   114   Value find_insert(Value x);
   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();
   123 #ifndef PRODUCT
   124   // debugging/printing
   125   void print();
   127   static void reset_statistics();
   128   static void print_statistics();
   129 #endif
   130 };
   132 define_array(ValueMapArray, ValueMap*)
   135 class ValueNumberingVisitor: public InstructionVisitor {
   136  protected:
   137   // called by visitor functions for instructions that kill values
   138   virtual void kill_memory() = 0;
   139   virtual void kill_field(ciField* field, bool all_offsets) = 0;
   140   virtual void kill_array(ValueType* type) = 0;
   142   // visitor functions
   143   void do_StoreField     (StoreField*      x) {
   144     if (x->is_init_point() ||  // putstatic is an initialization point so treat it as a wide kill
   145         // This is actually too strict and the JMM doesn't require
   146         // this in all cases (e.g. load a; volatile store b; load a)
   147         // but possible future optimizations might require this.
   148         x->field()->is_volatile()) {
   149       kill_memory();
   150     } else {
   151       kill_field(x->field(), x->needs_patching());
   152     }
   153   }
   154   void do_StoreIndexed   (StoreIndexed*    x) { kill_array(x->type()); }
   155   void do_MonitorEnter   (MonitorEnter*    x) { kill_memory(); }
   156   void do_MonitorExit    (MonitorExit*     x) { kill_memory(); }
   157   void do_Invoke         (Invoke*          x) { kill_memory(); }
   158   void do_UnsafePutRaw   (UnsafePutRaw*    x) { kill_memory(); }
   159   void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); }
   160   void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { kill_memory(); }
   161   void do_Intrinsic      (Intrinsic*       x) { if (!x->preserves_state()) kill_memory(); }
   163   void do_Phi            (Phi*             x) { /* nothing to do */ }
   164   void do_Local          (Local*           x) { /* nothing to do */ }
   165   void do_Constant       (Constant*        x) { /* nothing to do */ }
   166   void do_LoadField      (LoadField*       x) {
   167     if (x->is_init_point() ||         // getstatic is an initialization point so treat it as a wide kill
   168         x->field()->is_volatile()) {  // the JMM requires this
   169       kill_memory();
   170     }
   171   }
   172   void do_ArrayLength    (ArrayLength*     x) { /* nothing to do */ }
   173   void do_LoadIndexed    (LoadIndexed*     x) { /* nothing to do */ }
   174   void do_NegateOp       (NegateOp*        x) { /* nothing to do */ }
   175   void do_ArithmeticOp   (ArithmeticOp*    x) { /* nothing to do */ }
   176   void do_ShiftOp        (ShiftOp*         x) { /* nothing to do */ }
   177   void do_LogicOp        (LogicOp*         x) { /* nothing to do */ }
   178   void do_CompareOp      (CompareOp*       x) { /* nothing to do */ }
   179   void do_IfOp           (IfOp*            x) { /* nothing to do */ }
   180   void do_Convert        (Convert*         x) { /* nothing to do */ }
   181   void do_NullCheck      (NullCheck*       x) { /* nothing to do */ }
   182   void do_TypeCast       (TypeCast*        x) { /* nothing to do */ }
   183   void do_NewInstance    (NewInstance*     x) { /* nothing to do */ }
   184   void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ }
   185   void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ }
   186   void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ }
   187   void do_CheckCast      (CheckCast*       x) { /* nothing to do */ }
   188   void do_InstanceOf     (InstanceOf*      x) { /* nothing to do */ }
   189   void do_BlockBegin     (BlockBegin*      x) { /* nothing to do */ }
   190   void do_Goto           (Goto*            x) { /* nothing to do */ }
   191   void do_If             (If*              x) { /* nothing to do */ }
   192   void do_IfInstanceOf   (IfInstanceOf*    x) { /* nothing to do */ }
   193   void do_TableSwitch    (TableSwitch*     x) { /* nothing to do */ }
   194   void do_LookupSwitch   (LookupSwitch*    x) { /* nothing to do */ }
   195   void do_Return         (Return*          x) { /* nothing to do */ }
   196   void do_Throw          (Throw*           x) { /* nothing to do */ }
   197   void do_Base           (Base*            x) { /* nothing to do */ }
   198   void do_OsrEntry       (OsrEntry*        x) { /* nothing to do */ }
   199   void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
   200   void do_RoundFP        (RoundFP*         x) { /* nothing to do */ }
   201   void do_UnsafeGetRaw   (UnsafeGetRaw*    x) { /* nothing to do */ }
   202   void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ }
   203   void do_UnsafePrefetchRead (UnsafePrefetchRead*  x) { /* nothing to do */ }
   204   void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }
   205   void do_ProfileCall    (ProfileCall*     x) { /* nothing to do */ }
   206   void do_ProfileInvoke  (ProfileInvoke*   x) { /* nothing to do */ };
   207   void do_RuntimeCall    (RuntimeCall*     x) { /* nothing to do */ };
   208   void do_MemBar         (MemBar*          x) { /* nothing to do */ };
   209   void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
   210   void do_Assert         (Assert*          x) { /* nothing to do */ };
   211 };
   214 class ValueNumberingEffects: public ValueNumberingVisitor {
   215  private:
   216   ValueMap*     _map;
   218  public:
   219   // implementation for abstract methods of ValueNumberingVisitor
   220   void          kill_memory()                                 { _map->kill_memory(); }
   221   void          kill_field(ciField* field, bool all_offsets)  { _map->kill_field(field, all_offsets); }
   222   void          kill_array(ValueType* type)                   { _map->kill_array(type); }
   224   ValueNumberingEffects(ValueMap* map): _map(map) {}
   225 };
   228 class GlobalValueNumbering: public ValueNumberingVisitor {
   229  private:
   230   Compilation*  _compilation;     // compilation data
   231   ValueMap*     _current_map;     // value map of current block
   232   ValueMapArray _value_maps;      // list of value maps for all blocks
   233   ValueSet      _processed_values;  // marker for instructions that were already processed
   234   bool          _has_substitutions; // set to true when substitutions must be resolved
   236  public:
   237   // accessors
   238   Compilation*  compilation() const              { return _compilation; }
   239   ValueMap*     current_map()                    { return _current_map; }
   240   ValueMap*     value_map_of(BlockBegin* block)  { return _value_maps.at(block->linear_scan_number()); }
   241   void          set_value_map_of(BlockBegin* block, ValueMap* map)   { assert(value_map_of(block) == NULL, ""); _value_maps.at_put(block->linear_scan_number(), map); }
   243   bool          is_processed(Value v)            { return _processed_values.contains(v); }
   244   void          set_processed(Value v)           { _processed_values.put(v); }
   246   // implementation for abstract methods of ValueNumberingVisitor
   247   void          kill_memory()                                 { current_map()->kill_memory(); }
   248   void          kill_field(ciField* field, bool all_offsets)  { current_map()->kill_field(field, all_offsets); }
   249   void          kill_array(ValueType* type)                   { current_map()->kill_array(type); }
   251   // main entry point that performs global value numbering
   252   GlobalValueNumbering(IR* ir);
   253   void          substitute(Instruction* instr);  // substitute instruction if it is contained in current value map
   254 };
   256 #endif // SHARE_VM_C1_C1_VALUEMAP_HPP

mercurial