Create separate Android.mk for main build targets

The runtime, compiler, dex2oat, and oatdump now are in seperate trees
to prevent dependency creep.  They can now be individually built
without rebuilding the rest of the art projects. dalvikvm and jdwpspy
were already this way. Builds in the art directory should behave as
before, building everything including tests.

Change-Id: Ic6b1151e5ed0f823c3dd301afd2b13eb2d8feb81
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
new file mode 100644
index 0000000..6a25c1d
--- /dev/null
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex/compiler_ir.h"
+#include "dex/compiler_internals.h"
+#include "dex/quick/mir_to_lir-inl.h"
+#include "invoke_type.h"
+
+namespace art {
+
+/* This file contains target-independent codegen and support. */
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked in_use.
+ */
+LIR* Mir2Lir::LoadConstant(int r_dest, int value)
+{
+  if (IsTemp(r_dest)) {
+    Clobber(r_dest);
+    MarkInUse(r_dest);
+  }
+  return LoadConstantNoClobber(r_dest, value);
+}
+
+/*
+ * Temporary workaround for Issue 7250540.  If we're loading a constant zero into a
+ * promoted floating point register, also copy a zero into the int/ref identity of
+ * that sreg.
+ */
+void Mir2Lir::Workaround7250540(RegLocation rl_dest, int zero_reg)
+{
+  if (rl_dest.fp) {
+    int pmap_index = SRegToPMap(rl_dest.s_reg_low);
+    if (promotion_map_[pmap_index].fp_location == kLocPhysReg) {
+      // Now, determine if this vreg is ever used as a reference.  If not, we're done.
+      bool used_as_reference = false;
+      int base_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+      for (int i = 0; !used_as_reference && (i < mir_graph_->GetNumSSARegs()); i++) {
+        if (mir_graph_->SRegToVReg(mir_graph_->reg_location_[i].s_reg_low) == base_vreg) {
+          used_as_reference |= mir_graph_->reg_location_[i].ref;
+        }
+      }
+      if (!used_as_reference) {
+        return;
+      }
+      int temp_reg = zero_reg;
+      if (temp_reg == INVALID_REG) {
+        temp_reg = AllocTemp();
+        LoadConstant(temp_reg, 0);
+      }
+      if (promotion_map_[pmap_index].core_location == kLocPhysReg) {
+        // Promoted - just copy in a zero
+        OpRegCopy(promotion_map_[pmap_index].core_reg, temp_reg);
+      } else {
+        // Lives in the frame, need to store.
+        StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, kWord);
+      }
+      if (zero_reg == INVALID_REG) {
+        FreeTemp(temp_reg);
+      }
+    }
+  }
+}
+
+/* Load a word at base + displacement.  Displacement must be word multiple */
+LIR* Mir2Lir::LoadWordDisp(int rBase, int displacement, int r_dest)
+{
+  return LoadBaseDisp(rBase, displacement, r_dest, kWord,
+                      INVALID_SREG);
+}
+
+LIR* Mir2Lir::StoreWordDisp(int rBase, int displacement, int r_src)
+{
+  return StoreBaseDisp(rBase, displacement, r_src, kWord);
+}
+
+/*
+ * Load a Dalvik register into a physical register.  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+void Mir2Lir::LoadValueDirect(RegLocation rl_src, int r_dest)
+{
+  rl_src = UpdateLoc(rl_src);
+  if (rl_src.location == kLocPhysReg) {
+    OpRegCopy(r_dest, rl_src.low_reg);
+  } else if (IsInexpensiveConstant(rl_src)) {
+    LoadConstantNoClobber(r_dest, mir_graph_->ConstantValue(rl_src));
+  } else {
+    DCHECK((rl_src.location == kLocDalvikFrame) ||
+           (rl_src.location == kLocCompilerTemp));
+    LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest);
+  }
+}
+
+/*
+ * Similar to LoadValueDirect, but clobbers and allocates the target
+ * register.  Should be used when loading to a fixed register (for example,
+ * loading arguments to an out of line call.
+ */
+void Mir2Lir::LoadValueDirectFixed(RegLocation rl_src, int r_dest)
+{
+  Clobber(r_dest);
+  MarkInUse(r_dest);
+  LoadValueDirect(rl_src, r_dest);
+}
+
+/*
+ * Load a Dalvik register pair into a physical register[s].  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+void Mir2Lir::LoadValueDirectWide(RegLocation rl_src, int reg_lo,
+             int reg_hi)
+{
+  rl_src = UpdateLocWide(rl_src);
+  if (rl_src.location == kLocPhysReg) {
+    OpRegCopyWide(reg_lo, reg_hi, rl_src.low_reg, rl_src.high_reg);
+  } else if (IsInexpensiveConstant(rl_src)) {
+    LoadConstantWide(reg_lo, reg_hi, mir_graph_->ConstantValueWide(rl_src));
+  } else {
+    DCHECK((rl_src.location == kLocDalvikFrame) ||
+           (rl_src.location == kLocCompilerTemp));
+    LoadBaseDispWide(TargetReg(kSp), SRegOffset(rl_src.s_reg_low),
+                     reg_lo, reg_hi, INVALID_SREG);
+  }
+}
+
+/*
+ * Similar to LoadValueDirect, but clobbers and allocates the target
+ * registers.  Should be used when loading to a fixed registers (for example,
+ * loading arguments to an out of line call.
+ */
+void Mir2Lir::LoadValueDirectWideFixed(RegLocation rl_src, int reg_lo,
+                                       int reg_hi)
+{
+  Clobber(reg_lo);
+  Clobber(reg_hi);
+  MarkInUse(reg_lo);
+  MarkInUse(reg_hi);
+  LoadValueDirectWide(rl_src, reg_lo, reg_hi);
+}
+
+RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind)
+{
+  rl_src = EvalLoc(rl_src, op_kind, false);
+  if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
+    LoadValueDirect(rl_src, rl_src.low_reg);
+    rl_src.location = kLocPhysReg;
+    MarkLive(rl_src.low_reg, rl_src.s_reg_low);
+  }
+  return rl_src;
+}
+
+void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src)
+{
+  /*
+   * Sanity checking - should never try to store to the same
+   * ssa name during the compilation of a single instruction
+   * without an intervening ClobberSReg().
+   */
+  if (kIsDebugBuild) {
+    DCHECK((live_sreg_ == INVALID_SREG) ||
+           (rl_dest.s_reg_low != live_sreg_));
+    live_sreg_ = rl_dest.s_reg_low;
+  }
+  LIR* def_start;
+  LIR* def_end;
+  DCHECK(!rl_dest.wide);
+  DCHECK(!rl_src.wide);
+  rl_src = UpdateLoc(rl_src);
+  rl_dest = UpdateLoc(rl_dest);
+  if (rl_src.location == kLocPhysReg) {
+    if (IsLive(rl_src.low_reg) ||
+      IsPromoted(rl_src.low_reg) ||
+      (rl_dest.location == kLocPhysReg)) {
+      // Src is live/promoted or Dest has assigned reg.
+      rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+      OpRegCopy(rl_dest.low_reg, rl_src.low_reg);
+    } else {
+      // Just re-assign the registers.  Dest gets Src's regs
+      rl_dest.low_reg = rl_src.low_reg;
+      Clobber(rl_src.low_reg);
+    }
+  } else {
+    // Load Src either into promoted Dest or temps allocated for Dest
+    rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+    LoadValueDirect(rl_src, rl_dest.low_reg);
+  }
+
+  // Dest is now live and dirty (until/if we flush it to home location)
+  MarkLive(rl_dest.low_reg, rl_dest.s_reg_low);
+  MarkDirty(rl_dest);
+
+
+  ResetDefLoc(rl_dest);
+  if (IsDirty(rl_dest.low_reg) &&
+      oat_live_out(rl_dest.s_reg_low)) {
+    def_start = last_lir_insn_;
+    StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low),
+                  rl_dest.low_reg, kWord);
+    MarkClean(rl_dest);
+    def_end = last_lir_insn_;
+    if (!rl_dest.ref) {
+      // Exclude references from store elimination
+      MarkDef(rl_dest, def_start, def_end);
+    }
+  }
+}
+
+RegLocation Mir2Lir::LoadValueWide(RegLocation rl_src, RegisterClass op_kind)
+{
+  DCHECK(rl_src.wide);
+  rl_src = EvalLoc(rl_src, op_kind, false);
+  if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
+    LoadValueDirectWide(rl_src, rl_src.low_reg, rl_src.high_reg);
+    rl_src.location = kLocPhysReg;
+    MarkLive(rl_src.low_reg, rl_src.s_reg_low);
+    MarkLive(rl_src.high_reg, GetSRegHi(rl_src.s_reg_low));
+  }
+  return rl_src;
+}
+
+void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src)
+{
+  /*
+   * Sanity checking - should never try to store to the same
+   * ssa name during the compilation of a single instruction
+   * without an intervening ClobberSReg().
+   */
+  if (kIsDebugBuild) {
+    DCHECK((live_sreg_ == INVALID_SREG) ||
+           (rl_dest.s_reg_low != live_sreg_));
+    live_sreg_ = rl_dest.s_reg_low;
+  }
+  LIR* def_start;
+  LIR* def_end;
+  DCHECK_EQ(IsFpReg(rl_src.low_reg), IsFpReg(rl_src.high_reg));
+  DCHECK(rl_dest.wide);
+  DCHECK(rl_src.wide);
+  if (rl_src.location == kLocPhysReg) {
+    if (IsLive(rl_src.low_reg) ||
+        IsLive(rl_src.high_reg) ||
+        IsPromoted(rl_src.low_reg) ||
+        IsPromoted(rl_src.high_reg) ||
+        (rl_dest.location == kLocPhysReg)) {
+      // Src is live or promoted or Dest has assigned reg.
+      rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+      OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg,
+                    rl_src.low_reg, rl_src.high_reg);
+    } else {
+      // Just re-assign the registers.  Dest gets Src's regs
+      rl_dest.low_reg = rl_src.low_reg;
+      rl_dest.high_reg = rl_src.high_reg;
+      Clobber(rl_src.low_reg);
+      Clobber(rl_src.high_reg);
+    }
+  } else {
+    // Load Src either into promoted Dest or temps allocated for Dest
+    rl_dest = EvalLoc(rl_dest, kAnyReg, false);
+    LoadValueDirectWide(rl_src, rl_dest.low_reg, rl_dest.high_reg);
+  }
+
+  // Dest is now live and dirty (until/if we flush it to home location)
+  MarkLive(rl_dest.low_reg, rl_dest.s_reg_low);
+  MarkLive(rl_dest.high_reg, GetSRegHi(rl_dest.s_reg_low));
+  MarkDirty(rl_dest);
+  MarkPair(rl_dest.low_reg, rl_dest.high_reg);
+
+
+  ResetDefLocWide(rl_dest);
+  if ((IsDirty(rl_dest.low_reg) ||
+      IsDirty(rl_dest.high_reg)) &&
+      (oat_live_out(rl_dest.s_reg_low) ||
+      oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+    def_start = last_lir_insn_;
+    DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
+              mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
+    StoreBaseDispWide(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low),
+                      rl_dest.low_reg, rl_dest.high_reg);
+    MarkClean(rl_dest);
+    def_end = last_lir_insn_;
+    MarkDefWide(rl_dest, def_start, def_end);
+  }
+}
+
+/* Utilities to load the current Method* */
+void Mir2Lir::LoadCurrMethodDirect(int r_tgt)
+{
+  LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt);
+}
+
+RegLocation Mir2Lir::LoadCurrMethod()
+{
+  return LoadValue(mir_graph_->GetMethodLoc(), kCoreReg);
+}
+
+}  // namespace art