OSDN Git Service

Reuse promoted register temporarily
authorYevgeny Rouban <yevgeny.y.rouban@intel.com>
Tue, 18 Mar 2014 08:55:16 +0000 (15:55 +0700)
committerIan Rogers <irogers@google.com>
Wed, 26 Mar 2014 22:06:23 +0000 (15:06 -0700)
AtomicLong (x86) is implemented as an intrinsic, which uses
the cmpxchng8b instruction.
This instruction requires 4 physical registers plus 2 more used for
the memory operand. On x86 we have only 4 temporaries. The code tried
to solve this by using MarkTemp utility, but this was not meant to be
used with promoted registers. The problem is that MarkTemp does not
spill anything and as a result we can lose VR.

If the registers are promoted this patch just reuses the values pushed
on the stack.

Change-Id: Ifec9183e2483cf704d0d1166a1004a9aa07b4f1d
Signed-off-by: Serguei Katkov <serguei.i.katkov@intel.com>
Signed-off-by: Yevgeny Rouban <yevgeny.y.rouban@intel.com>
compiler/dex/quick/x86/int_x86.cc
test/083-compiler-regressions/expected.txt
test/083-compiler-regressions/src/Main.java

index 1fe0af9..c929265 100644 (file)
@@ -734,6 +734,10 @@ void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
   NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val);
 }
 
+static bool IsInReg(X86Mir2Lir *pMir2Lir, const RegLocation &rl, int reg) {
+  return !rl.reg.IsInvalid() && rl.reg.GetReg() == reg && (pMir2Lir->IsLive(reg) || rl.home);
+}
+
 bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
   DCHECK_EQ(cu_->instruction_set, kX86);
   // Unused - RegLocation rl_src_unsafe = info->args[0];
@@ -746,6 +750,8 @@ bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
   // If is_long, high half is in info->args[7]
 
   if (is_long) {
+    // TODO: avoid unnecessary loads of SI and DI when the values are in registers.
+    // TODO: CFI support.
     FlushAllRegs();
     LockCallTemps();
     LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
@@ -757,8 +763,14 @@ bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
     MarkTemp(rSI);
     LockTemp(rSI);
     const int push_offset = 4 /* push edi */ + 4 /* push esi */;
-    LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_obj.s_reg_low) + push_offset, rDI);
-    LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_offset.s_reg_low) + push_offset, rSI);
+    int srcObjSp = IsInReg(this, rl_src_obj, rSI) ? 0
+                : (IsInReg(this, rl_src_obj, rDI) ? 4
+                : (SRegOffset(rl_src_obj.s_reg_low) + push_offset));
+    LoadWordDisp(TargetReg(kSp), srcObjSp, rDI);
+    int srcOffsetSp = IsInReg(this, rl_src_offset, rSI) ? 0
+                   : (IsInReg(this, rl_src_offset, rDI) ? 4
+                   : (SRegOffset(rl_src_offset.s_reg_low) + push_offset));
+    LoadWordDisp(TargetReg(kSp), srcOffsetSp, rSI);
     NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
     FreeTemp(rSI);
     UnmarkTemp(rSI);
index 90d8634..f6de0e7 100644 (file)
@@ -16,3 +16,4 @@ longDivTest passes
 longModTest passes
 testIfCcz passes
 ManyFloatArgs passes
+atomicLong passes
index 96c71cf..2745c27 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * Test for Jit regressions.
@@ -47,6 +48,18 @@ public class Main {
         ZeroTests.longModTest();
         MirOpSelectTests.testIfCcz();
         ManyFloatArgs();
+        atomicLong();
+    }
+
+    public static void atomicLong() {
+        AtomicLong atomicLong = new AtomicLong();
+        atomicLong.addAndGet(3);
+        atomicLong.addAndGet(2);
+        atomicLong.addAndGet(1);
+        long result = atomicLong.get();
+        System.out.println(result == 6L ? "atomicLong passes" :
+          ("atomicLong failes: returns " + result + ", expected 6")
+        );
     }
 
     public static void returnConstantTest() {