OSDN Git Service

Have constant folding be more flexible.
authorRoland Levillain <rpl@google.com>
Wed, 5 Aug 2015 09:21:34 +0000 (10:21 +0100)
committerRoland Levillain <rpl@google.com>
Wed, 5 Aug 2015 10:01:53 +0000 (11:01 +0100)
- Have Evaluate methods take as argument(s) and return value
  instances of HConstant (instead of built-in 32- or 64-bit
  integer values), to let the evaluated instruction choose
  the type of the statically evaluated node; for instance,
  art::HEqual::Evaluate shall return a HIntConstant
  node (as implementation of a Boolean constant) whatever
  the type of its inputs (a pair of HIntConstant or a pair
  of HLongConstant).
- Split the evaluation job from the operation logic: the
  former is addressed by Evaluate methods, while the latter
  is done by a generic Compute method.
- Adress valid BinOp(int, long) and BinOp(long, int) cases.
- Add a constructor to art::HIntConstant to build an integer
  constant from a `bool` value.

Change-Id: If84b6fe8406bb94ddb1aa8b02e36628dff526db3

compiler/optimizing/nodes.cc
compiler/optimizing/nodes.h
test/442-checker-constant-folding/src/Main.java

index efaf48c..32ec85a 100644 (file)
@@ -1005,31 +1005,25 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
 
 HConstant* HUnaryOperation::TryStaticEvaluation() const {
   if (GetInput()->IsIntConstant()) {
-    int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
-    return GetBlock()->GetGraph()->GetIntConstant(value);
+    return Evaluate(GetInput()->AsIntConstant());
   } else if (GetInput()->IsLongConstant()) {
-    int64_t value = Evaluate(GetInput()->AsLongConstant()->GetValue());
-    return GetBlock()->GetGraph()->GetLongConstant(value);
+    return Evaluate(GetInput()->AsLongConstant());
   }
   return nullptr;
 }
 
 HConstant* HBinaryOperation::TryStaticEvaluation() const {
-  if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
-    int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
-                             GetRight()->AsIntConstant()->GetValue());
-    return GetBlock()->GetGraph()->GetIntConstant(value);
-  } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
-    int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
-                             GetRight()->AsLongConstant()->GetValue());
-    if (GetResultType() == Primitive::kPrimLong) {
-      return GetBlock()->GetGraph()->GetLongConstant(value);
-    } else if (GetResultType() == Primitive::kPrimBoolean) {
-      // This can be the result of an HCondition evaluation.
-      return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
-    } else {
-      DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
-      return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
+  if (GetLeft()->IsIntConstant()) {
+    if (GetRight()->IsIntConstant()) {
+      return Evaluate(GetLeft()->AsIntConstant(), GetRight()->AsIntConstant());
+    } else if (GetRight()->IsLongConstant()) {
+      return Evaluate(GetLeft()->AsIntConstant(), GetRight()->AsLongConstant());
+    }
+  } else if (GetLeft()->IsLongConstant()) {
+    if (GetRight()->IsIntConstant()) {
+      return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsIntConstant());
+    } else if (GetRight()->IsLongConstant()) {
+      return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant());
     }
   }
   return nullptr;
index 1190fae..10d8869 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_NODES_H_
 #define ART_COMPILER_OPTIMIZING_NODES_H_
 
+#include <type_traits>
+
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "dex/compiler_enums.h"
@@ -1551,6 +1553,7 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> {
   HInstruction* GetPreviousDisregardingMoves() const;
 
   HBasicBlock* GetBlock() const { return block_; }
+  ArenaAllocator* GetArena() const { return block_->GetGraph()->GetArena(); }
   void SetBlock(HBasicBlock* block) { block_ = block; }
   bool IsInBlock() const { return block_ != nullptr; }
   bool IsInLoop() const { return block_->IsInLoop(); }
@@ -2017,6 +2020,95 @@ class HGoto : public HTemplateInstruction<0> {
   DISALLOW_COPY_AND_ASSIGN(HGoto);
 };
 
+class HConstant : public HExpression<0> {
+ public:
+  explicit HConstant(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+
+  virtual bool IsMinusOne() const { return false; }
+  virtual bool IsZero() const { return false; }
+  virtual bool IsOne() const { return false; }
+
+  DECLARE_INSTRUCTION(Constant);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HConstant);
+};
+
+class HNullConstant : public HConstant {
+ public:
+  bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+    return true;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE { return 0; }
+
+  DECLARE_INSTRUCTION(NullConstant);
+
+ private:
+  HNullConstant() : HConstant(Primitive::kPrimNot) {}
+
+  friend class HGraph;
+  DISALLOW_COPY_AND_ASSIGN(HNullConstant);
+};
+
+// Constants of the type int. Those can be from Dex instructions, or
+// synthesized (for example with the if-eqz instruction).
+class HIntConstant : public HConstant {
+ public:
+  int32_t GetValue() const { return value_; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    DCHECK(other->IsIntConstant());
+    return other->AsIntConstant()->value_ == value_;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE { return GetValue(); }
+
+  bool IsMinusOne() const OVERRIDE { return GetValue() == -1; }
+  bool IsZero() const OVERRIDE { return GetValue() == 0; }
+  bool IsOne() const OVERRIDE { return GetValue() == 1; }
+
+  DECLARE_INSTRUCTION(IntConstant);
+
+ private:
+  explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
+  explicit HIntConstant(bool value) : HConstant(Primitive::kPrimInt), value_(value ? 1 : 0) {}
+
+  const int32_t value_;
+
+  friend class HGraph;
+  ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
+  ART_FRIEND_TYPED_TEST(ParallelMoveTest, ConstantLast);
+  DISALLOW_COPY_AND_ASSIGN(HIntConstant);
+};
+
+class HLongConstant : public HConstant {
+ public:
+  int64_t GetValue() const { return value_; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    DCHECK(other->IsLongConstant());
+    return other->AsLongConstant()->value_ == value_;
+  }
+
+  size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
+
+  bool IsMinusOne() const OVERRIDE { return GetValue() == -1; }
+  bool IsZero() const OVERRIDE { return GetValue() == 0; }
+  bool IsOne() const OVERRIDE { return GetValue() == 1; }
+
+  DECLARE_INSTRUCTION(LongConstant);
+
+ private:
+  explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
+
+  const int64_t value_;
+
+  friend class HGraph;
+  DISALLOW_COPY_AND_ASSIGN(HLongConstant);
+};
 
 // Conditional branch. A block ending with an HIf instruction must have
 // two successors.
@@ -2166,8 +2258,8 @@ class HUnaryOperation : public HExpression<1> {
   HConstant* TryStaticEvaluation() const;
 
   // Apply this operation to `x`.
-  virtual int32_t Evaluate(int32_t x) const = 0;
-  virtual int64_t Evaluate(int64_t x) const = 0;
+  virtual HConstant* Evaluate(HIntConstant* x) const = 0;
+  virtual HConstant* Evaluate(HLongConstant* x) const = 0;
 
   DECLARE_INSTRUCTION(UnaryOperation);
 
@@ -2234,8 +2326,18 @@ class HBinaryOperation : public HExpression<2> {
   HConstant* TryStaticEvaluation() const;
 
   // Apply this operation to `x` and `y`.
-  virtual int32_t Evaluate(int32_t x, int32_t y) const = 0;
-  virtual int64_t Evaluate(int64_t x, int64_t y) const = 0;
+  virtual HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const = 0;
+  virtual HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const = 0;
+  virtual HConstant* Evaluate(HIntConstant* x ATTRIBUTE_UNUSED,
+                              HLongConstant* y ATTRIBUTE_UNUSED) const {
+    VLOG(compiler) << DebugName() << " is not defined for the (int, long) case.";
+    return nullptr;
+  }
+  virtual HConstant* Evaluate(HLongConstant* x ATTRIBUTE_UNUSED,
+                              HIntConstant* y ATTRIBUTE_UNUSED) const {
+    VLOG(compiler) << DebugName() << " is not defined for the (long, int) case.";
+    return nullptr;
+  }
 
   // Returns an input that can legally be used as the right input and is
   // constant, or null.
@@ -2318,11 +2420,13 @@ class HEqual : public HCondition {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x == y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x == y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x == y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(Equal);
@@ -2346,11 +2450,13 @@ class HNotEqual : public HCondition {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x != y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x != y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x != y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(NotEqual);
@@ -2372,11 +2478,13 @@ class HLessThan : public HCondition {
   HLessThan(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x < y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x < y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x < y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(LessThan);
@@ -2398,11 +2506,13 @@ class HLessThanOrEqual : public HCondition {
   HLessThanOrEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x <= y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x <= y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x <= y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(LessThanOrEqual);
@@ -2424,11 +2534,13 @@ class HGreaterThan : public HCondition {
   HGreaterThan(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x > y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x > y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x > y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(GreaterThan);
@@ -2450,11 +2562,13 @@ class HGreaterThanOrEqual : public HCondition {
   HGreaterThanOrEqual(HInstruction* first, HInstruction* second)
       : HCondition(first, second) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x >= y ? 1 : 0;
+  template <typename T> bool Compute(T x, T y) const { return x >= y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x >= y ? 1 : 0;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(GreaterThanOrEqual);
@@ -2486,18 +2600,14 @@ class HCompare : public HBinaryOperation {
     DCHECK_EQ(type, second->GetType());
   }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return
-      x == y ? 0 :
-      x > y ? 1 :
-      -1;
-  }
+  template <typename T>
+  int32_t Compute(T x, T y) const { return x == y ? 0 : x > y ? 1 : -1; }
 
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return
-      x == y ? 0 :
-      x > y ? 1 :
-      -1;
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2569,27 +2679,12 @@ class HStoreLocal : public HTemplateInstruction<2> {
   DISALLOW_COPY_AND_ASSIGN(HStoreLocal);
 };
 
-class HConstant : public HExpression<0> {
- public:
-  explicit HConstant(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
-
-  bool CanBeMoved() const OVERRIDE { return true; }
-
-  virtual bool IsMinusOne() const { return false; }
-  virtual bool IsZero() const { return false; }
-  virtual bool IsOne() const { return false; }
-
-  DECLARE_INSTRUCTION(Constant);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HConstant);
-};
-
 class HFloatConstant : public HConstant {
  public:
   float GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    DCHECK(other->IsFloatConstant());
     return bit_cast<uint32_t, float>(other->AsFloatConstant()->value_) ==
         bit_cast<uint32_t, float>(value_);
   }
@@ -2629,6 +2724,7 @@ class HDoubleConstant : public HConstant {
   double GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    DCHECK(other->IsDoubleConstant());
     return bit_cast<uint64_t, double>(other->AsDoubleConstant()->value_) ==
         bit_cast<uint64_t, double>(value_);
   }
@@ -2663,77 +2759,6 @@ class HDoubleConstant : public HConstant {
   DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
 };
 
-class HNullConstant : public HConstant {
- public:
-  bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
-    return true;
-  }
-
-  size_t ComputeHashCode() const OVERRIDE { return 0; }
-
-  DECLARE_INSTRUCTION(NullConstant);
-
- private:
-  HNullConstant() : HConstant(Primitive::kPrimNot) {}
-
-  friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HNullConstant);
-};
-
-// Constants of the type int. Those can be from Dex instructions, or
-// synthesized (for example with the if-eqz instruction).
-class HIntConstant : public HConstant {
- public:
-  int32_t GetValue() const { return value_; }
-
-  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
-    return other->AsIntConstant()->value_ == value_;
-  }
-
-  size_t ComputeHashCode() const OVERRIDE { return GetValue(); }
-
-  bool IsMinusOne() const OVERRIDE { return GetValue() == -1; }
-  bool IsZero() const OVERRIDE { return GetValue() == 0; }
-  bool IsOne() const OVERRIDE { return GetValue() == 1; }
-
-  DECLARE_INSTRUCTION(IntConstant);
-
- private:
-  explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
-
-  const int32_t value_;
-
-  friend class HGraph;
-  ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
-  ART_FRIEND_TYPED_TEST(ParallelMoveTest, ConstantLast);
-  DISALLOW_COPY_AND_ASSIGN(HIntConstant);
-};
-
-class HLongConstant : public HConstant {
- public:
-  int64_t GetValue() const { return value_; }
-
-  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
-    return other->AsLongConstant()->value_ == value_;
-  }
-
-  size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
-
-  bool IsMinusOne() const OVERRIDE { return GetValue() == -1; }
-  bool IsZero() const OVERRIDE { return GetValue() == 0; }
-  bool IsOne() const OVERRIDE { return GetValue() == 1; }
-
-  DECLARE_INSTRUCTION(LongConstant);
-
- private:
-  explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
-
-  const int64_t value_;
-
-  friend class HGraph;
-  DISALLOW_COPY_AND_ASSIGN(HLongConstant);
-};
-
 enum class Intrinsics {
 #define OPTIMIZING_INTRINSICS(Name, IsStatic) k ## Name,
 #include "intrinsics_list.h"
@@ -3052,8 +3077,14 @@ class HNeg : public HUnaryOperation {
   explicit HNeg(Primitive::Type result_type, HInstruction* input)
       : HUnaryOperation(result_type, input) {}
 
-  int32_t Evaluate(int32_t x) const OVERRIDE { return -x; }
-  int64_t Evaluate(int64_t x) const OVERRIDE { return -x; }
+  template <typename T> T Compute(T x) const { return -x; }
+
+  HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(Neg);
 
@@ -3110,11 +3141,13 @@ class HAdd : public HBinaryOperation {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x + y;
+  template <typename T> T Compute(T x, T y) const { return x + y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x + y;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(Add);
@@ -3128,11 +3161,13 @@ class HSub : public HBinaryOperation {
   HSub(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    return x - y;
+  template <typename T> T Compute(T x, T y) const { return x - y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
   }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    return x - y;
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   DECLARE_INSTRUCTION(Sub);
@@ -3148,8 +3183,14 @@ class HMul : public HBinaryOperation {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x * y; }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x * y; }
+  template <typename T> T Compute(T x, T y) const { return x * y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(Mul);
 
@@ -3162,17 +3203,20 @@ class HDiv : public HBinaryOperation {
   HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
       : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    // Our graph structure ensures we never have 0 for `y` during constant folding.
+  template <typename T>
+  T Compute(T x, T y) const {
+    // Our graph structure ensures we never have 0 for `y` during
+    // constant folding.
     DCHECK_NE(y, 0);
     // Special case -1 to avoid getting a SIGFPE on x86(_64).
     return (y == -1) ? -x : x / y;
   }
 
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    DCHECK_NE(y, 0);
-    // Special case -1 to avoid getting a SIGFPE on x86(_64).
-    return (y == -1) ? -x : x / y;
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
@@ -3190,16 +3234,20 @@ class HRem : public HBinaryOperation {
   HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
       : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
+  template <typename T>
+  T Compute(T x, T y) const {
+    // Our graph structure ensures we never have 0 for `y` during
+    // constant folding.
     DCHECK_NE(y, 0);
     // Special case -1 to avoid getting a SIGFPE on x86(_64).
     return (y == -1) ? 0 : x % y;
   }
 
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    DCHECK_NE(y, 0);
-    // Special case -1 to avoid getting a SIGFPE on x86(_64).
-    return (y == -1) ? 0 : x % y;
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
   }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
@@ -3244,8 +3292,27 @@ class HShl : public HBinaryOperation {
   HShl(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x << (y & kMaxIntShiftValue); }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x << (y & kMaxLongShiftValue); }
+  template <typename T, typename U, typename V>
+  T Compute(T x, U y, V max_shift_value) const {
+    static_assert(std::is_same<V, typename std::make_unsigned<T>::type>::value,
+                  "V is not the unsigned integer type corresponding to T");
+    return x << (y & max_shift_value);
+  }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+  }
+  // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
+  // case is handled as `x << static_cast<int>(y)`.
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+  }
 
   DECLARE_INSTRUCTION(Shl);
 
@@ -3258,8 +3325,27 @@ class HShr : public HBinaryOperation {
   HShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x >> (y & kMaxIntShiftValue); }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x >> (y & kMaxLongShiftValue); }
+  template <typename T, typename U, typename V>
+  T Compute(T x, U y, V max_shift_value) const {
+    static_assert(std::is_same<V, typename std::make_unsigned<T>::type>::value,
+                  "V is not the unsigned integer type corresponding to T");
+    return x >> (y & max_shift_value);
+  }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+  }
+  // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
+  // case is handled as `x >> static_cast<int>(y)`.
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+  }
 
   DECLARE_INSTRUCTION(Shr);
 
@@ -3272,16 +3358,27 @@ class HUShr : public HBinaryOperation {
   HUShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
       : HBinaryOperation(result_type, left, right) {}
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE {
-    uint32_t ux = static_cast<uint32_t>(x);
-    uint32_t uy = static_cast<uint32_t>(y) & kMaxIntShiftValue;
-    return static_cast<int32_t>(ux >> uy);
+  template <typename T, typename U, typename V>
+  T Compute(T x, U y, V max_shift_value) const {
+    static_assert(std::is_same<V, typename std::make_unsigned<T>::type>::value,
+                  "V is not the unsigned integer type corresponding to T");
+    V ux = static_cast<V>(x);
+    return static_cast<T>(ux >> (y & max_shift_value));
   }
 
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE {
-    uint64_t ux = static_cast<uint64_t>(x);
-    uint64_t uy = static_cast<uint64_t>(y) & kMaxLongShiftValue;
-    return static_cast<int64_t>(ux >> uy);
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+  }
+  // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
+  // case is handled as `x >>> static_cast<int>(y)`.
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
   }
 
   DECLARE_INSTRUCTION(UShr);
@@ -3297,8 +3394,21 @@ class HAnd : public HBinaryOperation {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; }
+  template <typename T, typename U>
+  auto Compute(T x, U y) const -> decltype(x & y) { return x & y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(And);
 
@@ -3313,8 +3423,21 @@ class HOr : public HBinaryOperation {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; }
+  template <typename T, typename U>
+  auto Compute(T x, U y) const -> decltype(x | y) { return x | y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(Or);
 
@@ -3329,8 +3452,21 @@ class HXor : public HBinaryOperation {
 
   bool IsCommutative() const OVERRIDE { return true; }
 
-  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; }
-  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; }
+  template <typename T, typename U>
+  auto Compute(T x, U y) const -> decltype(x ^ y) { return x ^ y; }
+
+  HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(Xor);
 
@@ -3375,8 +3511,14 @@ class HNot : public HUnaryOperation {
     return true;
   }
 
-  int32_t Evaluate(int32_t x) const OVERRIDE { return ~x; }
-  int64_t Evaluate(int64_t x) const OVERRIDE { return ~x; }
+  template <typename T> T Compute(T x) const { return ~x; }
+
+  HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+  }
 
   DECLARE_INSTRUCTION(Not);
 
@@ -3395,13 +3537,16 @@ class HBooleanNot : public HUnaryOperation {
     return true;
   }
 
-  int32_t Evaluate(int32_t x) const OVERRIDE {
+  template <typename T> bool Compute(T x) const {
     DCHECK(IsUint<1>(x));
     return !x;
   }
 
-  int64_t Evaluate(int64_t x ATTRIBUTE_UNUSED) const OVERRIDE {
-    LOG(FATAL) << DebugName() << " cannot be used with 64-bit values";
+  HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+  }
+  HConstant* Evaluate(HLongConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
+    LOG(FATAL) << DebugName() << " is not defined for long values";
     UNREACHABLE();
   }
 
index 4805d77..59e7282 100644 (file)
@@ -363,6 +363,273 @@ public class Main {
 
 
   /**
+   * Exercise constant folding on left shift.
+   */
+
+  /// CHECK-START: int Main.ShlIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Const2L:j\d+>>  LongConstant 2
+  /// CHECK-DAG:     <<TypeConv:i\d+>> TypeConversion [<<Const2L>>]
+  /// CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Const1>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
+
+  /// CHECK-START: int Main.ShlIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<Const4:i\d+>>   IntConstant 4
+  /// CHECK-DAG:                       Return [<<Const4>>]
+
+  /// CHECK-START: int Main.ShlIntLong() constant_folding (after)
+  /// CHECK-NOT:                       Shl
+
+  public static int ShlIntLong() {
+    int lhs = 1;
+    long rhs = 2;
+    return lhs << rhs;
+  }
+
+  /// CHECK-START: long Main.ShlLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<Const3L:j\d+>>  LongConstant 3
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<Shl:j\d+>>      Shl [<<Const3L>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
+
+  /// CHECK-START: long Main.ShlLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<Const12L:j\d+>> LongConstant 12
+  /// CHECK-DAG:                       Return [<<Const12L>>]
+
+  /// CHECK-START: long Main.ShlLongInt() constant_folding (after)
+  /// CHECK-NOT:                       Shl
+
+  public static long ShlLongInt() {
+    long lhs = 3;
+    int rhs = 2;
+    return lhs << rhs;
+  }
+
+
+  /**
+   * Exercise constant folding on right shift.
+   */
+
+  /// CHECK-START: int Main.ShrIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<Const7:i\d+>>   IntConstant 7
+  /// CHECK-DAG:     <<Const2L:j\d+>>  LongConstant 2
+  /// CHECK-DAG:     <<TypeConv:i\d+>> TypeConversion [<<Const2L>>]
+  /// CHECK-DAG:     <<Shr:i\d+>>      Shr [<<Const7>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<Shr>>]
+
+  /// CHECK-START: int Main.ShrIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:                       Return [<<Const1>>]
+
+  /// CHECK-START: int Main.ShrIntLong() constant_folding (after)
+  /// CHECK-NOT:                       Shr
+
+  public static int ShrIntLong() {
+    int lhs = 7;
+    long rhs = 2;
+    return lhs >> rhs;
+  }
+
+  /// CHECK-START: long Main.ShrLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<Const9L:j\d+>>  LongConstant 9
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Const9L>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Shr>>]
+
+  /// CHECK-START: long Main.ShrLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<Const2L:j\d+>>  LongConstant 2
+  /// CHECK-DAG:                       Return [<<Const2L>>]
+
+  /// CHECK-START: long Main.ShrLongInt() constant_folding (after)
+  /// CHECK-NOT:                       Shr
+
+  public static long ShrLongInt() {
+    long lhs = 9;
+    int rhs = 2;
+    return lhs >> rhs;
+  }
+
+
+  /**
+   * Exercise constant folding on unsigned right shift.
+   */
+
+  /// CHECK-START: int Main.UShrIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<ConstM7:i\d+>>  IntConstant -7
+  /// CHECK-DAG:     <<Const2L:j\d+>>  LongConstant 2
+  /// CHECK-DAG:     <<TypeConv:i\d+>> TypeConversion [<<Const2L>>]
+  /// CHECK-DAG:     <<UShr:i\d+>>     UShr [<<ConstM7>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<UShr>>]
+
+  /// CHECK-START: int Main.UShrIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<ConstRes:i\d+>> IntConstant 1073741822
+  /// CHECK-DAG:                       Return [<<ConstRes>>]
+
+  /// CHECK-START: int Main.UShrIntLong() constant_folding (after)
+  /// CHECK-NOT:                       UShr
+
+  public static int UShrIntLong() {
+    int lhs = -7;
+    long rhs = 2;
+    return lhs >>> rhs;
+  }
+
+  /// CHECK-START: long Main.UShrLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<ConstM9L:j\d+>> LongConstant -9
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<UShr:j\d+>>     UShr [<<ConstM9L>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<UShr>>]
+
+  /// CHECK-START: long Main.UShrLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<ConstRes:j\d+>> LongConstant 4611686018427387901
+  /// CHECK-DAG:                       Return [<<ConstRes>>]
+
+  /// CHECK-START: long Main.UShrLongInt() constant_folding (after)
+  /// CHECK-NOT:                       UShr
+
+  public static long UShrLongInt() {
+    long lhs = -9;
+    int rhs = 2;
+    return lhs >>> rhs;
+  }
+
+
+  /**
+   * Exercise constant folding on logical and.
+   */
+
+  /// CHECK-START: long Main.AndIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<Const10:i\d+>>  IntConstant 10
+  /// CHECK-DAG:     <<Const3L:j\d+>>  LongConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const10>>]
+  /// CHECK-DAG:     <<And:j\d+>>      And [<<TypeConv>>,<<Const3L>>]
+  /// CHECK-DAG:                       Return [<<And>>]
+
+  /// CHECK-START: long Main.AndIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<Const2:j\d+>>   LongConstant 2
+  /// CHECK-DAG:                       Return [<<Const2>>]
+
+  /// CHECK-START: long Main.AndIntLong() constant_folding (after)
+  /// CHECK-NOT:                       And
+
+  public static long AndIntLong() {
+    int lhs = 10;
+    long rhs = 3;
+    return lhs & rhs;
+  }
+
+  /// CHECK-START: long Main.AndLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<Const10L:j\d+>> LongConstant 10
+  /// CHECK-DAG:     <<Const3:i\d+>>   IntConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const3>>]
+  /// CHECK-DAG:     <<And:j\d+>>      And [<<Const10L>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<And>>]
+
+  /// CHECK-START: long Main.AndLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<Const2:j\d+>>   LongConstant 2
+  /// CHECK-DAG:                       Return [<<Const2>>]
+
+  /// CHECK-START: long Main.AndLongInt() constant_folding (after)
+  /// CHECK-NOT:                       And
+
+  public static long AndLongInt() {
+    long lhs = 10;
+    int rhs = 3;
+    return lhs & rhs;
+  }
+
+
+  /**
+   * Exercise constant folding on logical or.
+   */
+
+  /// CHECK-START: long Main.OrIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<Const10:i\d+>>  IntConstant 10
+  /// CHECK-DAG:     <<Const3L:j\d+>>  LongConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const10>>]
+  /// CHECK-DAG:     <<Or:j\d+>>       Or [<<TypeConv>>,<<Const3L>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
+
+  /// CHECK-START: long Main.OrIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<Const11:j\d+>>  LongConstant 11
+  /// CHECK-DAG:                       Return [<<Const11>>]
+
+  /// CHECK-START: long Main.OrIntLong() constant_folding (after)
+  /// CHECK-NOT:                       Or
+
+  public static long OrIntLong() {
+    int lhs = 10;
+    long rhs = 3;
+    return lhs | rhs;
+  }
+
+  /// CHECK-START: long Main.OrLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<Const10L:j\d+>> LongConstant 10
+  /// CHECK-DAG:     <<Const3:i\d+>>   IntConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const3>>]
+  /// CHECK-DAG:     <<Or:j\d+>>       Or [<<Const10L>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
+
+  /// CHECK-START: long Main.OrLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<Const11:j\d+>>  LongConstant 11
+  /// CHECK-DAG:                       Return [<<Const11>>]
+
+  /// CHECK-START: long Main.OrLongInt() constant_folding (after)
+  /// CHECK-NOT:                       Or
+
+  public static long OrLongInt() {
+    long lhs = 10;
+    int rhs = 3;
+    return lhs | rhs;
+  }
+
+
+  /**
+   * Exercise constant folding on logical exclusive or.
+   */
+
+  /// CHECK-START: long Main.XorIntLong() constant_folding (before)
+  /// CHECK-DAG:     <<Const10:i\d+>>  IntConstant 10
+  /// CHECK-DAG:     <<Const3L:j\d+>>  LongConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const10>>]
+  /// CHECK-DAG:     <<Xor:j\d+>>      Xor [<<TypeConv>>,<<Const3L>>]
+  /// CHECK-DAG:                       Return [<<Xor>>]
+
+  /// CHECK-START: long Main.XorIntLong() constant_folding (after)
+  /// CHECK-DAG:     <<Const9:j\d+>>   LongConstant 9
+  /// CHECK-DAG:                       Return [<<Const9>>]
+
+  /// CHECK-START: long Main.XorIntLong() constant_folding (after)
+  /// CHECK-NOT:                       Xor
+
+  public static long XorIntLong() {
+    int lhs = 10;
+    long rhs = 3;
+    return lhs ^ rhs;
+  }
+
+  /// CHECK-START: long Main.XorLongInt() constant_folding (before)
+  /// CHECK-DAG:     <<Const10L:j\d+>> LongConstant 10
+  /// CHECK-DAG:     <<Const3:i\d+>>   IntConstant 3
+  /// CHECK-DAG:     <<TypeConv:j\d+>> TypeConversion [<<Const3>>]
+  /// CHECK-DAG:     <<Xor:j\d+>>      Xor [<<Const10L>>,<<TypeConv>>]
+  /// CHECK-DAG:                       Return [<<Xor>>]
+
+  /// CHECK-START: long Main.XorLongInt() constant_folding (after)
+  /// CHECK-DAG:     <<Const9:j\d+>>   LongConstant 9
+  /// CHECK-DAG:                       Return [<<Const9>>]
+
+  /// CHECK-START: long Main.XorLongInt() constant_folding (after)
+  /// CHECK-NOT:                       Xor
+
+  public static long XorLongInt() {
+    long lhs = 10;
+    int rhs = 3;
+    return lhs ^ rhs;
+  }
+
+
+  /**
    * Exercise constant folding on constant (static) condition.
    */
 
@@ -558,6 +825,25 @@ public class Main {
     return 0 << arg;
   }
 
+  /// CHECK-START: long Main.ShlLong0WithInt(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0L:j\d+>>  LongConstant 0
+  /// CHECK-DAG:     <<Shl:j\d+>>      Shl [<<Const0L>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
+
+  /// CHECK-START: long Main.ShlLong0WithInt(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0L:j\d+>>  LongConstant 0
+  /// CHECK-DAG:                       Return [<<Const0L>>]
+
+  /// CHECK-START: long Main.ShlLong0WithInt(int) constant_folding (after)
+  /// CHECK-NOT:                       Shl
+
+  public static long ShlLong0WithInt(int arg) {
+    long long_zero = 0;
+    return long_zero << arg;
+  }
+
   /// CHECK-START: long Main.Shr0(int) constant_folding (before)
   /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
   /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
@@ -903,6 +1189,24 @@ public class Main {
     assertIntEquals(2, IntRemainder());
     assertLongEquals(2L, LongRemainder());
 
+    assertIntEquals(4, ShlIntLong());
+    assertLongEquals(12L, ShlLongInt());
+
+    assertIntEquals(1, ShrIntLong());
+    assertLongEquals(2L, ShrLongInt());
+
+    assertIntEquals(1073741822, UShrIntLong());
+    assertLongEquals(4611686018427387901L, UShrLongInt());
+
+    assertLongEquals(2, AndIntLong());
+    assertLongEquals(2, AndLongInt());
+
+    assertLongEquals(11, OrIntLong());
+    assertLongEquals(11, OrLongInt());
+
+    assertLongEquals(9, XorIntLong());
+    assertLongEquals(9, XorLongInt());
+
     assertIntEquals(5, StaticCondition());
 
     assertIntEquals(7, JumpsAndConditionals(true));
@@ -917,6 +1221,7 @@ public class Main {
     assertIntEquals(0, Rem1(arbitrary));
     assertLongEquals(0, RemN1(arbitrary));
     assertIntEquals(0, Shl0(arbitrary));
+    assertLongEquals(0, ShlLong0WithInt(arbitrary));
     assertLongEquals(0, Shr0(arbitrary));
     assertLongEquals(0, SubSameLong(arbitrary));
     assertIntEquals(0, UShr0(arbitrary));