changeset 1447:62a746a17ffa

2009-03-23 Gary Benson <gbenson@redhat.com> * ports/hotspot/src/share/vm/shark/sharkFunction.hpp: (SharkFunction::_deferred_zero_checks): New field. (SharkFunction::deferred_zero_checks): New method. (SharkFunction::add_deferred_zero_check): Likewise. (SharkFunction::do_deferred_zero_checks): Likewise. * ports/hotspot/src/share/vm/shark/sharkFunction.cpp: (SharkFunction::DeferredZeroCheck): New class. (SharkFunction::add_deferred_zero_check): New method. (SharkFunction::do_deferred_zero_checks): Likewise. (SharkFunction::initialize): Do deferred zero checks after parsing blocks. * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp (SharkBlock::zero_check_value): New method. (SharkBlock::do_deferred_zero_check): Likewise. * ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp (SharkBlock::do_zero_check): Defer ambiguous zero checks. (SharkBlock::zero_check_value): New method. (SharkBlock::do_deferred_zero_check): Likewise. (SharkTopLevelBlock::handle_exception): Don't copy state. (SharkTopLevelBlock::do_if): Likewise. (SharkTopLevelBlock::do_switch): Likewise. * ports/hotspot/src/share/vm/shark/sharkValue.hpp (SharkPHIValue): New class. (SharkValue::is_phi): New method. (SharkValue::as_phi): Likewise. (SharkValue::create_phi): Likewise. (SharkValue::merge): Likewise. (SharkNormalValue::merge): Likewise. (SharkAddressValue::merge): Likewise. * ports/hotspot/src/share/vm/shark/sharkState.cpp (SharkPHIState::SharkPHIState): Create SharkPHIValues. (SharkState::merge): Defer to SharkValue::merge.
author Gary Benson <gbenson@redhat.com>
date Mon, 23 Mar 2009 09:33:31 -0400
parents 371412771066
children 246837dabf32
files ChangeLog ports/hotspot/src/share/vm/shark/sharkFunction.cpp ports/hotspot/src/share/vm/shark/sharkFunction.hpp ports/hotspot/src/share/vm/shark/sharkState.cpp ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp ports/hotspot/src/share/vm/shark/sharkValue.cpp ports/hotspot/src/share/vm/shark/sharkValue.hpp
diffstat 8 files changed, 363 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Mar 21 10:10:02 2009 +0100
+++ b/ChangeLog	Mon Mar 23 09:33:31 2009 -0400
@@ -1,3 +1,41 @@
+2009-03-23  Gary Benson  <gbenson@redhat.com>
+
+	* ports/hotspot/src/share/vm/shark/sharkFunction.hpp:
+	(SharkFunction::_deferred_zero_checks): New field.
+	(SharkFunction::deferred_zero_checks): New method.
+	(SharkFunction::add_deferred_zero_check): Likewise.
+	(SharkFunction::do_deferred_zero_checks): Likewise.
+	* ports/hotspot/src/share/vm/shark/sharkFunction.cpp:
+	(SharkFunction::DeferredZeroCheck): New class.
+	(SharkFunction::add_deferred_zero_check): New method.
+	(SharkFunction::do_deferred_zero_checks): Likewise.
+	(SharkFunction::initialize): Do deferred zero checks
+	after parsing blocks.
+
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp
+	(SharkBlock::zero_check_value): New method.
+	(SharkBlock::do_deferred_zero_check): Likewise.
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp
+	(SharkBlock::do_zero_check): Defer ambiguous zero checks.
+	(SharkBlock::zero_check_value): New method.
+	(SharkBlock::do_deferred_zero_check): Likewise.
+	(SharkTopLevelBlock::handle_exception): Don't copy state.
+	(SharkTopLevelBlock::do_if): Likewise.
+	(SharkTopLevelBlock::do_switch): Likewise.
+
+	* ports/hotspot/src/share/vm/shark/sharkValue.hpp
+	(SharkPHIValue): New class.
+	(SharkValue::is_phi): New method.
+	(SharkValue::as_phi): Likewise.
+	(SharkValue::create_phi): Likewise.
+	(SharkValue::merge): Likewise.
+	(SharkNormalValue::merge): Likewise.
+	(SharkAddressValue::merge): Likewise.
+	
+	* ports/hotspot/src/share/vm/shark/sharkState.cpp
+	(SharkPHIState::SharkPHIState): Create SharkPHIValues.
+	(SharkState::merge): Defer to SharkValue::merge.
+	
 2009-03-21  Matthias Klose  <doko@ubuntu.com>
 
 	* patches/hotspot/*/icedtea-text-relocations.patch: Build hotspot
--- a/ports/hotspot/src/share/vm/shark/sharkFunction.cpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkFunction.cpp	Mon Mar 23 09:33:31 2009 -0400
@@ -123,6 +123,7 @@
 
     block(i)->emit_IR();
   }
+  do_deferred_zero_checks();
 
   // Dump the bitcode, if requested
   if (SharkPrintBitcodeOf != NULL) {
@@ -307,3 +308,80 @@
     this,
     builder()->CreateGEP(monitors_slots(), indexes, indexes + 2));
 }
+
+class DeferredZeroCheck : public ResourceObj {
+ public:
+  DeferredZeroCheck(SharkTopLevelBlock* block, SharkValue* value)
+    : _block(block),
+      _value(value),
+      _bci(block->bci()),
+      _state(block->current_state()->copy()),
+      _check_block(builder()->GetInsertBlock()),
+      _continue_block(function()->CreateBlock("not_zero"))
+  {
+    builder()->SetInsertPoint(continue_block());
+  }
+
+ private:
+  SharkTopLevelBlock* _block;
+  SharkValue*         _value;
+  int                 _bci;
+  SharkState*         _state;
+  BasicBlock*         _check_block;
+  BasicBlock*         _continue_block;
+  
+ public:
+  SharkTopLevelBlock* block() const
+  {
+    return _block;
+  }
+  SharkValue* value() const
+  {
+    return _value;
+  }
+  int bci() const
+  {
+    return _bci;
+  } 
+  SharkState* state() const
+  {
+    return _state;
+  } 
+  BasicBlock* check_block() const
+  {
+    return _check_block;
+  }
+  BasicBlock* continue_block() const
+  {
+    return _continue_block;
+  }
+
+ public:
+  SharkBuilder* builder() const
+  {
+    return block()->builder();
+  }
+  SharkFunction* function() const
+  {
+    return block()->function();
+  }
+
+ public:
+  void process() const
+  {
+    builder()->SetInsertPoint(check_block());
+    block()->do_deferred_zero_check(value(), bci(), state(), continue_block());
+  }
+};
+
+void SharkFunction::add_deferred_zero_check(SharkTopLevelBlock* block,
+                                            SharkValue*         value)
+{
+  deferred_zero_checks()->append(new DeferredZeroCheck(block, value));
+}
+
+void SharkFunction::do_deferred_zero_checks()
+{
+  for (int i = 0; i < deferred_zero_checks()->length(); i++)
+    deferred_zero_checks()->at(i)->process();
+}
--- a/ports/hotspot/src/share/vm/shark/sharkFunction.hpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkFunction.hpp	Mon Mar 23 09:33:31 2009 -0400
@@ -23,8 +23,10 @@
  *
  */
 
+class SharkMonitor;
 class SharkTopLevelBlock;
-class SharkMonitor;
+
+class DeferredZeroCheck;
 
 class SharkFunction : public StackObj {
  public:
@@ -44,16 +46,17 @@
   void initialize();
 
  private:
-  SharkCompiler*       _compiler;
-  const char*          _name;
-  ciTypeFlow*          _flow;
-  ciBytecodeStream*    _iter;
-  MacroAssembler*      _masm;
-  llvm::Function*      _function;
-  SharkTopLevelBlock** _blocks;
-  llvm::Value*         _base_pc;
-  llvm::Value*         _thread;
-  int                  _monitor_count;
+  SharkCompiler*                    _compiler;
+  const char*                       _name;
+  ciTypeFlow*                       _flow;
+  ciBytecodeStream*                 _iter;
+  MacroAssembler*                   _masm;
+  llvm::Function*                   _function;
+  SharkTopLevelBlock**              _blocks;
+  llvm::Value*                      _base_pc;
+  llvm::Value*                      _thread;
+  int                               _monitor_count;
+  GrowableArray<DeferredZeroCheck*> _deferred_zero_checks;
 
  public:  
   SharkCompiler* compiler() const
@@ -96,6 +99,10 @@
   {
     return _monitor_count;
   }
+  GrowableArray<DeferredZeroCheck*>* deferred_zero_checks()
+  {
+    return &_deferred_zero_checks;
+  }
 
  public:
   SharkBuilder* builder() const
@@ -333,4 +340,12 @@
     builder()->CreateStore(LLVMValue::null(), addr);
     return result;
   }
+
+  // Deferred zero checks
+ public:
+  void add_deferred_zero_check(SharkTopLevelBlock* block,
+                               SharkValue*         value);
+
+ private:
+  void do_deferred_zero_checks();
 };
--- a/ports/hotspot/src/share/vm/shark/sharkState.cpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkState.cpp	Mon Mar 23 09:33:31 2009 -0400
@@ -130,14 +130,11 @@
                        BasicBlock* other_block,
                        BasicBlock* this_block)
 {
-  PHINode *phi;
-  char name[18];
-
   // Method
   Value *this_method = this->method();
   Value *other_method = other->method();
   if (this_method != other_method) {
-    phi = builder()->CreatePHI(SharkType::methodOop_type(), "method");
+    PHINode *phi = builder()->CreatePHI(SharkType::methodOop_type(), "method");
     phi->addIncoming(this_method, this_block);
     phi->addIncoming(other_method, other_block);
     set_method(phi);
@@ -149,20 +146,12 @@
     SharkValue *this_value = this->local(i);
     SharkValue *other_value = other->local(i);
     assert((this_value == NULL) == (other_value == NULL), "should be");
-    if (this_value == other_value)
-      continue;
-
-    ciType *this_type = this_value->type();
-    assert(this_type == other_value->type(), "should be");
-
-    bool this_checked = this_value->zero_checked();
-    assert(this_checked == other_value->zero_checked(), "should be");
-
-    snprintf(name, sizeof(name), "local_%d_", i);
-    phi = builder()->CreatePHI(SharkType::to_stackType(this_type), name);
-    phi->addIncoming(this_value->generic_value(), this_block);
-    phi->addIncoming(other_value->generic_value(), other_block);
-    set_local(i, SharkValue::create_generic(this_type, phi, this_checked));
+    if (this_value != NULL) {
+      char name[18];
+      snprintf(name, sizeof(name), "local_%d_", i);
+      set_local(i, this_value->merge(
+        builder(), other_value, other_block, this_block, name));
+    }
   }
 
   // Expression stack
@@ -171,20 +160,12 @@
     SharkValue *this_value = this->stack(i);
     SharkValue *other_value = other->stack(i);
     assert((this_value == NULL) == (other_value == NULL), "should be");
-    if (this_value == other_value)
-      continue;
-
-    ciType *this_type = this_value->type();
-    assert(this_type == other_value->type(), "should be");
-
-    bool this_checked = this_value->zero_checked();
-    assert(this_checked == other_value->zero_checked(), "should be");
-
-    snprintf(name, sizeof(name), "stack_%d_", i);
-    phi = builder()->CreatePHI(SharkType::to_stackType(this_type), name);
-    phi->addIncoming(this_value->generic_value(), this_block);
-    phi->addIncoming(other_value->generic_value(), other_block);
-    set_stack(i, SharkValue::create_generic(this_type, phi, this_checked));
+    if (this_value != NULL) {
+      char name[18];
+      snprintf(name, sizeof(name), "stack_%d_", i);
+      set_stack(i, this_value->merge(
+        builder(), other_value, other_block, this_block, name));
+    }
   }
 }
 
@@ -315,10 +296,8 @@
     case T_OBJECT:
     case T_ARRAY:
       snprintf(name, sizeof(name), "local_%d_", i);
-      value = SharkValue::create_generic(
-        type,
-        builder()->CreatePHI(SharkType::to_stackType(type), name),
-        false);
+      value = SharkValue::create_phi(
+        type, builder()->CreatePHI(SharkType::to_stackType(type), name));
       break;
 
     case T_ADDRESS:
@@ -355,10 +334,8 @@
     case T_OBJECT:
     case T_ARRAY:
       snprintf(name, sizeof(name), "stack_%d_", i);
-      value = SharkValue::create_generic(
-        type, 
-        builder()->CreatePHI(SharkType::to_stackType(type), name),
-        false);
+      value = SharkValue::create_phi(
+        type, builder()->CreatePHI(SharkType::to_stackType(type), name));
       break;
 
     case T_ADDRESS:
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Mon Mar 23 09:33:31 2009 -0400
@@ -250,8 +250,40 @@
 
 void SharkTopLevelBlock::do_zero_check(SharkValue *value)
 {
-  BasicBlock *zero     = function()->CreateBlock("zero");
-  BasicBlock *not_zero = function()->CreateBlock("not_zero");
+  if (value->is_phi() && value->as_phi()->all_incomers_zero_checked()) {
+    function()->add_deferred_zero_check(this, value);
+  }
+  else {
+    BasicBlock *continue_block = function()->CreateBlock("not_zero");
+    SharkState *saved_state = current_state();
+    set_current_state(saved_state->copy());
+    zero_check_value(value, continue_block);
+    builder()->SetInsertPoint(continue_block);
+    set_current_state(saved_state);
+  }
+
+  value->set_zero_checked(true);
+}
+
+void SharkTopLevelBlock::do_deferred_zero_check(SharkValue* value,
+                                                int         bci,
+                                                SharkState* saved_state,
+                                                BasicBlock* continue_block)
+{
+  if (value->as_phi()->all_incomers_zero_checked()) {
+    builder()->CreateBr(continue_block);
+  }
+  else {
+    iter()->force_bci(start());
+    set_current_state(saved_state);  
+    zero_check_value(value, continue_block);
+  }
+}
+
+void SharkTopLevelBlock::zero_check_value(SharkValue* value,
+                                          BasicBlock* continue_block)
+{
+  BasicBlock *zero_block = builder()->CreateBlock(continue_block, "zero");
 
   Value *a, *b;
   switch (value->basic_type()) {
@@ -276,10 +308,10 @@
     ShouldNotReachHere();
   }
 
-  builder()->CreateCondBr(builder()->CreateICmpNE(a, b), not_zero, zero);
+  builder()->CreateCondBr(
+    builder()->CreateICmpNE(a, b), continue_block, zero_block);
 
-  builder()->SetInsertPoint(zero);
-  SharkState *saved_state = current_state()->copy();
+  builder()->SetInsertPoint(zero_block);
   if (value->is_jobject()) {
     call_vm_nocheck(
       SharkRuntime::throw_NullPointerException(),
@@ -290,11 +322,6 @@
     builder()->CreateUnimplemented(__FILE__, __LINE__);
   } 
   handle_exception(function()->CreateGetPendingException());
-  set_current_state(saved_state);  
-
-  builder()->SetInsertPoint(not_zero);
-
-  value->set_zero_checked(true);
 }
 
 void SharkTopLevelBlock::check_bounds(SharkValue* array, SharkValue* index)
@@ -402,7 +429,7 @@
           LLVMValue::jint_constant(i),
           handler->entry_block());
 
-        handler->add_incoming(current_state()->copy());
+        handler->add_incoming(current_state());
       }
 
       builder()->SetInsertPoint(no_handler);
@@ -776,8 +803,6 @@
 // All propagation of state from one block to the next (via
 // dest->add_incoming) is handled by the next three methods
 // (do_branch, do_if and do_switch) and by handle_exception.
-// Where control flow forks, each successor must have its
-// own copy of the state.
 
 void SharkTopLevelBlock::do_branch(int successor_index)
 {
@@ -808,7 +833,7 @@
     if_taken->entry_block(), not_taken->entry_block());
 
   if_taken->add_incoming(current_state());
-  not_taken->add_incoming(current_state()->copy());
+  not_taken->add_incoming(current_state());
 }
 
 void SharkTopLevelBlock::do_switch()
@@ -827,7 +852,7 @@
       switchinst->addCase(
         LLVMValue::jint_constant(switch_key(i)),
         dest_block->entry_block());
-      dest_block->add_incoming(current_state()->copy());      
+      dest_block->add_incoming(current_state());      
     }
   }
 }
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Mon Mar 23 09:33:31 2009 -0400
@@ -185,11 +185,21 @@
 
   // Helpers
  private:
-  void do_zero_check(SharkValue* value);
   llvm::Value* lookup_for_ldc();
   llvm::Value* lookup_for_field_access();
   void do_branch(int successor_index);
 
+  // Zero checks
+ private:
+  void do_zero_check(SharkValue* value);
+  void zero_check_value(SharkValue* value, llvm::BasicBlock* continue_block);
+
+ public:
+  void do_deferred_zero_check(SharkValue*       value,
+                              int               bci,
+                              SharkState*       saved_state,
+                              llvm::BasicBlock* continue_block);
+
   // VM calls
  private:
   llvm::CallInst* call_vm_nocheck(llvm::Constant* callee,
--- a/ports/hotspot/src/share/vm/shark/sharkValue.cpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkValue.cpp	Mon Mar 23 09:33:31 2009 -0400
@@ -34,11 +34,34 @@
 {
   return SharkValue::create_generic(type(), generic_value(), zero_checked());
 }
+SharkValue* SharkPHIValue::clone() const
+{
+  return SharkValue::create_phi(type(), (PHINode *) generic_value(), this);
+}
 SharkValue* SharkAddressValue::clone() const
 {
   return SharkValue::address_constant(address_value());
 }
 
+// Casting
+
+bool SharkValue::is_phi() const
+{
+  return false;
+}
+bool SharkPHIValue::is_phi() const
+{
+  return true;
+}
+SharkPHIValue* SharkValue::as_phi()
+{
+  ShouldNotCallThis();
+}
+SharkPHIValue* SharkPHIValue::as_phi()
+{
+  return this;
+}
+
 // Comparison
 
 bool SharkNormalValue::equal_to(SharkValue *other) const
@@ -225,19 +248,51 @@
   return builder->CreatePtrToInt(jobject_value(), SharkType::intptr_type());
 }
 
-// Phi-style stuff
+// Phi-style stuff for SharkPHIState::add_incoming
 
-void SharkNormalValue::addIncoming(SharkValue *value, BasicBlock* block)
+void SharkValue::addIncoming(SharkValue *value, BasicBlock* block)
 {
-  assert(llvm::isa<llvm::PHINode>(generic_value()), "should be");
+  ShouldNotCallThis();
+}
+void SharkPHIValue::addIncoming(SharkValue *value, BasicBlock* block)
+{
+  assert(!is_clone(), "shouldn't be");
   ((llvm::PHINode *) generic_value())->addIncoming(
       value->generic_value(), block);
+  if (!value->zero_checked())
+    _all_incomers_zero_checked = false;
 }
 void SharkAddressValue::addIncoming(SharkValue *value, BasicBlock* block)
 {
   assert(this->equal_to(value), "should be");
 }
 
+// Phi-style stuff for SharkState::merge
+
+SharkValue* SharkNormalValue::merge(SharkBuilder* builder,
+                                    SharkValue*   other,
+                                    BasicBlock*   other_block,
+                                    BasicBlock*   this_block,
+                                    const char*   name)
+{
+  assert(type() == other->type(), "should be");
+  assert(zero_checked() == other->zero_checked(), "should be");
+
+  PHINode *phi = builder->CreatePHI(SharkType::to_stackType(type()), name);
+  phi->addIncoming(this->generic_value(), this_block);
+  phi->addIncoming(other->generic_value(), other_block);
+  return SharkValue::create_generic(type(), phi, zero_checked());
+}
+SharkValue* SharkAddressValue::merge(SharkBuilder* builder,
+                                     SharkValue*   other,
+                                     BasicBlock*   other_block,
+                                     BasicBlock*   this_block,
+                                     const char*   name)
+{
+  assert(this->equal_to(other), "should be");
+  return this;
+}
+
 // Repeated null and divide-by-zero check removal
 
 bool SharkValue::zero_checked() const
--- a/ports/hotspot/src/share/vm/shark/sharkValue.hpp	Sat Mar 21 10:10:02 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkValue.hpp	Mon Mar 23 09:33:31 2009 -0400
@@ -24,7 +24,9 @@
  */
 
 // Items on the stack and in local variables are tracked using
-// SharkValue objects.  There are two types, SharkNormalValue
+// SharkValue objects.
+// 
+// All SharkValues are one of two core types, SharkNormalValue
 // and SharkAddressValue, but no code outside this file should
 // ever refer to those directly.  The split is because of the
 // way JSRs are handled: the typeflow pass expands them into
@@ -32,8 +34,14 @@
 // popped by ret only exist at compile time.  Having separate
 // classes for these allows us to check that our jsr handling
 // is correct, via assertions.
+// 
+// There is one more type, SharkPHIValue, which is a subclass
+// of SharkNormalValue with a couple of extra methods.  Use of
+// SharkPHIValue outside of this file is acceptable, so long
+// as it is obtained via SharkValue::as_phi().
 
 class SharkBuilder;
+class SharkPHIValue;
 
 class SharkValue : public ResourceObj {
  protected:
@@ -43,6 +51,11 @@
  public:
   virtual SharkValue* clone() const = 0;
 
+  // Casting
+ public:
+  virtual bool           is_phi() const;
+  virtual SharkPHIValue* as_phi();
+
   // Comparison
  public:
   virtual bool equal_to(SharkValue* other) const = 0;
@@ -180,10 +193,18 @@
   static inline SharkValue* create_generic(ciType*      type,
                                            llvm::Value* value,
                                            bool         zero_checked);
+  static inline SharkValue* create_phi(ciType*              type,
+                                       llvm::PHINode*       phi,
+                                       const SharkPHIValue* parent = NULL);
 
   // Phi-style stuff
  public:
-  virtual void addIncoming(SharkValue *value, llvm::BasicBlock* block) = 0;
+  virtual void addIncoming(SharkValue* value, llvm::BasicBlock* block);
+  virtual SharkValue* merge(SharkBuilder*     builder,
+                            SharkValue*       other,
+                            llvm::BasicBlock* other_block,
+                            llvm::BasicBlock* this_block,
+                            const char*       name) = 0;
 
   // Repeated null and divide-by-zero check removal
  public:
@@ -245,9 +266,13 @@
   llvm::Value* generic_value() const;
   llvm::Value* intptr_value(SharkBuilder* builder) const;
 
-  // Wrapped PHINodes
+  // Phi-style stuff
  public:
-  void addIncoming(SharkValue *value, llvm::BasicBlock* block);
+  SharkValue* merge(SharkBuilder*     builder,
+                    SharkValue*       other,
+                    llvm::BasicBlock* other_block,
+                    llvm::BasicBlock* this_block,
+                    const char*       name);
 
   // Repeated null and divide-by-zero check removal
  public:
@@ -255,12 +280,51 @@
   void set_zero_checked(bool zero_checked);
 };
 
-inline SharkValue* SharkValue::create_generic(ciType*      type,
-                                              llvm::Value* value,
-                                              bool         zero_checked)
-{
-  return new SharkNormalValue(type, value, zero_checked);
-}
+class SharkPHIValue : public SharkNormalValue {
+  friend class SharkValue;
+
+ protected:
+  SharkPHIValue(ciType* type, llvm::PHINode* phi, const SharkPHIValue *parent)
+    : SharkNormalValue(type, phi, parent && parent->zero_checked()),
+      _parent(parent),
+      _all_incomers_zero_checked(true) {}
+
+ private:
+  const SharkPHIValue* _parent;
+  bool                 _all_incomers_zero_checked;
+
+ private:
+  const SharkPHIValue* parent() const
+  {
+    return _parent;
+  }
+  bool is_clone() const
+  {
+    return parent() != NULL;
+  }
+
+ public:
+  bool all_incomers_zero_checked() const
+  {
+    if (is_clone())
+      return parent()->all_incomers_zero_checked();
+
+    return _all_incomers_zero_checked;
+  }
+
+  // Cloning
+ public:
+  SharkValue* clone() const;
+
+  // Casting
+ public:
+  bool           is_phi() const;
+  SharkPHIValue* as_phi();
+
+  // Phi-style stuff
+ public:
+  void addIncoming(SharkValue *value, llvm::BasicBlock* block);
+};
 
 class SharkAddressValue : public SharkValue {
   friend class SharkValue;
@@ -297,8 +361,29 @@
   // Phi-style stuff
  public:
   void addIncoming(SharkValue *value, llvm::BasicBlock* block);
+  SharkValue* merge(SharkBuilder*     builder,
+                    SharkValue*       other,
+                    llvm::BasicBlock* other_block,
+                    llvm::BasicBlock* this_block,
+                    const char*       name);
 };
 
+// SharkValue methods that can't be declared above
+
+inline SharkValue* SharkValue::create_generic(ciType*      type,
+                                              llvm::Value* value,
+                                              bool         zero_checked)
+{
+  return new SharkNormalValue(type, value, zero_checked);
+}
+
+inline SharkValue* SharkValue::create_phi(ciType*              type,
+                                          llvm::PHINode*       phi,
+                                          const SharkPHIValue* parent)
+{
+  return new SharkPHIValue(type, phi, parent);
+}
+
 inline SharkValue* SharkValue::address_constant(int bci)
 {
   return new SharkAddressValue(bci);