AArch64: fix and enable sparse- and packed-switch.
Changed implementation of sparse- and packed-switch to use w and x
registers appropriately. Also added a couple of utilities to obtain a
w/s register corresponding to a given x/d register and viceversa.
Change-Id: I485a110f6e91b09227d9e2a0b8b14224a10bca90
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 547c0f6..a366a20 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -157,6 +157,8 @@
Instruction::GOTO,
Instruction::GOTO_16,
Instruction::GOTO_32,
+ Instruction::PACKED_SWITCH,
+ Instruction::SPARSE_SWITCH,
Instruction::IF_EQ,
Instruction::IF_NE,
Instruction::IF_LT,
@@ -248,8 +250,6 @@
Instruction::MOVE_OBJECT,
Instruction::MOVE_OBJECT_FROM16,
Instruction::MOVE_OBJECT_16,
- // Instruction::PACKED_SWITCH,
- // Instruction::SPARSE_SWITCH,
// Instruction::MOVE_RESULT,
// Instruction::MOVE_RESULT_WIDE,
// Instruction::MOVE_RESULT_OBJECT,
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index b80938a..b85f569 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -68,7 +68,7 @@
// Get the switch value
rl_src = LoadValue(rl_src, kCoreReg);
- RegStorage r_base = AllocTemp();
+ RegStorage r_base = AllocTempWide();
// Allocate key and disp temps.
RegStorage r_key = AllocTemp();
RegStorage r_disp = AllocTemp();
@@ -95,7 +95,8 @@
tab_rec->anchor = switch_label;
// Add displacement to base branch address and go!
- OpRegRegRegShift(kOpAdd, r_base, r_base, r_disp, ENCODE_NO_SHIFT);
+ // TODO(Arm64): generate "add x1, x1, w3, sxtw" rather than "add x1, x1, x3"?
+ OpRegRegRegShift(kOpAdd, r_base, r_base, As64BitReg(r_disp), ENCODE_NO_SHIFT);
NewLIR1(kA64Br1x, r_base.GetReg());
// Loop exit label.
@@ -105,7 +106,7 @@
void Arm64Mir2Lir::GenPackedSwitch(MIR* mir, uint32_t table_offset,
- RegLocation rl_src) {
+ RegLocation rl_src) {
const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
if (cu_->verbose) {
DumpPackedSwitchTable(table);
@@ -122,7 +123,7 @@
// Get the switch value
rl_src = LoadValue(rl_src, kCoreReg);
- RegStorage table_base = AllocTemp();
+ RegStorage table_base = AllocTempWide();
// Materialize a pointer to the switch table
NewLIR3(kA64Adr2xd, table_base.GetReg(), 0, WrapPointer(tab_rec));
int low_key = s4FromSwitchData(&table[2]);
@@ -140,15 +141,17 @@
// Load the displacement from the switch table
RegStorage disp_reg = AllocTemp();
- LoadBaseIndexed(table_base, key_reg, disp_reg, 2, k32);
+ // TODO(Arm64): generate "ldr w3, [x1,w2,sxtw #2]" rather than "ldr w3, [x1,x2,lsl #2]"?
+ LoadBaseIndexed(table_base, key_reg, As64BitReg(disp_reg), 2, k32);
// Get base branch address.
- RegStorage branch_reg = AllocTemp();
+ RegStorage branch_reg = AllocTempWide();
LIR* switch_label = NewLIR3(kA64Adr2xd, branch_reg.GetReg(), 0, -1);
tab_rec->anchor = switch_label;
// Add displacement to base branch address and go!
- OpRegRegRegShift(kOpAdd, branch_reg, branch_reg, disp_reg, ENCODE_NO_SHIFT);
+ // TODO(Arm64): generate "add x4, x4, w3, sxtw" rather than "add x4, x4, x3"?
+ OpRegRegRegShift(kOpAdd, branch_reg, branch_reg, As64BitReg(disp_reg), ENCODE_NO_SHIFT);
NewLIR1(kA64Br1x, branch_reg.GetReg());
// branch_over target here
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 6251f4f..21db771 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -223,6 +223,40 @@
bool skip_this);
private:
+ /**
+ * @brief Given register xNN (dNN), returns register wNN (sNN).
+ * @param reg #RegStorage containing a Solo64 input register (e.g. @c x1 or @c d2).
+ * @return A Solo32 with the same register number as the @p reg (e.g. @c w1 or @c s2).
+ * @see As64BitReg
+ */
+ RegStorage As32BitReg(RegStorage reg) {
+ DCHECK(reg.Is64Bit());
+ DCHECK(!reg.IsPair());
+ RegStorage ret_val = RegStorage(RegStorage::k32BitSolo,
+ reg.GetRawBits() & RegStorage::kRegTypeMask);
+ DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k32SoloStorageMask)
+ ->GetReg().GetReg(),
+ ret_val.GetReg());
+ return ret_val;
+ }
+
+ /**
+ * @brief Given register wNN (sNN), returns register xNN (dNN).
+ * @param reg #RegStorage containing a Solo32 input register (e.g. @c w1 or @c s2).
+ * @return A Solo64 with the same register number as the @p reg (e.g. @c x1 or @c d2).
+ * @see As32BitReg
+ */
+ RegStorage As64BitReg(RegStorage reg) {
+ DCHECK(reg.Is32Bit());
+ DCHECK(!reg.IsPair());
+ RegStorage ret_val = RegStorage(RegStorage::k64BitSolo,
+ reg.GetRawBits() & RegStorage::kRegTypeMask);
+ DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k64SoloStorageMask)
+ ->GetReg().GetReg(),
+ ret_val.GetReg());
+ return ret_val;
+ }
+
LIR* LoadFPConstantValue(int r_dest, int32_t value);
LIR* LoadFPConstantValueWide(int r_dest, int64_t value);
void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);