Have constant folding be more flexible.
- 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
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index efaf48c..32ec85a 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1005,31 +1005,25 @@
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;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 1190fae..10d8869 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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();
}
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 4805d77..59e7282 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -363,6 +363,273 @@
/**
+ * 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 @@
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 @@
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 @@
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));