1 /*
2  * Copyright (c) 2012, 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_RANGECHECKELIMINATION_HPP
26 #define SHARE_C1_C1_RANGECHECKELIMINATION_HPP
27 
28 #include "c1/c1_Instruction.hpp"
29 
30 // Base class for range check elimination
31 class RangeCheckElimination : AllStatic {
32 public:
33   static void eliminate(IR *ir);
34 };
35 
36 // Implementation
37 class RangeCheckEliminator {
38 private:
39   int _number_of_instructions;
40   bool _optimistic; // Insert predicates and deoptimize when they fail
41   IR *_ir;
42 
43   typedef GrowableArray<BlockBegin*> BlockBeginList;
44   typedef GrowableArray<int> IntegerStack;
45 
46 #ifdef ASSERT
47   class Verification : public BlockClosure {
48   // RangeCheckEliminator::Verification should never get instatiated on the heap.
49   private:
50     void* operator new(size_t size) throw();
51     void* operator new[](size_t size) throw();
operator delete(void * p)52     void operator delete(void* p) { ShouldNotReachHere(); }
operator delete[](void * p)53     void operator delete[](void* p) { ShouldNotReachHere(); }
54 
55     bool can_reach(BlockBegin *start, BlockBegin *end, BlockBegin *dont_use = NULL);
56     bool dominates(BlockBegin *dominator, BlockBegin *block);
57     bool is_backbranch_from_xhandler(BlockBegin* block);
58 
59     IR *_ir;
60     boolArray _used;
61     BlockBeginList _current;
62     BlockBeginList _successors;
63 
64   public:
65     Verification(IR *ir);
66     virtual void block_do(BlockBegin *block);
67   };
68 #endif
69 
70 public:
71   // Bounds for an instruction in the form x + c which c integer
72   // constant and x another instruction
73   class Bound : public CompilationResourceObj {
74   private:
75     int _upper;
76     Value _upper_instr;
77     int _lower;
78     Value _lower_instr;
79 
80   public:
81     Bound();
82     Bound(Value v);
83     Bound(Instruction::Condition cond, Value v, int constant = 0);
84     Bound(int lower, Value lower_instr, int upper, Value upper_instr);
85     ~Bound();
86 
87 #ifdef ASSERT
88     void add_assertion(Instruction *instruction, Instruction *position, int i, Value instr, Instruction::Condition cond);
89 #endif
90     int upper();
91     Value upper_instr();
92     int lower();
93     Value lower_instr();
94     void print();
95     bool check_no_overflow(int const_value);
96     void or_op(Bound *b);
97     void and_op(Bound *b);
98     bool has_upper();
99     bool has_lower();
100     void set_upper(int upper, Value upper_instr);
101     void set_lower(int lower, Value lower_instr);
102     bool is_smaller(Bound *b);
103     void remove_upper();
104     void remove_lower();
105     void add_constant(int value);
106     Bound *copy();
107 
108   private:
109     void init();
110   };
111 
112 
113   class Visitor : public InstructionVisitor {
114   private:
115     Bound *_bound;
116     RangeCheckEliminator *_rce;
117 
118   public:
set_range_check_eliminator(RangeCheckEliminator * rce)119     void set_range_check_eliminator(RangeCheckEliminator *rce) { _rce = rce; }
bound() const120     Bound *bound() const { return _bound; }
clear_bound()121     void clear_bound() { _bound = NULL; }
122 
123   protected:
124     // visitor functions
125     void do_Constant       (Constant*        x);
126     void do_IfOp           (IfOp*            x);
127     void do_LogicOp        (LogicOp*         x);
128     void do_ArithmeticOp   (ArithmeticOp*    x);
129     void do_Phi            (Phi*             x);
130 
do_StoreField(StoreField * x)131     void do_StoreField     (StoreField*      x) { /* nothing to do */ };
do_StoreIndexed(StoreIndexed * x)132     void do_StoreIndexed   (StoreIndexed*    x) { /* nothing to do */ };
do_MonitorEnter(MonitorEnter * x)133     void do_MonitorEnter   (MonitorEnter*    x) { /* nothing to do */ };
do_MonitorExit(MonitorExit * x)134     void do_MonitorExit    (MonitorExit*     x) { /* nothing to do */ };
do_Invoke(Invoke * x)135     void do_Invoke         (Invoke*          x) { /* nothing to do */ };
do_UnsafePutRaw(UnsafePutRaw * x)136     void do_UnsafePutRaw   (UnsafePutRaw*    x) { /* nothing to do */ };
do_UnsafePutObject(UnsafePutObject * x)137     void do_UnsafePutObject(UnsafePutObject* x) { /* nothing to do */ };
do_Intrinsic(Intrinsic * x)138     void do_Intrinsic      (Intrinsic*       x) { /* nothing to do */ };
do_Local(Local * x)139     void do_Local          (Local*           x) { /* nothing to do */ };
do_LoadField(LoadField * x)140     void do_LoadField      (LoadField*       x) { /* nothing to do */ };
do_ArrayLength(ArrayLength * x)141     void do_ArrayLength    (ArrayLength*     x) { /* nothing to do */ };
do_LoadIndexed(LoadIndexed * x)142     void do_LoadIndexed    (LoadIndexed*     x) { /* nothing to do */ };
do_NegateOp(NegateOp * x)143     void do_NegateOp       (NegateOp*        x) { /* nothing to do */ };
do_ShiftOp(ShiftOp * x)144     void do_ShiftOp        (ShiftOp*         x) { /* nothing to do */ };
do_CompareOp(CompareOp * x)145     void do_CompareOp      (CompareOp*       x) { /* nothing to do */ };
do_Convert(Convert * x)146     void do_Convert        (Convert*         x) { /* nothing to do */ };
do_NullCheck(NullCheck * x)147     void do_NullCheck      (NullCheck*       x) { /* nothing to do */ };
do_TypeCast(TypeCast * x)148     void do_TypeCast       (TypeCast*        x) { /* nothing to do */ };
do_NewInstance(NewInstance * x)149     void do_NewInstance    (NewInstance*     x) { /* nothing to do */ };
do_NewTypeArray(NewTypeArray * x)150     void do_NewTypeArray   (NewTypeArray*    x) { /* nothing to do */ };
do_NewObjectArray(NewObjectArray * x)151     void do_NewObjectArray (NewObjectArray*  x) { /* nothing to do */ };
do_NewMultiArray(NewMultiArray * x)152     void do_NewMultiArray  (NewMultiArray*   x) { /* nothing to do */ };
do_CheckCast(CheckCast * x)153     void do_CheckCast      (CheckCast*       x) { /* nothing to do */ };
do_InstanceOf(InstanceOf * x)154     void do_InstanceOf     (InstanceOf*      x) { /* nothing to do */ };
do_BlockBegin(BlockBegin * x)155     void do_BlockBegin     (BlockBegin*      x) { /* nothing to do */ };
do_Goto(Goto * x)156     void do_Goto           (Goto*            x) { /* nothing to do */ };
do_If(If * x)157     void do_If             (If*              x) { /* nothing to do */ };
do_IfInstanceOf(IfInstanceOf * x)158     void do_IfInstanceOf   (IfInstanceOf*    x) { /* nothing to do */ };
do_TableSwitch(TableSwitch * x)159     void do_TableSwitch    (TableSwitch*     x) { /* nothing to do */ };
do_LookupSwitch(LookupSwitch * x)160     void do_LookupSwitch   (LookupSwitch*    x) { /* nothing to do */ };
do_Return(Return * x)161     void do_Return         (Return*          x) { /* nothing to do */ };
do_Throw(Throw * x)162     void do_Throw          (Throw*           x) { /* nothing to do */ };
do_Base(Base * x)163     void do_Base           (Base*            x) { /* nothing to do */ };
do_OsrEntry(OsrEntry * x)164     void do_OsrEntry       (OsrEntry*        x) { /* nothing to do */ };
do_ExceptionObject(ExceptionObject * x)165     void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ };
do_RoundFP(RoundFP * x)166     void do_RoundFP        (RoundFP*         x) { /* nothing to do */ };
do_UnsafeGetRaw(UnsafeGetRaw * x)167     void do_UnsafeGetRaw   (UnsafeGetRaw*    x) { /* nothing to do */ };
do_UnsafeGetObject(UnsafeGetObject * x)168     void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ };
do_UnsafeGetAndSetObject(UnsafeGetAndSetObject * x)169     void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { /* nothing to do */ };
do_ProfileCall(ProfileCall * x)170     void do_ProfileCall    (ProfileCall*     x) { /* nothing to do */ };
do_ProfileReturnType(ProfileReturnType * x)171     void do_ProfileReturnType (ProfileReturnType*  x) { /* nothing to do */ };
do_ProfileInvoke(ProfileInvoke * x)172     void do_ProfileInvoke  (ProfileInvoke*   x) { /* nothing to do */ };
do_RuntimeCall(RuntimeCall * x)173     void do_RuntimeCall    (RuntimeCall*     x) { /* nothing to do */ };
do_MemBar(MemBar * x)174     void do_MemBar         (MemBar*          x) { /* nothing to do */ };
do_RangeCheckPredicate(RangeCheckPredicate * x)175     void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
176 #ifdef ASSERT
do_Assert(Assert * x)177     void do_Assert         (Assert*          x) { /* nothing to do */ };
178 #endif
179   };
180 
181 #ifdef ASSERT
182   void add_assertions(Bound *bound, Instruction *instruction, Instruction *position);
183 #endif
184 
185   typedef GrowableArray<Bound*> BoundStack;
186   typedef GrowableArray<BoundStack*> BoundMap;
187   typedef GrowableArray<AccessIndexed*> AccessIndexedList;
188   typedef GrowableArray<Instruction*> InstructionList;
189 
190   class AccessIndexedInfo : public CompilationResourceObj  {
191   public:
192     AccessIndexedList *_list;
193     int _min;
194     int _max;
195   };
196 
197   typedef GrowableArray<AccessIndexedInfo*> AccessIndexedInfoArray;
198   BoundMap _bounds; // Mapping from Instruction's id to current bound
199   AccessIndexedInfoArray _access_indexed_info; // Mapping from Instruction's id to AccessIndexedInfo for in block motion
200   Visitor _visitor;
201 
202 public:
203   RangeCheckEliminator(IR *ir);
204 
ir() const205   IR *ir() const { return _ir; }
206 
207   // Pass over the dominator tree to identify blocks where there's an oppportunity for optimization
208   bool set_process_block_flags(BlockBegin *block);
209   // The core of the optimization work: pass over the dominator tree
210   // to propagate bound information, insert predicate out of loops,
211   // eliminate bound checks when possible and perform in block motion
212   void calc_bounds(BlockBegin *block, BlockBegin *loop_header);
213   // reorder bound checks within a block in order to eliminate some of them
214   void in_block_motion(BlockBegin *block, AccessIndexedList &accessIndexed, InstructionList &arrays);
215 
216   // update/access current bound
217   void update_bound(IntegerStack &pushed, Value v, Instruction::Condition cond, Value value, int constant);
218   void update_bound(IntegerStack &pushed, Value v, Bound *bound);
219   Bound *get_bound(Value v);
220 
221   bool loop_invariant(BlockBegin *loop_header, Instruction *instruction);                                    // check for loop invariance
222   void add_access_indexed_info(InstructionList &indices, int i, Value instruction, AccessIndexed *ai); // record indexed access for in block motion
223   void remove_range_check(AccessIndexed *ai);                                                                // Mark this instructions as not needing a range check
224   void add_if_condition(IntegerStack &pushed, Value x, Value y, Instruction::Condition condition);           // Update bound for an If
225   bool in_array_bound(Bound *bound, Value array);                                                            // Check whether bound is known to fall within array
226 
227   // helper functions to work with predicates
228   Instruction* insert_after(Instruction* insert_position, Instruction* instr, int bci);
229   Instruction* predicate(Instruction* left, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci=-1);
230   Instruction* predicate_cmp_with_const(Instruction* instr, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci=1);
231   Instruction* predicate_add(Instruction* left, int left_const, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci=-1);
232   Instruction* predicate_add_cmp_with_const(Instruction* left, int left_const, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci=-1);
233 
234   void insert_deoptimization(ValueStack *state, Instruction *insert_position, Instruction *array_instr,      // Add predicate
235                              Instruction *length_instruction, Instruction *lower_instr, int lower,
236                              Instruction *upper_instr, int upper, AccessIndexed *ai);
237   bool is_ok_for_deoptimization(Instruction *insert_position, Instruction *array_instr,                      // Can we safely add a predicate?
238                                 Instruction *length_instr, Instruction *lower_instr,
239                                 int lower, Instruction *upper_instr, int upper);
240   void process_if(IntegerStack &pushed, BlockBegin *block, If *cond);                                        // process If Instruction
241   void process_access_indexed(BlockBegin *loop_header, BlockBegin *block, AccessIndexed *ai);                // process indexed access
242 
243   void dump_condition_stack(BlockBegin *cur_block);
244   static void print_statistics();
245 };
246 
247 #endif // SHARE_C1_C1_RANGECHECKELIMINATION_HPP
248