ARM: Add vldm/vstm assembler support.
Change-Id: Id97417de8ebd07fc1fbee5d17e4b1c620a2c44cc
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index ff0bbaf..86548e1 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -680,6 +680,8 @@
virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0;
virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0;
virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0;
+ virtual void vldmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) = 0;
+ virtual void vstmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) = 0;
// Branch instructions.
virtual void b(Label* label, Condition cond = AL) = 0;
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 6f9d5f3..b8eb60c 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -1106,6 +1106,18 @@
}
+void Arm32Assembler::vldmiad(Register, DRegister, int, Condition) {
+ LOG(FATAL) << "Unimplemented.";
+ UNREACHABLE();
+}
+
+
+void Arm32Assembler::vstmiad(Register, DRegister, int, Condition) {
+ LOG(FATAL) << "Unimplemented.";
+ UNREACHABLE();
+}
+
+
void Arm32Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
CHECK_NE(cond, kNoCondition);
CHECK_GT(nregs, 0);
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 044eaa1..0cb6b17 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -212,6 +212,8 @@
void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
+ void vldmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
+ void vstmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
// Branch instructions.
void b(Label* label, Condition cond = AL) OVERRIDE;
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index ee69698..ebdfc98 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -3020,9 +3020,49 @@
}
+void Thumb2Assembler::vldmiad(Register base_reg, DRegister reg, int nregs, Condition cond) {
+ int32_t rest = B23;
+ EmitVLdmOrStm(rest,
+ static_cast<uint32_t>(reg),
+ nregs,
+ base_reg,
+ /*is_load*/ true,
+ /*dbl*/ true,
+ cond);
+}
+
+
+void Thumb2Assembler::vstmiad(Register base_reg, DRegister reg, int nregs, Condition cond) {
+ int32_t rest = B23;
+ EmitVLdmOrStm(rest,
+ static_cast<uint32_t>(reg),
+ nregs,
+ base_reg,
+ /*is_load*/ false,
+ /*dbl*/ true,
+ cond);
+}
+
+
void Thumb2Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
+ int32_t rest = B21 | (push ? B24 : B23);
+ EmitVLdmOrStm(rest, reg, nregs, SP, /*is_load*/ !push, dbl, cond);
+}
+
+
+void Thumb2Assembler::EmitVLdmOrStm(int32_t rest,
+ uint32_t reg,
+ int nregs,
+ Register rn,
+ bool is_load,
+ bool dbl,
+ Condition cond) {
CheckCondition(cond);
+ DCHECK_GT(nregs, 0);
+ DCHECK_LE(reg + nregs, 32u);
+ DCHECK(!dbl || (nregs <= 16));
+
uint32_t D;
uint32_t Vd;
if (dbl) {
@@ -3034,14 +3074,17 @@
D = reg & 1;
Vd = (reg >> 1) & 15U /* 0b1111 */;
}
- int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
- B11 | B9 |
- (dbl ? B8 : 0) |
- (push ? B24 : (B23 | B20)) |
- 14U /* 0b1110 */ << 28 |
- nregs << (dbl ? 1 : 0) |
- D << 22 |
- Vd << 12;
+
+ int32_t encoding = rest |
+ 14U /* 0b1110 */ << 28 |
+ B27 | B26 | B11 | B9 |
+ (is_load ? B20 : 0) |
+ static_cast<int16_t>(rn) << 16 |
+ D << 22 |
+ Vd << 12 |
+ (dbl ? B8 : 0) |
+ nregs << (dbl ? 1 : 0);
+
Emit32(encoding);
}
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 1c1c98b..13f3bec 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -258,6 +258,8 @@
void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
+ void vldmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
+ void vstmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
// Branch instructions.
void b(Label* label, Condition cond = AL);
@@ -748,6 +750,14 @@
SRegister sn,
SRegister sm);
+ void EmitVLdmOrStm(int32_t rest,
+ uint32_t reg,
+ int nregs,
+ Register rn,
+ bool is_load,
+ bool dbl,
+ Condition cond);
+
void EmitVFPddd(Condition cond,
int32_t opcode,
DRegister dd,
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 3ca3714..d0799d6 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -1611,4 +1611,46 @@
DriverStr(expected, "LoadFromShiftedRegOffset");
}
+TEST_F(AssemblerThumb2Test, VStmLdmPushPop) {
+ // Different D register numbers are used here, to test register encoding.
+ // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd,
+ // For source and destination registers which use D0..D15, the M bit and D bit should be 0.
+ // For source and destination registers which use D16..D32, the M bit and D bit should be 1.
+ // Different data types (signed and unsigned) are also tested.
+ __ vstmiad(arm::R0, arm::D0, 4);
+ __ vldmiad(arm::R1, arm::D9, 5);
+ __ vpopd(arm::D0, 4);
+ __ vpushd(arm::D9, 5);
+ __ vpops(arm::S0, 4);
+ __ vpushs(arm::S9, 5);
+ __ vpushs(arm::S16, 5);
+ __ vpushd(arm::D0, 16);
+ __ vpushd(arm::D1, 15);
+ __ vpushd(arm::D8, 16);
+ __ vpushd(arm::D31, 1);
+ __ vpushs(arm::S0, 32);
+ __ vpushs(arm::S1, 31);
+ __ vpushs(arm::S16, 16);
+ __ vpushs(arm::S31, 1);
+
+ std::string expected =
+ "vstmia r0, {d0 - d3}\n"
+ "vldmia r1, {d9 - d13}\n"
+ "vpop {d0 - d3}\n"
+ "vpush {d9 - d13}\n"
+ "vpop {s0 - s3}\n"
+ "vpush {s9 - s13}\n"
+ "vpush {s16 - s20}\n"
+ "vpush {d0 - d15}\n"
+ "vpush {d1 - d15}\n"
+ "vpush {d8 - d23}\n"
+ "vpush {d31}\n"
+ "vpush {s0 - s31}\n"
+ "vpush {s1 - s31}\n"
+ "vpush {s16 - s31}\n"
+ "vpush {s31}\n";
+
+ DriverStr(expected, "VStmLdmPushPop");
+}
+
} // namespace art