summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/quick/arm/call_arm.cc198
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h8
2 files changed, 127 insertions, 79 deletions
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index d4d33e4a6e..22466f08cf 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -24,43 +24,72 @@
namespace art {
-// TODO: generalize & move to RegUtil.cc
-// The number of dalvik registers passed in core registers.
-constexpr int kInArgsInCoreRegs = 3;
-// The core register corresponding to the first (index 0) input argument.
-constexpr int kInArg0CoreReg = r1; // r0 is Method*.
-// Offset, in words, for getting args from stack (even core reg args have space on stack).
-constexpr int kInArgToStackOffset = 1;
-
-/* Lock argument if it's in register. */
-void ArmMir2Lir::LockArg(int in_position, bool wide) {
- if (in_position < kInArgsInCoreRegs) {
- LockTemp(kInArg0CoreReg + in_position);
- }
- if (wide && in_position + 1 < kInArgsInCoreRegs) {
- LockTemp(kInArg0CoreReg + in_position + 1);
+
+/* Return the position of an ssa name within the argument list */
+int ArmMir2Lir::InPosition(int s_reg) {
+ int v_reg = mir_graph_->SRegToVReg(s_reg);
+ return v_reg - cu_->num_regs;
+}
+
+/*
+ * Describe an argument. If it's already in an arg register, just leave it
+ * there. NOTE: all live arg registers must be locked prior to this call
+ * to avoid having them allocated as a temp by downstream utilities.
+ */
+RegLocation ArmMir2Lir::ArgLoc(RegLocation loc) {
+ int arg_num = InPosition(loc.s_reg_low);
+ if (loc.wide) {
+ if (arg_num == 2) {
+ // Bad case - half in register, half in frame. Just punt
+ loc.location = kLocInvalid;
+ } else if (arg_num < 2) {
+ loc.low_reg = rARM_ARG1 + arg_num;
+ loc.high_reg = loc.low_reg + 1;
+ loc.location = kLocPhysReg;
+ } else {
+ loc.location = kLocDalvikFrame;
+ }
+ } else {
+ if (arg_num < 3) {
+ loc.low_reg = rARM_ARG1 + arg_num;
+ loc.location = kLocPhysReg;
+ } else {
+ loc.location = kLocDalvikFrame;
+ }
}
+ return loc;
}
-/* Load argument into register. LockArg(in_position, wide) must have been previously called. */
-int ArmMir2Lir::LoadArg(int in_position, bool wide) {
- if (in_position < kInArgsInCoreRegs) {
- int low_reg = kInArg0CoreReg + in_position;
- if (!wide) {
- return low_reg;
+/*
+ * Load an argument. If already in a register, just return. If in
+ * the frame, we can't use the normal LoadValue() because it assumed
+ * a proper frame - and we're frameless.
+ */
+RegLocation ArmMir2Lir::LoadArg(RegLocation loc) {
+ if (loc.location == kLocDalvikFrame) {
+ int start = (InPosition(loc.s_reg_low) + 1) * sizeof(uint32_t);
+ loc.low_reg = AllocTemp();
+ LoadWordDisp(rARM_SP, start, loc.low_reg);
+ if (loc.wide) {
+ loc.high_reg = AllocTemp();
+ LoadWordDisp(rARM_SP, start + sizeof(uint32_t), loc.high_reg);
}
- int high_reg = (in_position != kInArgsInCoreRegs - 1) ? low_reg + 1 : LoadArg(in_position + 1);
- return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
+ loc.location = kLocPhysReg;
}
- int low_reg = AllocTemp();
- int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
- if (!wide) {
- LoadWordDisp(rARM_SP, offset, low_reg);
- return low_reg;
+ return loc;
+}
+
+/* Lock any referenced arguments that arrive in registers */
+void ArmMir2Lir::LockLiveArgs(MIR* mir) {
+ int first_in = cu_->num_regs;
+ const int num_arg_regs = 3; // TODO: generalize & move to RegUtil.cc
+ for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+ int v_reg = mir_graph_->SRegToVReg(mir->ssa_rep->uses[i]);
+ int InPosition = v_reg - first_in;
+ if (InPosition < num_arg_regs) {
+ LockTemp(rARM_ARG1 + InPosition);
+ }
}
- int high_reg = AllocTemp();
- LoadBaseDispWide(rARM_SP, offset, low_reg, high_reg, INVALID_SREG);
- return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
}
/* Find the next MIR, which may be in a following basic block */
@@ -101,80 +130,96 @@ void ArmMir2Lir::GenPrintLabel(MIR* mir) {
MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
// FastInstance() already checked by DexFileMethodInliner.
const InlineIGetIPutData& data = special.d.ifield_data;
- if (data.method_is_static || data.object_arg != 0) {
+ if (!data.method_is_static || data.object_arg != 0) {
return NULL; // The object is not "this" and has to be null-checked.
}
+ OpSize size = static_cast<OpSize>(data.op_size);
DCHECK_NE(data.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
bool long_or_double = (data.op_size == kLong);
+ bool is_object = data.is_object;
- // Point of no return - no aborts after this
- ArmMir2Lir::GenPrintLabel(mir);
- LockArg(data.object_arg);
- RegLocation rl_dest = long_or_double ? GetReturnWide(false) : GetReturn(false);
- int reg_obj = LoadArg(data.object_arg);
+ // TODO: Generate the method using only the data in special.
+ RegLocation rl_obj = mir_graph_->GetSrc(mir, 0);
+ LockLiveArgs(mir);
+ rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
+ RegLocation rl_dest;
if (long_or_double) {
- LoadBaseDispWide(reg_obj, data.field_offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
+ rl_dest = GetReturnWide(false);
} else {
- LoadBaseDisp(reg_obj, data.field_offset, rl_dest.low_reg, kWord, INVALID_SREG);
- }
- if (data.is_volatile) {
- GenMemBarrier(kLoadLoad);
+ rl_dest = GetReturn(false);
}
+ // Point of no return - no aborts after this
+ ArmMir2Lir::GenPrintLabel(mir);
+ rl_obj = LoadArg(rl_obj);
+ uint32_t field_idx = mir->dalvikInsn.vC;
+ GenIGet(field_idx, mir->optimization_flags, size, rl_dest, rl_obj, long_or_double, is_object);
return GetNextMir(bb, mir);
}
MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
// FastInstance() already checked by DexFileMethodInliner.
const InlineIGetIPutData& data = special.d.ifield_data;
- if (data.method_is_static || data.object_arg != 0) {
+ if (!data.method_is_static || data.object_arg != 0) {
return NULL; // The object is not "this" and has to be null-checked.
}
+ OpSize size = static_cast<OpSize>(data.op_size);
DCHECK_NE(data.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
bool long_or_double = (data.op_size == kLong);
+ bool is_object = data.is_object;
- // Point of no return - no aborts after this
- ArmMir2Lir::GenPrintLabel(mir);
- LockArg(data.object_arg);
- LockArg(data.src_arg, long_or_double);
- int reg_obj = LoadArg(data.object_arg);
- int reg_src = LoadArg(data.src_arg, long_or_double);
- if (data.is_volatile) {
- GenMemBarrier(kStoreStore);
- }
+ // TODO: Generate the method using only the data in special.
+ RegLocation rl_src;
+ RegLocation rl_obj;
+ LockLiveArgs(mir);
if (long_or_double) {
- StoreBaseDispWide(reg_obj, data.field_offset, reg_src & 0xff, reg_src >> 8);
+ rl_src = mir_graph_->GetSrcWide(mir, 0);
+ rl_obj = mir_graph_->GetSrc(mir, 2);
} else {
- StoreBaseDisp(reg_obj, data.field_offset, reg_src, kWord);
+ rl_src = mir_graph_->GetSrc(mir, 0);
+ rl_obj = mir_graph_->GetSrc(mir, 1);
}
- if (data.is_volatile) {
- GenMemBarrier(kLoadLoad);
- }
- if (data.is_object) {
- MarkGCCard(reg_src, reg_obj);
+ rl_src = ArmMir2Lir::ArgLoc(rl_src);
+ rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
+ // Reject if source is split across registers & frame
+ if (rl_src.location == kLocInvalid) {
+ ResetRegPool();
+ return NULL;
}
+ // Point of no return - no aborts after this
+ ArmMir2Lir::GenPrintLabel(mir);
+ rl_obj = LoadArg(rl_obj);
+ rl_src = LoadArg(rl_src);
+ uint32_t field_idx = mir->dalvikInsn.vC;
+ GenIPut(field_idx, mir->optimization_flags, size, rl_src, rl_obj, long_or_double, is_object);
return GetNextMir(bb, mir);
}
-MIR* ArmMir2Lir::SpecialIdentity(MIR* mir, const InlineMethod& special) {
- const InlineReturnArgData& data = special.d.return_data;
- DCHECK_NE(data.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
- bool long_or_double = (data.op_size == kLong);
-
+MIR* ArmMir2Lir::SpecialIdentity(MIR* mir) {
+ RegLocation rl_src;
+ RegLocation rl_dest;
+ bool wide = (mir->ssa_rep->num_uses == 2);
+ if (wide) {
+ rl_src = mir_graph_->GetSrcWide(mir, 0);
+ rl_dest = GetReturnWide(false);
+ } else {
+ rl_src = mir_graph_->GetSrc(mir, 0);
+ rl_dest = GetReturn(false);
+ }
+ LockLiveArgs(mir);
+ rl_src = ArmMir2Lir::ArgLoc(rl_src);
+ if (rl_src.location == kLocInvalid) {
+ ResetRegPool();
+ return NULL;
+ }
// Point of no return - no aborts after this
ArmMir2Lir::GenPrintLabel(mir);
- LockArg(data.arg);
- if (long_or_double) {
- LockArg(data.arg + 1);
- }
- RegLocation rl_dest = long_or_double ? GetReturnWide(false) : GetReturn(false);
- int reg_src = LoadArg(data.arg, rl_dest.low_reg);
- OpRegCopy(rl_dest.low_reg, reg_src);
- if (long_or_double) {
- int reg_src_high = LoadArg(data.arg + 1, rl_dest.high_reg);
- CHECK_NE(rl_dest.low_reg, reg_src_high); // The high register hasn't been clobbered.
- OpRegCopy(rl_dest.high_reg, reg_src_high);
+ rl_src = LoadArg(rl_src);
+ if (wide) {
+ StoreValueWide(rl_dest, rl_src);
+ } else {
+ StoreValue(rl_dest, rl_src);
}
return mir;
}
@@ -204,7 +249,8 @@ void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
next_mir = SpecialIPut(&bb, mir, special);
break;
case kInlineOpReturnArg:
- next_mir = SpecialIdentity(mir, special);
+ // TODO: Generate the method using only the data in special.
+ next_mir = SpecialIdentity(mir);
break;
default:
return;
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 0047b37418..598da89372 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -167,6 +167,7 @@ class ArmMir2Lir : public Mir2Lir {
void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
void OpTlsCmp(ThreadOffset offset, int val);
+ RegLocation ArgLoc(RegLocation loc);
LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
int s_reg);
LIR* StoreBaseDispBody(int rBase, int displacement, int r_src, int r_src_hi, OpSize size);
@@ -185,12 +186,13 @@ class ArmMir2Lir : public Mir2Lir {
private:
void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, int64_t val,
ConditionCode ccode);
- void LockArg(int in_position, bool wide = false);
- int LoadArg(int in_position, bool wide = false);
+ int InPosition(int s_reg);
+ RegLocation LoadArg(RegLocation loc);
+ void LockLiveArgs(MIR* mir);
MIR* GetNextMir(BasicBlock** p_bb, MIR* mir);
MIR* SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special);
MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
- MIR* SpecialIdentity(MIR* mir, const InlineMethod& special);
+ MIR* SpecialIdentity(MIR* mir);
LIR* LoadFPConstantValue(int r_dest, int value);
void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);