ARM: Don't generate memory instructions with writeback where the data and address registers are the same.
BUG=http://dartbug.com/24855
R=fschneider@google.com
Review URL: https://codereview.chromium.org/1434323003 .
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 815b796..12fb7ff 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -104,6 +104,8 @@
Address ad) {
ASSERT(rd != kNoRegister);
ASSERT(cond != kNoCondition);
+ ASSERT(!ad.has_writeback() || (ad.rn() != rd)); // Unpredictable.
+
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
B26 | (ad.kind() == Address::Immediate ? 0 : B25) |
(load ? L : 0) |
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 9ba279c..78fb22d 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -321,6 +321,11 @@
Mode mode() const { return static_cast<Mode>(encoding() & kModeMask); }
+ bool has_writeback() const {
+ return (mode() == PreIndex) || (mode() == PostIndex) ||
+ (mode() == NegPreIndex) || (mode() == NegPostIndex);
+ }
+
uint32_t encoding() const { return encoding_; }
// Encoding for addressing mode 3.
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 5419aaa..531ed4a 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1996,6 +1996,7 @@
HandleIllegalAccess(addr, instr);
} else {
if (write_back) {
+ ASSERT(rd != rn); // Unpredictable.
set_register(rn, rn_val);
}
if (!instr->HasSign()) {
@@ -2312,6 +2313,7 @@
HandleIllegalAccess(addr, instr);
} else {
if (write_back) {
+ ASSERT(rd != rn); // Unpredictable.
set_register(rn, rn_val);
}
if (instr->HasB()) {
@@ -2424,6 +2426,7 @@
HandleIllegalAccess(addr, instr);
} else {
if (write_back) {
+ ASSERT(rd != rn); // Unpredictable.
set_register(rn, rn_val);
}
if (instr->HasB()) {
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 5acd669..1629107 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -419,6 +419,9 @@
__ eor(IP, IP, Operand(LR));
// Set up the frame manually with return address now stored in IP.
+ COMPILE_ASSERT(PP < CODE_REG);
+ COMPILE_ASSERT(CODE_REG < FP);
+ COMPILE_ASSERT(FP < IP);
__ EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << IP), 0);
__ LoadPoolPointer();
@@ -434,9 +437,12 @@
if (i == CODE_REG) {
// Save the original value of CODE_REG pushed before invoking this stub
// instead of the value used to call this stub.
- COMPILE_ASSERT(IP > CODE_REG); // Assert IP is pushed first.
__ ldr(IP, Address(FP, kCallerSpSlotFromFp * kWordSize));
__ Push(IP);
+ } else if (i == SP) {
+ // Push(SP) has unpredictable behavior.
+ __ mov(IP, Operand(SP));
+ __ Push(IP);
} else {
__ Push(static_cast<Register>(i));
}