[aarch32] Apply veneers to out-of-range backwards conditional branches (#114)
Backwards (ie. bound) conditional branches that were out of range of the
immediate encoded in the instruction would fail, so apply a veneer to
these instruction by inverting the condition and using an unconditional branch.
diff --git a/src/aarch32/macro-assembler-aarch32.cc b/src/aarch32/macro-assembler-aarch32.cc
index 89101e7..9ec86fb 100644
--- a/src/aarch32/macro-assembler-aarch32.cc
+++ b/src/aarch32/macro-assembler-aarch32.cc
@@ -1245,6 +1245,53 @@
}
+void MacroAssembler::Delegate(InstructionType type,
+ InstructionCondSizeL instruction,
+ Condition cond,
+ EncodingSize size,
+ Location* location) {
+ VIXL_ASSERT(type == kB);
+
+ CONTEXT_SCOPE;
+
+ // Apply veneer to increase range of backwards conditional branches.
+ // This replaces:
+ // label:
+ // <instructions>
+ // bcond label ; T3
+ // With:
+ // label:
+ // <instructions>
+ // binvcond skip ; T1
+ // b label ; T4
+ // skip:
+ Location::Offset offset = location->GetLocation() -
+ (GetCursorOffset() + GetArchitectureStatePCOffset());
+ if (IsUsingT32() && location->IsBound() && ((offset & 0x1) == 0) &&
+ !cond.Is(al) && cond.IsNotNever()) {
+ // Bound locations must be earlier in the code.
+ VIXL_ASSERT(offset < 0);
+
+ // The offset must be within range of a T4 branch, accounting for the
+ // conditional branch (T1) we emit first, in order to jump over it.
+ offset -= k16BitT32InstructionSizeInBytes;
+ if (offset >= -16777216) {
+ CodeBufferCheckScope scope(this, k16BitT32InstructionSizeInBytes +
+ k32BitT32InstructionSizeInBytes);
+ Label skip;
+ b(cond.Negate(), Narrow, &skip);
+ b(location);
+ Bind(&skip);
+ return;
+ } else {
+ VIXL_ABORT_WITH_MSG("Conditional branch too far for veneer.\n");
+ }
+ }
+
+ Assembler::Delegate(type, instruction, cond, size, location);
+}
+
+
template <typename T>
static inline bool IsI64BitPattern(T imm) {
for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
diff --git a/src/aarch32/macro-assembler-aarch32.h b/src/aarch32/macro-assembler-aarch32.h
index 390b908..702f7cc 100644
--- a/src/aarch32/macro-assembler-aarch32.h
+++ b/src/aarch32/macro-assembler-aarch32.h
@@ -908,6 +908,12 @@
InstructionRL instruction,
Register rn,
Location* location) VIXL_OVERRIDE;
+ // B
+ virtual void Delegate(InstructionType type,
+ InstructionCondSizeL instruction,
+ Condition cond,
+ EncodingSize size,
+ Location* location) VIXL_OVERRIDE;
// VMOV
virtual void Delegate(InstructionType type,
InstructionCondDtSSop instruction,
diff --git a/test/aarch32/test-disasm-a32.cc b/test/aarch32/test-disasm-a32.cc
index c229c2f..95bb26e 100644
--- a/test/aarch32/test-disasm-a32.cc
+++ b/test/aarch32/test-disasm-a32.cc
@@ -1700,6 +1700,41 @@
}
+TEST(macro_assembler_b_cond_t32) {
+ SETUP();
+
+#ifdef VIXL_INCLUDE_TARGET_T32
+ // Ensure backward conditional branches are veneered correctly.
+ __ UseT32();
+ int pc_off = __ GetArchitectureStatePCOffset();
+
+ // Largest encodable backwards offset.
+ int curs = __ GetCursorOffset() + pc_off;
+ Label label_neg1m(curs - 1048576);
+ COMPARE_T32(B(ne, &label_neg1m), "bne 0xfff00004\n");
+
+ // Next largest cannot be encoded.
+ curs = __ GetCursorOffset() + pc_off;
+ Label label_neg1m_plus_inst(curs - (1048576 + 2));
+ COMPARE_T32(B(ne, &label_neg1m_plus_inst), "beq 0x00000006\n"
+ "b 0xfff00002\n");
+
+ // Offset that requires largest unconditional branch in veneer.
+ curs = __ GetCursorOffset() + pc_off;
+ Label label_neg16m(curs - (16777216 - 2));
+ COMPARE_T32(B(ne, &label_neg16m), "beq 0x00000006\n"
+ "b 0xff000006\n");
+
+ // Next largest cannot be veneered.
+ curs = __ GetCursorOffset() + pc_off;
+ Label label_neg16m_plus_inst(curs - 16777216);
+ MUST_FAIL_TEST_T32(B(ne, &label_neg16m_plus_inst),
+ "Conditional branch too far for veneer.\n");
+#endif
+
+ CLEANUP();
+}
+
#ifdef VIXL_NEGATIVE_TESTING
TEST(assembler_crc_negative) {
SETUP();
diff --git a/tools/code_coverage.log b/tools/code_coverage.log
index 77cbd3a..bc12d15 100644
--- a/tools/code_coverage.log
+++ b/tools/code_coverage.log
@@ -31,3 +31,4 @@
1715261843 82.84% 97.60% 94.69%
1718190785 82.85% 97.60% 94.70%
1722595938 82.94% 97.78% 94.72%
+1728570468 82.94% 97.78% 94.71%