summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2015-05-20 12:31:08 +0100
committer Nicolas Geoffray <ngeoffray@google.com> 2015-05-20 18:44:51 +0100
commitdb0bbab279534974dca507946c66cff2d05dc9f9 (patch)
tree190c7ace8cfb404202a342bef51aa967592c8d6b
parent099d3750d59719cecffdf49284f2633308b9c221 (diff)
Introduce a NearLabel in thumb2.
This tells the assembler that the user knows the encoding can be in 16bits. Change-Id: Idf36c38beb1e07a69862c972484aeb08326a0499
-rw-r--r--compiler/optimizing/code_generator_arm.cc16
-rw-r--r--compiler/utils/arm/assembler_arm.h16
-rw-r--r--compiler/utils/arm/assembler_arm32.h4
-rw-r--r--compiler/utils/arm/assembler_thumb2.cc17
-rw-r--r--compiler/utils/arm/assembler_thumb2.h28
5 files changed, 62 insertions, 19 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 1c76630efe..7a0c9c1d31 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2883,7 +2883,7 @@ void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Location left = locations->InAt(0);
Location right = locations->InAt(1);
- Label less, greater, done;
+ NearLabel less, greater, done;
Primitive::Type type = compare->InputAt(0)->GetType();
switch (type) {
case Primitive::kPrimLong: {
@@ -2979,7 +2979,7 @@ void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
Register temp1,
Register temp2,
HInstruction* instruction) {
- Label fail;
+ NearLabel fail;
if (offset != 0) {
__ LoadImmediate(temp1, offset);
__ add(IP, addr, ShifterOperand(temp1));
@@ -3659,7 +3659,7 @@ void CodeGeneratorARM::MarkGCCard(Register temp,
Register object,
Register value,
bool can_be_null) {
- Label is_null;
+ NearLabel is_null;
if (can_be_null) {
__ CompareAndBranchIfZero(value, &is_null);
}
@@ -4081,14 +4081,13 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Register cls = locations->InAt(1).AsRegister<Register>();
Register out = locations->Out().AsRegister<Register>();
uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
- Label done, zero;
+ NearLabel done, zero;
SlowPathCodeARM* slow_path = nullptr;
// Return 0 if `obj` is null.
// avoid null check if we know obj is not null.
if (instruction->MustDoNullCheck()) {
- __ cmp(obj, ShifterOperand(0));
- __ b(&zero, EQ);
+ __ CompareAndBranchIfZero(obj, &zero);
}
// Compare the class of `obj` with `cls`.
__ LoadFromOffset(kLoadWord, out, obj, class_offset);
@@ -4139,16 +4138,17 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
codegen_->AddSlowPath(slow_path);
+ NearLabel done;
// avoid null check if we know obj is not null.
if (instruction->MustDoNullCheck()) {
- __ cmp(obj, ShifterOperand(0));
- __ b(slow_path->GetExitLabel(), EQ);
+ __ CompareAndBranchIfZero(obj, &done);
}
// Compare the class of `obj` with `cls`.
__ LoadFromOffset(kLoadWord, temp, obj, class_offset);
__ cmp(temp, ShifterOperand(cls));
__ b(slow_path->GetEntryLabel(), NE);
__ Bind(slow_path->GetExitLabel());
+ __ Bind(&done);
}
void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index dee8287e67..a19a7645c2 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -33,6 +33,16 @@ namespace arm {
class Arm32Assembler;
class Thumb2Assembler;
+// This class indicates that the label and its uses
+// will fall into a range that is encodable in 16bits on thumb2.
+class NearLabel : public Label {
+ public:
+ NearLabel() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NearLabel);
+};
+
class ShifterOperand {
public:
ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
@@ -519,6 +529,9 @@ class ArmAssembler : public Assembler {
// Branch instructions.
virtual void b(Label* label, Condition cond = AL) = 0;
+ virtual void b(NearLabel* label, Condition cond = AL) {
+ b(reinterpret_cast<Label*>(label), cond);
+ }
virtual void bl(Label* label, Condition cond = AL) = 0;
virtual void blx(Register rm, Condition cond = AL) = 0;
virtual void bx(Register rm, Condition cond = AL) = 0;
@@ -654,6 +667,9 @@ class ArmAssembler : public Assembler {
virtual void Bind(Label* label) = 0;
virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
+ virtual void CompareAndBranchIfZero(Register r, NearLabel* label) {
+ CompareAndBranchIfZero(r, reinterpret_cast<Label*>(label));
+ }
virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
//
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 55ec7b46d8..45647675e8 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -201,8 +201,8 @@ class Arm32Assembler FINAL : public ArmAssembler {
void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
// Branch instructions.
- void b(Label* label, Condition cond = AL);
- void bl(Label* label, Condition cond = AL);
+ void b(Label* label, Condition cond = AL) OVERRIDE;
+ void bl(Label* label, Condition cond = AL) OVERRIDE;
void blx(Register rm, Condition cond = AL) OVERRIDE;
void bx(Register rm, Condition cond = AL) OVERRIDE;
void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 75f2b77c96..c3b19da498 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -671,11 +671,17 @@ void Thumb2Assembler::vcmpdz(DRegister dd, Condition cond) {
EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
}
+
void Thumb2Assembler::b(Label* label, Condition cond) {
EmitBranch(cond, label, false, false);
}
+void Thumb2Assembler::b(NearLabel* label, Condition cond) {
+ EmitBranch(cond, label, false, false, true /* is_near */);
+}
+
+
void Thumb2Assembler::bl(Label* label, Condition cond) {
CheckCondition(cond);
EmitBranch(cond, label, true, false);
@@ -1613,7 +1619,7 @@ void Thumb2Assembler::EmitMultiMemOp(Condition cond,
}
-void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
+void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x, bool is_near) {
uint32_t pc = buffer_.Size();
Branch::Type branch_type;
if (cond == AL) {
@@ -1644,8 +1650,8 @@ void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x
}
} else {
// Branch is to an unbound label. Emit space for it.
- uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
- if (!CanRelocateBranches() || force_32bit_) {
+ uint16_t branch_id = AddBranch(branch_type, pc, cond, is_near); // Unresolved branch.
+ if (force_32bit_ || (!CanRelocateBranches() && !is_near)) {
Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
Emit16(0); // another 16 bits.
} else {
@@ -2750,6 +2756,11 @@ void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
}
+void Thumb2Assembler::CompareAndBranchIfZero(Register r, NearLabel* label) {
+ cbz(r, label);
+}
+
+
void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
if (CanRelocateBranches()) {
cbnz(r, label);
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 90d489fb02..e8def73609 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -239,6 +239,7 @@ class Thumb2Assembler FINAL : public ArmAssembler {
// Branch instructions.
void b(Label* label, Condition cond = AL);
+ void b(NearLabel* label, Condition cond = AL);
void bl(Label* label, Condition cond = AL);
void blx(Label* label);
void blx(Register rm, Condition cond = AL) OVERRIDE;
@@ -273,6 +274,7 @@ class Thumb2Assembler FINAL : public ArmAssembler {
void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE;
void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
+ void CompareAndBranchIfZero(Register r, NearLabel* label) OVERRIDE;
void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
// Memory barriers.
@@ -431,7 +433,7 @@ class Thumb2Assembler FINAL : public ArmAssembler {
void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond);
- void EmitBranch(Condition cond, Label* label, bool link, bool x);
+ void EmitBranch(Condition cond, Label* label, bool link, bool x, bool is_near = false);
static int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
static int DecodeBranchOffset(int32_t inst);
int32_t EncodeTstOffset(int offset, int32_t inst);
@@ -559,6 +561,7 @@ class Thumb2Assembler FINAL : public ArmAssembler {
// Resolve a branch when the target is known. If this causes the
// size of the branch to change return true. Otherwise return false.
bool Resolve(uint32_t target) {
+ uint32_t old_target = target_;
target_ = target;
if (assembler_->CanRelocateBranches()) {
Size new_size = CalculateSize();
@@ -569,9 +572,11 @@ class Thumb2Assembler FINAL : public ArmAssembler {
return false;
} else {
if (kIsDebugBuild) {
- Size new_size = CalculateSize();
- // Check that the size has not increased.
- DCHECK(!(new_size == k32Bit && size_ == k16Bit));
+ if (old_target == kUnresolved) {
+ DCHECK(!(CalculateSize() == k32Bit && size_ == k16Bit));
+ } else {
+ DCHECK(CalculateSize() == size_);
+ }
}
return false;
}
@@ -651,6 +656,10 @@ class Thumb2Assembler FINAL : public ArmAssembler {
if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
return k32Bit;
}
+ if (IsCompareAndBranch()) {
+ // Compare and branch instructions can only be encoded on 16 bits.
+ return k16Bit;
+ }
return assembler_->CanRelocateBranches() ? k16Bit : k32Bit;
}
// When the target is resolved, we know the best encoding for it.
@@ -714,8 +723,15 @@ class Thumb2Assembler FINAL : public ArmAssembler {
}
// Add an unresolved branch and return its id.
- uint16_t AddBranch(Branch::Type type, uint32_t location, Condition cond = AL) {
- branches_.push_back(new Branch(this, type, location, cond));
+ uint16_t AddBranch(Branch::Type type,
+ uint32_t location,
+ Condition cond = AL,
+ bool is_near = false) {
+ Branch* branch = new Branch(this, type, location, cond);
+ if (is_near) {
+ branch->ResetSize(Branch::k16Bit);
+ }
+ branches_.push_back(branch);
return branches_.size() - 1;
}