summaryrefslogtreecommitdiffstats
path: root/compiler/dex/quick/gen_loadstore.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/quick/gen_loadstore.cc')
-rw-r--r--compiler/dex/quick/gen_loadstore.cc312
1 files changed, 312 insertions, 0 deletions
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
new file mode 100644
index 0000000000..6a25c1db45
--- /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