[Optimizing] Thumb2 assembler: use 16bits branches when we can.

We cannot relocate branches, but we can at least encode branches
on 16bits when the target is known.

Change-Id: Icb6116ed974fc97e03622ac80d914c2c06f4cba2
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 7b37f74..1c76630 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -391,7 +391,7 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
-      assembler_(true),
+      assembler_(false /* can_relocate_branches */),
       isa_features_(isa_features) {
   // Save the PC register to mimic Quick.
   AddAllocatedRegister(Location::RegisterLocation(PC));
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index e7cf26e..75f2b77 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -1638,7 +1638,6 @@
     // branch the size may change if it so happens that other branches change size that change
     // the distance to the target and that distance puts this branch over the limit for 16 bits.
     if (size == Branch::k16Bit) {
-      DCHECK(!force_32bit_branches_);
       Emit16(0);          // Space for a 16 bit branch.
     } else {
       Emit32(0);            // Space for a 32 bit branch.
@@ -1646,7 +1645,7 @@
   } else {
     // Branch is to an unbound label.  Emit space for it.
     uint16_t branch_id = AddBranch(branch_type, pc, cond);    // Unresolved branch.
-    if (force_32bit_branches_ || force_32bit_) {
+    if (!CanRelocateBranches() || force_32bit_) {
       Emit16(static_cast<uint16_t>(label->position_));    // Emit current label link.
       Emit16(0);                   // another 16 bits.
     } else {
@@ -2282,7 +2281,7 @@
     uint32_t branch_location = branch->GetLocation();
     uint16_t next = buffer_.Load<uint16_t>(branch_location);       // Get next in chain.
     if (changed) {
-      DCHECK(!force_32bit_branches_);
+      DCHECK(CanRelocateBranches());
       MakeHoleForBranch(branch->GetLocation(), 2);
       if (branch->IsCompareAndBranch()) {
         // A cbz/cbnz instruction has changed size.  There is no valid encoding for
@@ -2742,21 +2741,21 @@
 
 
 void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches()) {
+    cbz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, EQ);
-  } else {
-    cbz(r, label);
   }
 }
 
 
 void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches()) {
+    cbnz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, NE);
-  } else {
-    cbnz(r, label);
   }
 }
 }  // namespace arm
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 17eae8b..90d489f 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -31,8 +31,8 @@
 
 class Thumb2Assembler FINAL : public ArmAssembler {
  public:
-  explicit Thumb2Assembler(bool force_32bit_branches = false)
-      : force_32bit_branches_(force_32bit_branches),
+  explicit Thumb2Assembler(bool can_relocate_branches = true)
+      : can_relocate_branches_(can_relocate_branches),
         force_32bit_(false),
         it_cond_index_(kNoItCondition),
         next_condition_(AL) {
@@ -52,8 +52,8 @@
     return force_32bit_;
   }
 
-  bool IsForced32BitBranches() const {
-    return force_32bit_branches_;
+  bool CanRelocateBranches() const {
+    return can_relocate_branches_;
   }
 
   void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
@@ -439,8 +439,12 @@
   void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc = false);
   void EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc = false);
 
-  bool force_32bit_branches_;  // Force the assembler to use 32 bit branch instructions.
-  bool force_32bit_;           // Force the assembler to use 32 bit thumb2 instructions.
+  // Whether the assembler can relocate branches. If false, unresolved branches will be
+  // emitted on 32bits.
+  bool can_relocate_branches_;
+
+  // Force the assembler to use 32 bit thumb2 instructions.
+  bool force_32bit_;
 
   // IfThen conditions.  Used to check that conditional instructions match the preceding IT.
   Condition it_conditions_[4];
@@ -556,12 +560,21 @@
     // size of the branch to change return true.  Otherwise return false.
     bool Resolve(uint32_t target) {
       target_ = target;
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
-        return true;
+      if (assembler_->CanRelocateBranches()) {
+        Size new_size = CalculateSize();
+        if (size_ != new_size) {
+          size_ = new_size;
+          return true;
+        }
+        return false;
+      } else {
+        if (kIsDebugBuild) {
+          Size new_size = CalculateSize();
+          // Check that the size has not increased.
+          DCHECK(!(new_size == k32Bit && size_ == k16Bit));
+        }
+        return false;
       }
-      return false;
     }
 
     // Move a cbz/cbnz branch.  This is always forward.
@@ -577,6 +590,7 @@
     // size of the branch instruction.  It returns true if the branch
     // has changed size.
     bool Relocate(uint32_t oldlocation, int32_t delta) {
+      DCHECK(assembler_->CanRelocateBranches());
       if (location_ > oldlocation) {
         location_ += delta;
       }
@@ -589,9 +603,9 @@
       }
 
       // Calculate the new size.
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
+      Size new_size = CalculateSize();
+      if (size_ != new_size) {
+        size_ = new_size;
         return true;
       }
       return false;
@@ -633,15 +647,13 @@
    private:
     // Calculate the size of the branch instruction based on its type and offset.
     Size CalculateSize() const {
-      if (assembler_->IsForced32BitBranches()) {
-        return k32Bit;
-      }
       if (target_ == kUnresolved) {
         if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
           return k32Bit;
         }
-        return k16Bit;
+        return assembler_->CanRelocateBranches() ? k16Bit : k32Bit;
       }
+      // When the target is resolved, we know the best encoding for it.
       int32_t delta = target_ - location_ - 4;
       if (delta < 0) {
         delta = -delta;