OSDN Git Service

ART: Implement HBooleanNot instruction
authorDavid Brazdil <dbrazdil@google.com>
Fri, 3 Apr 2015 15:02:44 +0000 (16:02 +0100)
committerDavid Brazdil <dbrazdil@google.com>
Wed, 15 Apr 2015 11:51:49 +0000 (12:51 +0100)
Optimizations simplifying operations on boolean values (boolean
simplifier, instruction simplifier) can benefit from having a special
HInstruction for negating booleans in order to perform more transforms
and produce faster machine code.

This patch implements HBooleanNot as 'x xor 1', assuming that booleans
are 1-bit integers and allowing for a single-instruction negation on
all supported platforms.

Change-Id: I33a2649c1821255b18a86ca68ed16416063c739f

compiler/optimizing/boolean_simplifier.cc
compiler/optimizing/code_generator_arm.cc
compiler/optimizing/code_generator_arm64.cc
compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/nodes.h
test/468-checker-bool-simplifier-regression/expected.txt [moved from test/468-bool-simplifier-regression/expected.txt with 100% similarity]
test/468-checker-bool-simplifier-regression/info.txt [moved from test/468-bool-simplifier-regression/info.txt with 100% similarity]
test/468-checker-bool-simplifier-regression/smali/TestCase.smali [moved from test/468-bool-simplifier-regression/smali/TestCase.smali with 100% similarity]
test/468-checker-bool-simplifier-regression/src/Main.java [moved from test/468-bool-simplifier-regression/src/Main.java with 63% similarity]

index be432c5..06328f2 100644 (file)
@@ -73,8 +73,8 @@ static HInstruction* GetOppositeCondition(HInstruction* cond) {
     }
   } else {
     // General case when 'cond' is another instruction of type boolean.
-    // Negate with 'cond == 0'.
-    return new (allocator) HEqual(cond, graph->GetIntConstant(0));
+    DCHECK_EQ(cond->GetType(), Primitive::Type::kPrimBoolean);
+    return new (allocator) HBooleanNot(cond);
   }
 }
 
index 332c99a..72b07cd 100644 (file)
@@ -2657,6 +2657,21 @@ void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
   }
 }
 
+void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
+  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
+  LocationSummary* locations = bool_not->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
+}
+
 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
index a5ddd6b..7dfb595 100644 (file)
@@ -2279,6 +2279,17 @@ void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
   }
 }
 
+void LocationsBuilderARM64::VisitBooleanNot(HBooleanNot* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM64::VisitBooleanNot(HBooleanNot* instruction) {
+  DCHECK_EQ(instruction->InputAt(0)->GetType(), Primitive::kPrimBoolean);
+  __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), vixl::Operand(1));
+}
+
 void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
index 38f9ef8..79c00ba 100644 (file)
@@ -2915,6 +2915,22 @@ void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
   }
 }
 
+void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
+  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
+  LocationSummary* locations = bool_not->GetLocations();
+  Location in = locations->InAt(0);
+  Location out = locations->Out();
+  DCHECK(in.Equals(out));
+  __ xorl(out.AsRegister<Register>(), Immediate(1));
+}
+
 void LocationsBuilderX86::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
index 7a928d4..0dd4423 100644 (file)
@@ -2974,6 +2974,22 @@ void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
   }
 }
 
+void LocationsBuilderX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
+  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
+  LocationSummary* locations = bool_not->GetLocations();
+  DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
+            locations->Out().AsRegister<CpuRegister>().AsRegister());
+  Location out = locations->Out();
+  __ xorl(out.AsRegister<CpuRegister>(), Immediate(1));
+}
+
 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
index 5f50494..e2eafe5 100644 (file)
@@ -676,6 +676,7 @@ class HLoopInformationOutwardIterator : public ValueObject {
   M(ArrayGet, Instruction)                                              \
   M(ArrayLength, Instruction)                                           \
   M(ArraySet, Instruction)                                              \
+  M(BooleanNot, UnaryOperation)                                         \
   M(BoundsCheck, Instruction)                                           \
   M(BoundType, Instruction)                                             \
   M(CheckCast, Instruction)                                             \
@@ -2643,6 +2644,33 @@ class HNot : public HUnaryOperation {
   DISALLOW_COPY_AND_ASSIGN(HNot);
 };
 
+class HBooleanNot : public HUnaryOperation {
+ public:
+  explicit HBooleanNot(HInstruction* input)
+      : HUnaryOperation(Primitive::Type::kPrimBoolean, input) {}
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    UNUSED(other);
+    return true;
+  }
+
+  int32_t Evaluate(int32_t x) const OVERRIDE {
+    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";
+    UNREACHABLE();
+  }
+
+  DECLARE_INSTRUCTION(BooleanNot);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HBooleanNot);
+};
+
 class HTypeConversion : public HExpression<1> {
  public:
   // Instantiate a type conversion of `input` to `result_type`.
 import java.lang.reflect.*;
 
 public class Main {
+  
+  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (before)
+  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
+  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
+  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
+  // CHECK-DAG:                       If [ [[Value]] ]
+  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
+  // CHECK-DAG:                       Return [ [[Phi]] ]
+
+  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
+  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
+  // CHECK-DAG:     [[Not:z\d+]]      BooleanNot [ [[Value]] ]
+  // CHECK-DAG:                       Return [ [[Not]] ]
+  
   public static boolean runTest(boolean input) throws Exception {
     Class<?> c = Class.forName("TestCase");
     Method m = c.getMethod("testCase");