MIPS: Shorten .bss string/class loads
This is a follow-up to
https://android-review.googlesource.com/#/c/384033/.
Test: booted MIPS64 (with 2nd arch MIPS32R6) in QEMU
Test: testrunner.py --target --optimizing
Test: same tests as above on CI20
Test: booted MIPS32R2 and MIPS64 in QEMU in configurations:
ART_USE_READ_BARRIER=false,
ART_READ_BARRIER_TYPE=TABLELOOKUP
Change-Id: I4cb2f4ded13c0d9fc960c7eac55396f7931c1e38
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index d99d237..3bec30f 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -49,43 +49,27 @@
uint32_t target_offset) {
uint32_t anchor_literal_offset = patch.PcInsnOffset();
uint32_t literal_offset = patch.LiteralOffset();
- uint32_t literal_low_offset;
+ bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
- // Perform basic sanity checks and initialize `literal_low_offset` to point
- // to the instruction containing the 16 least significant bits of the
- // relative address.
- if (is_r6) {
- DCHECK_GE(code->size(), 8u);
- DCHECK_LE(literal_offset, code->size() - 8u);
- DCHECK_EQ(literal_offset, anchor_literal_offset);
- // AUIPC reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
- DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
- // instr reg(s), offset_low
- DCHECK_EQ((*code)[literal_offset + 4], 0x78);
- DCHECK_EQ((*code)[literal_offset + 5], 0x56);
- literal_low_offset = literal_offset + 4;
+ // Perform basic sanity checks.
+ if (high_patch) {
+ if (is_r6) {
+ // auipc reg, offset_high
+ DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
+ DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
+ } else {
+ // lui reg, offset_high
+ DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
+ DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
+ // addu reg, reg, reg2
+ DCHECK_EQ((*code)[literal_offset + 4], 0x21);
+ DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
+ DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
+ }
} else {
- DCHECK_GE(code->size(), 16u);
- DCHECK_LE(literal_offset, code->size() - 12u);
- DCHECK_GE(literal_offset, 4u);
- // The NAL instruction does not precede immediately as the PC+0
- // comes from HMipsComputeBaseMethodAddress.
- // LUI reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
- DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
- // ADDU reg, reg, reg2
- DCHECK_EQ((*code)[literal_offset + 4], 0x21);
- DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
- DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
// instr reg(s), offset_low
- DCHECK_EQ((*code)[literal_offset + 8], 0x78);
- DCHECK_EQ((*code)[literal_offset + 9], 0x56);
- literal_low_offset = literal_offset + 8;
+ CHECK_EQ((*code)[literal_offset + 0], 0x78);
+ CHECK_EQ((*code)[literal_offset + 1], 0x56);
}
// Apply patch.
@@ -93,12 +77,15 @@
uint32_t diff = target_offset - anchor_offset;
diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low".
- // LUI reg, offset_high / AUIPC reg, offset_high
- (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
- (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
- // instr reg(s), offset_low
- (*code)[literal_low_offset + 0] = static_cast<uint8_t>(diff >> 0);
- (*code)[literal_low_offset + 1] = static_cast<uint8_t>(diff >> 8);
+ if (high_patch) {
+ // lui reg, offset_high / auipc reg, offset_high
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
+ } else {
+ // instr reg(s), offset_low
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
+ }
}
void MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
diff --git a/compiler/linker/mips/relative_patcher_mips32r6_test.cc b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
index 63ad8a5..d1a75e2 100644
--- a/compiler/linker/mips/relative_patcher_mips32r6_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
@@ -26,7 +26,9 @@
protected:
static const uint8_t kUnpatchedPcRelativeRawCode[];
- static const uint32_t kLiteralOffset;
+ static const uint32_t kLiteralOffsetHigh;
+ static const uint32_t kLiteralOffsetLow1;
+ static const uint32_t kLiteralOffsetLow2;
static const uint32_t kAnchorOffset;
static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
@@ -44,9 +46,11 @@
const uint8_t Mips32r6RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
0x34, 0x12, 0x5E, 0xEE, // auipc s2, high(diff); placeholder = 0x1234
0x78, 0x56, 0x52, 0x26, // addiu s2, s2, low(diff); placeholder = 0x5678
+ 0x78, 0x56, 0x52, 0x8E, // lw s2, (low(diff))(s2) ; placeholder = 0x5678
};
-const uint32_t Mips32r6RelativePatcherTest::kLiteralOffset = 0; // At auipc (where
- // patching starts).
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetHigh = 0; // At auipc.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow1 = 4; // At addiu.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow2 = 8; // At lw.
const uint32_t Mips32r6RelativePatcherTest::kAnchorOffset = 0; // At auipc (where PC+0 points).
const ArrayRef<const uint8_t> Mips32r6RelativePatcherTest::kUnpatchedPcRelativeCode(
kUnpatchedPcRelativeRawCode);
@@ -60,11 +64,12 @@
ASSERT_TRUE(result.first);
uint32_t diff = target_offset - (result.second + kAnchorOffset);
- diff += (diff & 0x8000) << 1; // Account for sign extension in addiu.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in addiu/lw.
const uint8_t expected_code[] = {
static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x5E, 0xEE,
static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+ static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
};
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
@@ -75,7 +80,9 @@
string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
bss_begin_ = bss_begin;
LinkerPatch patches[] = {
- LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
}
@@ -84,7 +91,9 @@
constexpr uint32_t kStringIndex = 1u;
string_index_to_offset_map_.Put(kStringIndex, string_offset);
LinkerPatch patches[] = {
- LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
}
diff --git a/compiler/linker/mips/relative_patcher_mips_test.cc b/compiler/linker/mips/relative_patcher_mips_test.cc
index 49af7c6..2f7a075 100644
--- a/compiler/linker/mips/relative_patcher_mips_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips_test.cc
@@ -26,7 +26,9 @@
protected:
static const uint8_t kUnpatchedPcRelativeRawCode[];
- static const uint32_t kLiteralOffset;
+ static const uint32_t kLiteralOffsetHigh;
+ static const uint32_t kLiteralOffsetLow1;
+ static const uint32_t kLiteralOffsetLow2;
static const uint32_t kAnchorOffset;
static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
@@ -46,8 +48,11 @@
0x34, 0x12, 0x12, 0x3C, // lui s2, high(diff); placeholder = 0x1234
0x21, 0x90, 0x5F, 0x02, // addu s2, s2, ra
0x78, 0x56, 0x52, 0x26, // addiu s2, s2, low(diff); placeholder = 0x5678
+ 0x78, 0x56, 0x52, 0x8E, // lw s2, (low(diff))(s2) ; placeholder = 0x5678
};
-const uint32_t MipsRelativePatcherTest::kLiteralOffset = 4; // At lui (where patching starts).
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetHigh = 4; // At lui.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow1 = 12; // At addiu.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow2 = 16; // At lw.
const uint32_t MipsRelativePatcherTest::kAnchorOffset = 8; // At addu (where PC+0 points).
const ArrayRef<const uint8_t> MipsRelativePatcherTest::kUnpatchedPcRelativeCode(
kUnpatchedPcRelativeRawCode);
@@ -61,13 +66,14 @@
ASSERT_TRUE(result.first);
uint32_t diff = target_offset - (result.second + kAnchorOffset);
- diff += (diff & 0x8000) << 1; // Account for sign extension in addiu.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in addiu/lw.
const uint8_t expected_code[] = {
0x00, 0x00, 0x10, 0x04,
static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x12, 0x3C,
0x21, 0x90, 0x5F, 0x02,
static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+ static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
};
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
@@ -78,7 +84,9 @@
string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
bss_begin_ = bss_begin;
LinkerPatch patches[] = {
- LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
}
@@ -87,7 +95,9 @@
constexpr uint32_t kStringIndex = 1u;
string_index_to_offset_map_.Put(kStringIndex, string_offset);
LinkerPatch patches[] = {
- LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
}