X86: Assembler support for near labels

The optimizing compiler uses 32 bit relative jumps for all forward
jumps, just in case the offset is too large to fit in one byte.  Some of
the generated code knows that the jumps will in fact fit.

Add a 'NearLabel' class to the x86 and x86_64 assemblers.  This will be
used to generate known short forward branches.

Add jecxz/jrcxz instructions, which only handle a short offset.  They
will be used for intrinsics.

Add tests for the new instructions and NearLabel.

Change-Id: I11177f36394d35d63b32364b0e6289ee6d97de46
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 731b5f4..9ac54af 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -243,4 +243,43 @@
   DriverStr(expected, "bsrl_address");
 }
 
+/////////////////
+// Near labels //
+/////////////////
+
+TEST_F(AssemblerX86Test, Jecxz) {
+  x86::NearLabel target;
+  GetAssembler()->jecxz(&target);
+  GetAssembler()->addl(x86::EDI, x86::Address(x86::ESP, 4));
+  GetAssembler()->Bind(&target);
+  const char* expected =
+    "jecxz 1f\n"
+    "addl 4(%ESP),%EDI\n"
+    "1:\n";
+
+  DriverStr(expected, "jecxz");
+}
+
+TEST_F(AssemblerX86Test, NearLabel) {
+  // Test both forward and backward branches.
+  x86::NearLabel start, target;
+  GetAssembler()->Bind(&start);
+  GetAssembler()->j(x86::kEqual, &target);
+  GetAssembler()->jmp(&target);
+  GetAssembler()->jecxz(&target);
+  GetAssembler()->addl(x86::EDI, x86::Address(x86::ESP, 4));
+  GetAssembler()->Bind(&target);
+  GetAssembler()->j(x86::kNotEqual, &start);
+  GetAssembler()->jmp(&start);
+  const char* expected =
+    "1: je 2f\n"
+    "jmp 2f\n"
+    "jecxz 2f\n"
+    "addl 4(%ESP),%EDI\n"
+    "2: jne 1b\n"
+    "jmp 1b\n";
+
+  DriverStr(expected, "near_label");
+}
+
 }  // namespace art