summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/quick/mips/utility_mips.cc55
-rw-r--r--compiler/driver/compiler_driver.cc6
-rw-r--r--compiler/dwarf/debug_abbrev_writer.h98
-rw-r--r--compiler/dwarf/debug_info_entry_writer.h116
-rw-r--r--compiler/dwarf/dedup_vector.h67
-rw-r--r--compiler/dwarf/dwarf_test.cc3
-rw-r--r--compiler/dwarf/register.h2
-rw-r--r--compiler/elf_writer_debug.cc180
-rw-r--r--compiler/image_writer.cc4
-rw-r--r--compiler/optimizing/bounds_check_elimination.cc41
-rw-r--r--compiler/optimizing/code_generator_arm64.cc55
-rw-r--r--compiler/optimizing/code_generator_mips.cc27
-rw-r--r--compiler/optimizing/code_generator_mips64.cc56
-rw-r--r--compiler/optimizing/code_generator_mips64.h8
-rw-r--r--compiler/optimizing/code_generator_x86.cc8
-rw-r--r--compiler/optimizing/induction_var_range.cc9
-rw-r--r--compiler/optimizing/induction_var_range.h32
-rw-r--r--compiler/optimizing/inliner.cc4
-rw-r--r--compiler/optimizing/instruction_simplifier.cc77
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc268
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc14
-rw-r--r--compiler/optimizing/load_store_elimination.cc4
-rw-r--r--compiler/optimizing/optimizing_cfi_test_expected.inc19
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.cc62
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc124
-rw-r--r--compiler/utils/mips64/assembler_mips64.h22
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc696
27 files changed, 1538 insertions, 519 deletions
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 372fe2b599..4d6c058bdf 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -28,6 +28,8 @@
namespace art {
+static constexpr size_t kMips64DoublewordSize = 8;
+
/* This file contains codegen for the Mips ISA */
LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
int opcode;
@@ -760,7 +762,25 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora
if (cu_->target64) {
if (short_form) {
- load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
+ if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMips64Ld) {
+ RegStorage r_tmp = AllocTemp();
+ load = res = NewLIR3(kMips64Lwu, r_dest.GetReg(), displacement + LOWORD_OFFSET,
+ r_base.GetReg());
+ load2 = NewLIR3(kMips64Lwu, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+ NewLIR3(kMips64Dsll32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0);
+ NewLIR3(kMipsOr, r_dest.GetReg(), r_dest.GetReg(), r_tmp.GetReg());
+ FreeTemp(r_tmp);
+ } else if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMipsFldc1) {
+ RegStorage r_tmp = AllocTemp();
+ r_dest = Fp64ToSolo32(r_dest);
+ load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
+ r_base.GetReg());
+ load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+ NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
+ FreeTemp(r_tmp);
+ } else {
+ load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
+ }
} else {
RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
@@ -771,7 +791,12 @@ LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStora
if (mem_ref_type_ == ResourceMask::kDalvikReg) {
DCHECK_EQ(r_base, TargetPtrReg(kSp));
- AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
+ AnnotateDalvikRegAccess(load, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, r_dest.Is64Bit() /* is64bit */);
+ if (load2 != nullptr) {
+ AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
+ true /* is_load */, r_dest.Is64Bit() /* is64bit */);
+ }
}
return res;
}
@@ -932,7 +957,24 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStor
if (cu_->target64) {
if (short_form) {
- store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
+ if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMips64Sd) {
+ RegStorage r_tmp = AllocTemp();
+ res = NewLIR2(kMipsMove, r_tmp.GetReg(), r_src.GetReg());
+ store = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
+ NewLIR3(kMips64Dsrl32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0);
+ store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+ FreeTemp(r_tmp);
+ } else if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMipsFsdc1) {
+ RegStorage r_tmp = AllocTemp();
+ r_src = Fp64ToSolo32(r_src);
+ store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
+ r_base.GetReg());
+ NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
+ store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
+ FreeTemp(r_tmp);
+ } else {
+ store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
+ }
} else {
RegStorage r_scratch = AllocTemp();
res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
@@ -942,7 +984,12 @@ LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStor
if (mem_ref_type_ == ResourceMask::kDalvikReg) {
DCHECK_EQ(r_base, TargetPtrReg(kSp));
- AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
+ AnnotateDalvikRegAccess(store, (displacement + LOWORD_OFFSET) >> 2,
+ false /* is_load */, r_src.Is64Bit() /* is64bit */);
+ if (store2 != nullptr) {
+ AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
+ false /* is_load */, r_src.Is64Bit() /* is64bit */);
+ }
}
return res;
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 9ab7280793..f078bf6507 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -921,7 +921,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
: exceptions_to_resolve_(exceptions_to_resolve) {}
- virtual bool Visit(mirror::Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+ virtual bool operator()(mirror::Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (auto& m : c->GetMethods(pointer_size)) {
ResolveExceptionsForMethod(&m, pointer_size);
@@ -975,7 +975,7 @@ class RecordImageClassesVisitor : public ClassVisitor {
explicit RecordImageClassesVisitor(std::unordered_set<std::string>* image_classes)
: image_classes_(image_classes) {}
- bool Visit(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool operator()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
std::string temp;
image_classes_->insert(klass->GetDescriptor(&temp));
return true;
@@ -1142,7 +1142,7 @@ class ClinitImageUpdate {
public:
explicit FindImageClassesVisitor(ClinitImageUpdate* data) : data_(data) {}
- bool Visit(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool operator()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
std::string temp;
const char* name = klass->GetDescriptor(&temp);
if (data_->image_class_descriptors_->find(name) != data_->image_class_descriptors_->end()) {
diff --git a/compiler/dwarf/debug_abbrev_writer.h b/compiler/dwarf/debug_abbrev_writer.h
new file mode 100644
index 0000000000..71367e85ad
--- /dev/null
+++ b/compiler/dwarf/debug_abbrev_writer.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+#define ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+
+#include <cstdint>
+#include <type_traits>
+#include <unordered_map>
+
+#include "base/casts.h"
+#include "base/stl_util.h"
+#include "dwarf/dwarf_constants.h"
+#include "dwarf/writer.h"
+#include "leb128.h"
+
+namespace art {
+namespace dwarf {
+
+// Writer for the .debug_abbrev.
+//
+// Abbreviations specify the format of entries in .debug_info.
+// Each entry specifies abbreviation code, which in turns
+// determines all the attributes and their format.
+// It is possible to think of them as type definitions.
+template <typename Vector = std::vector<uint8_t>>
+class DebugAbbrevWriter FINAL : private Writer<Vector> {
+ static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
+
+ public:
+ explicit DebugAbbrevWriter(Vector* buffer)
+ : Writer<Vector>(buffer),
+ current_abbrev_(buffer->get_allocator()) {
+ this->PushUint8(0); // Add abbrev table terminator.
+ }
+
+ // Start abbreviation declaration.
+ void StartAbbrev(Tag tag) {
+ DCHECK(current_abbrev_.empty());
+ EncodeUnsignedLeb128(&current_abbrev_, tag);
+ has_children_offset_ = current_abbrev_.size();
+ current_abbrev_.push_back(0); // Place-holder for DW_CHILDREN.
+ }
+
+ // Add attribute specification.
+ void AddAbbrevAttribute(Attribute name, Form type) {
+ EncodeUnsignedLeb128(&current_abbrev_, name);
+ EncodeUnsignedLeb128(&current_abbrev_, type);
+ }
+
+ // End abbreviation declaration and return its code.
+ // This will deduplicate abbreviations.
+ uint32_t EndAbbrev(Children has_children) {
+ DCHECK(!current_abbrev_.empty());
+ current_abbrev_[has_children_offset_] = has_children;
+ auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_), NextAbbrevCode()));
+ uint32_t abbrev_code = it.first->second;
+ if (UNLIKELY(it.second)) { // Inserted new entry.
+ const Vector& abbrev = it.first->first;
+ this->Pop(); // Remove abbrev table terminator.
+ this->PushUleb128(abbrev_code);
+ this->PushData(abbrev.data(), abbrev.size());
+ this->PushUint8(0); // Attribute list end.
+ this->PushUint8(0); // Attribute list end.
+ this->PushUint8(0); // Add abbrev table terminator.
+ }
+ current_abbrev_.clear();
+ return abbrev_code;
+ }
+
+ // Get the next free abbrev code.
+ uint32_t NextAbbrevCode() {
+ return dchecked_integral_cast<uint32_t>(1 + abbrev_codes_.size());
+ }
+
+ private:
+ Vector current_abbrev_;
+ size_t has_children_offset_ = 0;
+ std::unordered_map<Vector, uint32_t, FNVHash<Vector> > abbrev_codes_;
+};
+
+} // namespace dwarf
+} // namespace art
+
+#endif // ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
index e5bbed3c8e..1e298595a1 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -21,6 +21,7 @@
#include <unordered_map>
#include "base/casts.h"
+#include "dwarf/debug_abbrev_writer.h"
#include "dwarf/dwarf_constants.h"
#include "dwarf/expression.h"
#include "dwarf/writer.h"
@@ -29,24 +30,8 @@
namespace art {
namespace dwarf {
-// 32-bit FNV-1a hash function which we use to find duplicate abbreviations.
-// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
-template <typename Vector>
-struct FNVHash {
- static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
-
- size_t operator()(const Vector& v) const {
- uint32_t hash = 2166136261u;
- for (size_t i = 0; i < v.size(); i++) {
- hash = (hash ^ v[i]) * 16777619u;
- }
- return hash;
- }
-};
-
/*
* Writer for debug information entries (DIE).
- * It also handles generation of abbreviations.
*
* Usage:
* StartTag(DW_TAG_compile_unit);
@@ -69,13 +54,13 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
if (inside_entry_) {
// Write abbrev code for the previous entry.
// Parent entry is finalized before any children are written.
- this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_yes));
+ this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_yes));
inside_entry_ = false;
}
- StartAbbrev(tag);
+ debug_abbrev_->StartAbbrev(tag);
// Abbrev code placeholder of sufficient size.
abbrev_code_offset_ = this->data()->size();
- this->PushUleb128(NextAbbrevCode());
+ this->PushUleb128(debug_abbrev_->NextAbbrevCode());
depth_++;
inside_entry_ = true;
return abbrev_code_offset_ + kCompilationUnitHeaderSize;
@@ -86,7 +71,7 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
DCHECK_GT(depth_, 0);
if (inside_entry_) {
// Write abbrev code for this entry.
- this->UpdateUleb128(abbrev_code_offset_, EndAbbrev(DW_CHILDREN_no));
+ this->UpdateUleb128(abbrev_code_offset_, debug_abbrev_->EndAbbrev(DW_CHILDREN_no));
inside_entry_ = false;
// This entry has no children and so there is no terminator.
} else {
@@ -98,7 +83,7 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
}
void WriteAddr(Attribute attrib, uint64_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_addr);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_addr);
patch_locations_.push_back(this->data()->size());
if (is64bit_) {
this->PushUint64(value);
@@ -108,85 +93,89 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
}
void WriteBlock(Attribute attrib, const uint8_t* ptr, size_t num_bytes) {
- AddAbbrevAttribute(attrib, DW_FORM_block);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_block);
this->PushUleb128(num_bytes);
this->PushData(ptr, num_bytes);
}
void WriteExprLoc(Attribute attrib, const Expression& expr) {
- AddAbbrevAttribute(attrib, DW_FORM_exprloc);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_exprloc);
this->PushUleb128(dchecked_integral_cast<uint32_t>(expr.size()));
this->PushData(expr.data());
}
void WriteData1(Attribute attrib, uint8_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_data1);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data1);
this->PushUint8(value);
}
void WriteData2(Attribute attrib, uint16_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_data2);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data2);
this->PushUint16(value);
}
void WriteData4(Attribute attrib, uint32_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_data4);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data4);
this->PushUint32(value);
}
void WriteData8(Attribute attrib, uint64_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_data8);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_data8);
this->PushUint64(value);
}
void WriteSecOffset(Attribute attrib, uint32_t offset) {
- AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
this->PushUint32(offset);
}
void WriteSdata(Attribute attrib, int value) {
- AddAbbrevAttribute(attrib, DW_FORM_sdata);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_sdata);
this->PushSleb128(value);
}
void WriteUdata(Attribute attrib, int value) {
- AddAbbrevAttribute(attrib, DW_FORM_udata);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
this->PushUleb128(value);
}
void WriteUdata(Attribute attrib, uint32_t value) {
- AddAbbrevAttribute(attrib, DW_FORM_udata);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_udata);
this->PushUleb128(value);
}
void WriteFlag(Attribute attrib, bool value) {
- AddAbbrevAttribute(attrib, DW_FORM_flag);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag);
this->PushUint8(value ? 1 : 0);
}
+ void WriteFlagPresent(Attribute attrib) {
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_flag_present);
+ }
+
void WriteRef4(Attribute attrib, uint32_t cu_offset) {
- AddAbbrevAttribute(attrib, DW_FORM_ref4);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref4);
this->PushUint32(cu_offset);
}
void WriteRef(Attribute attrib, uint32_t cu_offset) {
- AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_ref_udata);
this->PushUleb128(cu_offset);
}
void WriteString(Attribute attrib, const char* value) {
- AddAbbrevAttribute(attrib, DW_FORM_string);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_string);
this->PushString(value);
}
void WriteStrp(Attribute attrib, size_t debug_str_offset) {
- AddAbbrevAttribute(attrib, DW_FORM_strp);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
this->PushUint32(dchecked_integral_cast<uint32_t>(debug_str_offset));
}
void WriteStrp(Attribute attrib, const char* str, size_t len,
std::vector<uint8_t>* debug_str) {
- AddAbbrevAttribute(attrib, DW_FORM_strp);
+ debug_abbrev_->AddAbbrevAttribute(attrib, DW_FORM_strp);
this->PushUint32(debug_str->size());
debug_str->insert(debug_str->end(), str, str + len);
debug_str->push_back(0);
@@ -209,16 +198,13 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
using Writer<Vector>::UpdateUint32;
DebugInfoEntryWriter(bool is64bitArch,
- Vector* debug_abbrev,
+ DebugAbbrevWriter<Vector>* debug_abbrev,
const typename Vector::allocator_type& alloc =
typename Vector::allocator_type())
: Writer<Vector>(&entries_),
debug_abbrev_(debug_abbrev),
- current_abbrev_(alloc),
- abbrev_codes_(alloc),
entries_(alloc),
is64bit_(is64bitArch) {
- debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
}
~DebugInfoEntryWriter() {
@@ -227,53 +213,7 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
}
private:
- // Start abbreviation declaration.
- void StartAbbrev(Tag tag) {
- current_abbrev_.clear();
- EncodeUnsignedLeb128(&current_abbrev_, tag);
- has_children_offset_ = current_abbrev_.size();
- current_abbrev_.push_back(0); // Place-holder for DW_CHILDREN.
- }
-
- // Add attribute specification.
- void AddAbbrevAttribute(Attribute name, Form type) {
- DCHECK(inside_entry_) << "Call StartTag before adding attributes.";
- EncodeUnsignedLeb128(&current_abbrev_, name);
- EncodeUnsignedLeb128(&current_abbrev_, type);
- }
-
- int NextAbbrevCode() {
- return 1 + abbrev_codes_.size();
- }
-
- // End abbreviation declaration and return its code.
- int EndAbbrev(Children has_children) {
- DCHECK(!current_abbrev_.empty());
- current_abbrev_[has_children_offset_] = has_children;
- auto it = abbrev_codes_.insert(std::make_pair(std::move(current_abbrev_),
- NextAbbrevCode()));
- int abbrev_code = it.first->second;
- if (UNLIKELY(it.second)) { // Inserted new entry.
- const Vector& abbrev = it.first->first;
- debug_abbrev_.Pop(); // Remove abbrev table terminator.
- debug_abbrev_.PushUleb128(abbrev_code);
- debug_abbrev_.PushData(abbrev.data(), abbrev.size());
- debug_abbrev_.PushUint8(0); // Attribute list end.
- debug_abbrev_.PushUint8(0); // Attribute list end.
- debug_abbrev_.PushUint8(0); // Add abbrev table terminator.
- }
- return abbrev_code;
- }
-
- private:
- // Fields for writing and deduplication of abbrevs.
- Writer<Vector> debug_abbrev_;
- Vector current_abbrev_;
- size_t has_children_offset_ = 0;
- std::unordered_map<Vector, int,
- FNVHash<Vector> > abbrev_codes_;
-
- // Fields for writing of debugging information entries.
+ DebugAbbrevWriter<Vector>* debug_abbrev_;
Vector entries_;
bool is64bit_;
int depth_ = 0;
diff --git a/compiler/dwarf/dedup_vector.h b/compiler/dwarf/dedup_vector.h
deleted file mode 100644
index 7fb21b76e2..0000000000
--- a/compiler/dwarf/dedup_vector.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DWARF_DEDUP_VECTOR_H_
-#define ART_COMPILER_DWARF_DEDUP_VECTOR_H_
-
-#include <vector>
-#include <unordered_map>
-
-namespace art {
-namespace dwarf {
- class DedupVector {
- public:
- // Returns an offset to previously inserted identical block of data,
- // or appends the data at the end of the vector and returns offset to it.
- size_t Insert(const uint8_t* ptr, size_t num_bytes) {
- // See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
- uint32_t hash = 2166136261u;
- for (size_t i = 0; i < num_bytes; i++) {
- hash = (hash ^ ptr[i]) * 16777619u;
- }
- // Try to find existing copy of the data.
- const auto& range = hash_to_offset_.equal_range(hash);
- for (auto it = range.first; it != range.second; ++it) {
- const size_t offset = it->second;
- if (offset + num_bytes <= vector_.size() &&
- memcmp(vector_.data() + offset, ptr, num_bytes) == 0) {
- return offset;
- }
- }
- // Append the data at the end of the vector.
- const size_t new_offset = vector_.size();
- hash_to_offset_.emplace(hash, new_offset);
- vector_.insert(vector_.end(), ptr, ptr + num_bytes);
- return new_offset;
- }
-
- const std::vector<uint8_t>& Data() const { return vector_; }
-
- private:
- struct IdentityHash {
- size_t operator()(uint32_t v) const { return v; }
- };
-
- // We store the full hash as the key to simplify growing of the table.
- // It avoids storing or referencing the actual data in the hash-table.
- std::unordered_multimap<uint32_t, size_t, IdentityHash> hash_to_offset_;
-
- std::vector<uint8_t> vector_;
- };
-} // namespace dwarf
-} // namespace art
-
-#endif // ART_COMPILER_DWARF_DEDUP_VECTOR_H_
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index e9cd421da9..32373119b2 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -283,7 +283,8 @@ TEST_F(DwarfTest, DebugLineSpecialOpcodes) {
TEST_F(DwarfTest, DebugInfo) {
constexpr bool is64bit = false;
- DebugInfoEntryWriter<> info(is64bit, &debug_abbrev_data_);
+ DebugAbbrevWriter<> debug_abbrev(&debug_abbrev_data_);
+ DebugInfoEntryWriter<> info(is64bit, &debug_abbrev);
DW_CHECK("Contents of the .debug_info section:");
info.StartTag(dwarf::DW_TAG_compile_unit);
DW_CHECK("Abbrev Number: 1 (DW_TAG_compile_unit)");
diff --git a/compiler/dwarf/register.h b/compiler/dwarf/register.h
index 35b3e15d83..aa3070a9cd 100644
--- a/compiler/dwarf/register.h
+++ b/compiler/dwarf/register.h
@@ -42,6 +42,8 @@ class Reg {
static Reg Arm64Fp(int num) { return Reg(64 + num); } // V0-V31.
static Reg MipsCore(int num) { return Reg(num); }
static Reg Mips64Core(int num) { return Reg(num); }
+ static Reg MipsFp(int num) { return Reg(32 + num); }
+ static Reg Mips64Fp(int num) { return Reg(32 + num); }
static Reg X86Core(int num) { return Reg(num); }
static Reg X86Fp(int num) { return Reg(21 + num); }
static Reg X86_64Core(int num) {
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 2e98b69c47..d1f50073a0 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -27,7 +27,6 @@
#include "compiled_method.h"
#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
-#include "dwarf/dedup_vector.h"
#include "dwarf/expression.h"
#include "dwarf/headers.h"
#include "dwarf/method_debug_info.h"
@@ -90,6 +89,10 @@ static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
return Reg::X86Fp(machine_reg);
case kX86_64:
return Reg::X86_64Fp(machine_reg);
+ case kMips:
+ return Reg::MipsFp(machine_reg);
+ case kMips64:
+ return Reg::Mips64Fp(machine_reg);
default:
LOG(FATAL) << "Unknown instruction set: " << isa;
UNREACHABLE();
@@ -162,6 +165,14 @@ static void WriteCIE(InstructionSet isa,
opcodes.SameValue(Reg::MipsCore(reg));
}
}
+ // fp registers.
+ for (int reg = 0; reg < 32; reg++) {
+ if (reg < 24) {
+ opcodes.Undefined(Reg::Mips64Fp(reg));
+ } else {
+ opcodes.SameValue(Reg::Mips64Fp(reg));
+ }
+ }
auto return_reg = Reg::MipsCore(31); // R31(RA).
WriteCIE(is64bit, return_reg, opcodes, format, buffer);
return;
@@ -474,7 +485,7 @@ class DebugInfoWriter {
public:
explicit CompilationUnitWriter(DebugInfoWriter* owner)
: owner_(owner),
- info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &debug_abbrev_) {
+ info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) {
}
void Write(const CompilationUnit& compilation_unit) {
@@ -485,9 +496,9 @@ class DebugInfoWriter {
const uintptr_t cu_size = compilation_unit.high_pc_ - compilation_unit.low_pc_;
info_.StartTag(DW_TAG_compile_unit);
- info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
+ info_.WriteString(DW_AT_producer, "Android dex2oat");
info_.WriteData1(DW_AT_language, DW_LANG_Java);
- info_.WriteStrp(DW_AT_comp_dir, owner_->WriteString("$JAVA_SRC_ROOT"));
+ info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_);
info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
@@ -505,7 +516,7 @@ class DebugInfoWriter {
// Enclose the method in correct class definition.
if (last_dex_class_desc != dex_class_desc) {
if (last_dex_class_desc != nullptr) {
- EndClassTag(last_dex_class_desc);
+ EndClassTag();
}
// Write reference tag for the class we are about to declare.
size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
@@ -516,7 +527,7 @@ class DebugInfoWriter {
// Declare the class that owns this method.
size_t class_offset = StartClassTag(dex_class_desc);
info_.UpdateUint32(type_attrib_offset, class_offset);
- info_.WriteFlag(DW_AT_declaration, true);
+ info_.WriteFlagPresent(DW_AT_declaration);
// Check that each class is defined only once.
bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
CHECK(unique) << "Redefinition of " << dex_class_desc;
@@ -542,7 +553,7 @@ class DebugInfoWriter {
if (!is_static) {
info_.StartTag(DW_TAG_formal_parameter);
WriteName("this");
- info_.WriteFlag(DW_AT_artificial, true);
+ info_.WriteFlagPresent(DW_AT_artificial);
WriteLazyType(dex_class_desc);
if (dex_code != nullptr) {
// Write the stack location of the parameter.
@@ -601,25 +612,32 @@ class DebugInfoWriter {
CHECK_EQ(info_.Depth(), start_depth); // Balanced start/end.
}
if (last_dex_class_desc != nullptr) {
- EndClassTag(last_dex_class_desc);
+ EndClassTag();
}
- CHECK_EQ(info_.Depth(), 1);
FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
info_.EndTag(); // DW_TAG_compile_unit
+ CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
- const size_t debug_abbrev_offset =
- owner_->debug_abbrev_.Insert(debug_abbrev_.data(), debug_abbrev_.size());
+ // All compilation units share single table which is at the start of .debug_abbrev.
+ const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
}
void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
info_.StartTag(DW_TAG_compile_unit);
- info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
+ info_.WriteString(DW_AT_producer, "Android dex2oat");
info_.WriteData1(DW_AT_language, DW_LANG_Java);
+ // Base class references to be patched at the end.
+ std::map<size_t, mirror::Class*> base_class_references;
+
+ // Already written declarations or definitions.
+ std::map<mirror::Class*, size_t> class_declarations;
+
std::vector<uint8_t> expr_buffer;
for (mirror::Class* type : types) {
if (type->IsPrimitive()) {
@@ -633,6 +651,7 @@ class DebugInfoWriter {
uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
info_.StartTag(DW_TAG_array_type);
std::string descriptor_string;
WriteLazyType(element_type->GetDescriptor(&descriptor_string));
@@ -650,22 +669,10 @@ class DebugInfoWriter {
// Skip. Variables cannot have an interface as a dynamic type.
// We do not expose the interface information to the debugger in any way.
} else {
- // Declare base class. We can not use the standard WriteLazyType
- // since we want to avoid the DW_TAG_reference_tag wrapping.
- mirror::Class* base_class = type->GetSuperClass();
- size_t base_class_declaration_offset = 0;
- if (base_class != nullptr) {
- std::string tmp_storage;
- const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
- base_class_declaration_offset = StartClassTag(base_class_desc);
- info_.WriteFlag(DW_AT_declaration, true);
- WriteLinkageName(base_class);
- EndClassTag(base_class_desc);
- }
-
std::string descriptor_string;
const char* desc = type->GetDescriptor(&descriptor_string);
- StartClassTag(desc);
+ size_t class_offset = StartClassTag(desc);
+ class_declarations.emplace(type, class_offset);
if (!type->IsVariableSize()) {
info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
@@ -680,7 +687,7 @@ class DebugInfoWriter {
info_.StartTag(DW_TAG_member);
WriteName(".dynamic_type");
WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
- info_.WriteFlag(DW_AT_artificial, true);
+ info_.WriteFlagPresent(DW_AT_artificial);
// Create DWARF expression to get the value of the methods_ field.
Expression expr(&expr_buffer);
// The address of the object has been implicitly pushed on the stack.
@@ -702,9 +709,11 @@ class DebugInfoWriter {
}
// Base class.
+ mirror::Class* base_class = type->GetSuperClass();
if (base_class != nullptr) {
info_.StartTag(DW_TAG_inheritance);
- info_.WriteRef4(DW_AT_type, base_class_declaration_offset);
+ base_class_references.emplace(info_.size(), base_class);
+ info_.WriteRef4(DW_AT_type, 0);
info_.WriteUdata(DW_AT_data_member_location, 0);
info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
info_.EndTag(); // DW_TAG_inheritance.
@@ -743,18 +752,40 @@ class DebugInfoWriter {
info_.EndTag(); // DW_TAG_member.
}
- EndClassTag(desc);
+ EndClassTag();
+ }
+ }
+
+ // Write base class declarations.
+ for (const auto& base_class_reference : base_class_references) {
+ size_t reference_offset = base_class_reference.first;
+ mirror::Class* base_class = base_class_reference.second;
+ const auto& it = class_declarations.find(base_class);
+ if (it != class_declarations.end()) {
+ info_.UpdateUint32(reference_offset, it->second);
+ } else {
+ // Declare base class. We can not use the standard WriteLazyType
+ // since we want to avoid the DW_TAG_reference_tag wrapping.
+ std::string tmp_storage;
+ const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+ size_t base_class_declaration_offset = StartClassTag(base_class_desc);
+ info_.WriteFlagPresent(DW_AT_declaration);
+ WriteLinkageName(base_class);
+ EndClassTag();
+ class_declarations.emplace(base_class, base_class_declaration_offset);
+ info_.UpdateUint32(reference_offset, base_class_declaration_offset);
}
}
- CHECK_EQ(info_.Depth(), 1);
FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
info_.EndTag(); // DW_TAG_compile_unit.
+ CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
- const size_t debug_abbrev_offset =
- owner_->debug_abbrev_.Insert(debug_abbrev_.data(), debug_abbrev_.size());
+ // All compilation units share single table which is at the start of .debug_abbrev.
+ const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
}
@@ -840,10 +871,6 @@ class DebugInfoWriter {
expr.WriteOpReg(Reg::ArmDp(value / 2).num());
break;
}
- if (isa == kMips || isa == kMips64) {
- // TODO: Find what the DWARF floating point register numbers are on MIPS.
- break;
- }
expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
reg_hi.GetValue() == reg_lo.GetValue()) {
@@ -940,7 +967,7 @@ class DebugInfoWriter {
private:
void WriteName(const char* name) {
if (name != nullptr) {
- info_.WriteStrp(DW_AT_name, owner_->WriteString(name));
+ info_.WriteString(DW_AT_name, name);
}
}
@@ -957,8 +984,8 @@ class DebugInfoWriter {
if (desc[0] == 'L') {
// Class type. For example: Lpackage/name;
size_t class_offset = StartClassTag(desc.c_str());
- info_.WriteFlag(DW_AT_declaration, true);
- EndClassTag(desc.c_str());
+ info_.WriteFlagPresent(DW_AT_declaration);
+ EndClassTag();
// Reference to the class type.
offset = info_.StartTag(DW_TAG_reference_type);
info_.WriteRef(DW_AT_type, class_offset);
@@ -966,8 +993,9 @@ class DebugInfoWriter {
} else if (desc[0] == '[') {
// Array type.
size_t element_type = WriteTypeDeclaration(desc.substr(1));
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
size_t array_type = info_.StartTag(DW_TAG_array_type);
- info_.WriteFlag(DW_AT_declaration, true);
+ info_.WriteFlagPresent(DW_AT_declaration);
info_.WriteRef(DW_AT_type, element_type);
info_.EndTag();
offset = info_.StartTag(DW_TAG_reference_type);
@@ -1028,6 +1056,7 @@ class DebugInfoWriter {
LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
UNREACHABLE();
}
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
offset = info_.StartTag(DW_TAG_base_type);
WriteName(name);
info_.WriteData1(DW_AT_encoding, encoding);
@@ -1042,36 +1071,52 @@ class DebugInfoWriter {
// Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
// Returns offset of the class tag in the compilation unit.
size_t StartClassTag(const char* desc) {
- DCHECK(desc != nullptr && desc[0] == 'L');
- // Enclose the type in namespace tags.
- const char* end;
- for (desc = desc + 1; (end = strchr(desc, '/')) != nullptr; desc = end + 1) {
- info_.StartTag(DW_TAG_namespace);
- WriteName(std::string(desc, end - desc).c_str());
- }
- // Start the class tag.
+ std::string name = SetNamespaceForClass(desc);
size_t offset = info_.StartTag(DW_TAG_class_type);
- end = strchr(desc, ';');
- CHECK(end != nullptr);
- WriteName(std::string(desc, end - desc).c_str());
+ WriteName(name.c_str());
return offset;
}
- void EndClassTag(const char* desc) {
- DCHECK(desc != nullptr && desc[0] == 'L');
- // End the class tag.
+ void EndClassTag() {
info_.EndTag();
- // Close namespace tags.
- const char* end;
- for (desc = desc + 1; (end = strchr(desc, '/')) != nullptr; desc = end + 1) {
+ }
+
+ // Set the current namespace nesting to one required by the given class.
+ // Returns the class name with namespaces, 'L', and ';' stripped.
+ std::string SetNamespaceForClass(const char* desc) {
+ DCHECK(desc != nullptr && desc[0] == 'L');
+ desc++; // Skip the initial 'L'.
+ size_t depth = 0;
+ for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
+ // Check whether the name at this depth is already what we need.
+ if (depth < current_namespace_.size()) {
+ const std::string& name = current_namespace_[depth];
+ if (name.compare(0, name.size(), desc, end - desc) == 0) {
+ continue;
+ }
+ }
+ // Otherwise we need to open a new namespace tag at this depth.
+ CloseNamespacesAboveDepth(depth);
+ info_.StartTag(DW_TAG_namespace);
+ std::string name(desc, end - desc);
+ WriteName(name.c_str());
+ current_namespace_.push_back(std::move(name));
+ }
+ CloseNamespacesAboveDepth(depth);
+ return std::string(desc, strchr(desc, ';') - desc);
+ }
+
+ // Close namespace tags to reach the given nesting depth.
+ void CloseNamespacesAboveDepth(size_t depth) {
+ DCHECK_LE(depth, current_namespace_.size());
+ while (current_namespace_.size() > depth) {
info_.EndTag();
+ current_namespace_.pop_back();
}
}
// For access to the ELF sections.
DebugInfoWriter<ElfTypes>* owner_;
- // Debug abbrevs for this compilation unit only.
- std::vector<uint8_t> debug_abbrev_;
// Temporary buffer to create and store the entries.
DebugInfoEntryWriter<> info_;
// Cache of already translated type descriptors.
@@ -1079,10 +1124,14 @@ class DebugInfoWriter {
// 32-bit references which need to be resolved to a type later.
// Given type may be used multiple times. Therefore we need a multimap.
std::multimap<std::string, size_t> lazy_types_; // type_desc -> patch_offset.
+ // The current set of open namespace tags which are active and not closed yet.
+ std::vector<std::string> current_namespace_;
};
public:
- explicit DebugInfoWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
+ explicit DebugInfoWriter(ElfBuilder<ElfTypes>* builder)
+ : builder_(builder),
+ debug_abbrev_(&debug_abbrev_buffer_) {
}
void Start() {
@@ -1103,21 +1152,16 @@ class DebugInfoWriter {
builder_->GetDebugInfo()->End();
builder_->WritePatches(".debug_info.oat_patches",
ArrayRef<const uintptr_t>(debug_info_patches_));
- builder_->WriteSection(".debug_abbrev", &debug_abbrev_.Data());
- builder_->WriteSection(".debug_str", &debug_str_.Data());
+ builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
builder_->WriteSection(".debug_loc", &debug_loc_);
builder_->WriteSection(".debug_ranges", &debug_ranges_);
}
private:
- size_t WriteString(const char* str) {
- return debug_str_.Insert(reinterpret_cast<const uint8_t*>(str), strlen(str) + 1);
- }
-
ElfBuilder<ElfTypes>* builder_;
std::vector<uintptr_t> debug_info_patches_;
- DedupVector debug_abbrev_;
- DedupVector debug_str_;
+ std::vector<uint8_t> debug_abbrev_buffer_;
+ DebugAbbrevWriter<> debug_abbrev_;
std::vector<uint8_t> debug_loc_;
std::vector<uint8_t> debug_ranges_;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 60dfcfb508..73574ba673 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -714,7 +714,7 @@ bool ImageWriter::AllocMemory() {
class ComputeLazyFieldsForClassesVisitor : public ClassVisitor {
public:
- bool Visit(Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool operator()(Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
StackHandleScope<1> hs(Thread::Current());
mirror::Class::ComputeName(hs.NewHandle(c));
return true;
@@ -852,7 +852,7 @@ class NonImageClassesVisitor : public ClassVisitor {
public:
explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
- bool Visit(Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool operator()(Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
if (!image_writer_->KeepClass(klass)) {
classes_to_prune_.insert(klass);
}
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index eee6116098..c307522f2b 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1227,27 +1227,28 @@ class BCEVisitor : public HGraphVisitor {
InductionVarRange::Value v1;
InductionVarRange::Value v2;
bool needs_finite_test = false;
- induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test);
- do {
- if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) &&
- v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) {
- DCHECK(v1.a_constant == 1 || v1.instruction == nullptr);
- DCHECK(v2.a_constant == 1 || v2.instruction == nullptr);
- ValueRange index_range(GetGraph()->GetArena(),
- ValueBound(v1.instruction, v1.b_constant),
- ValueBound(v2.instruction, v2.b_constant));
- // If analysis reveals a certain OOB, disable dynamic BCE.
- if (index_range.GetLower().LessThan(array_range->GetLower()) ||
- index_range.GetUpper().GreaterThan(array_range->GetUpper())) {
- *try_dynamic_bce = false;
- return false;
- }
- // Use analysis for static bce only if loop is finite.
- if (!needs_finite_test && index_range.FitsIn(array_range)) {
- return true;
+ if (induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test)) {
+ do {
+ if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) &&
+ v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) {
+ DCHECK(v1.a_constant == 1 || v1.instruction == nullptr);
+ DCHECK(v2.a_constant == 1 || v2.instruction == nullptr);
+ ValueRange index_range(GetGraph()->GetArena(),
+ ValueBound(v1.instruction, v1.b_constant),
+ ValueBound(v2.instruction, v2.b_constant));
+ // If analysis reveals a certain OOB, disable dynamic BCE.
+ if (index_range.GetLower().LessThan(array_range->GetLower()) ||
+ index_range.GetUpper().GreaterThan(array_range->GetUpper())) {
+ *try_dynamic_bce = false;
+ return false;
+ }
+ // Use analysis for static bce only if loop is finite.
+ if (!needs_finite_test && index_range.FitsIn(array_range)) {
+ return true;
+ }
}
- }
- } while (induction_range_.RefineOuter(&v1, &v2));
+ } while (induction_range_.RefineOuter(&v1, &v2));
+ }
return false;
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a59024e139..4179fabe48 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1556,21 +1556,13 @@ void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCod
UseScratchRegisterScope temps(GetVIXLAssembler());
Register temp = temps.AcquireW();
size_t status_offset = mirror::Class::StatusOffset().SizeValue();
- bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
// Even if the initialized flag is set, we need to ensure consistent memory ordering.
- if (use_acquire_release) {
- // TODO(vixl): Let the MacroAssembler handle MemOperand.
- __ Add(temp, class_reg, status_offset);
- __ Ldar(temp, HeapOperand(temp));
- __ Cmp(temp, mirror::Class::kStatusInitialized);
- __ B(lt, slow_path->GetEntryLabel());
- } else {
- __ Ldr(temp, HeapOperand(class_reg, status_offset));
- __ Cmp(temp, mirror::Class::kStatusInitialized);
- __ B(lt, slow_path->GetEntryLabel());
- __ Dmb(InnerShareable, BarrierReads);
- }
+ // TODO(vixl): Let the MacroAssembler handle MemOperand.
+ __ Add(temp, class_reg, status_offset);
+ __ Ldar(temp, HeapOperand(temp));
+ __ Cmp(temp, mirror::Class::kStatusInitialized);
+ __ B(lt, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
}
@@ -1716,9 +1708,7 @@ void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction,
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Primitive::Type field_type = field_info.GetFieldType();
BlockPoolsScope block_pools(GetVIXLAssembler());
-
MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), field_info.GetFieldOffset());
- bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
if (field_type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// Object FieldGet with Baker's read barrier case.
@@ -1736,26 +1726,15 @@ void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction,
offset,
temp,
/* needs_null_check */ true,
- field_info.IsVolatile() && use_acquire_release);
- if (field_info.IsVolatile() && !use_acquire_release) {
- // For IRIW sequential consistency kLoadAny is not sufficient.
- codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
- }
+ field_info.IsVolatile());
} else {
// General case.
if (field_info.IsVolatile()) {
- if (use_acquire_release) {
- // Note that a potential implicit null check is handled in this
- // CodeGeneratorARM64::LoadAcquire call.
- // NB: LoadAcquire will record the pc info if needed.
- codegen_->LoadAcquire(
- instruction, OutputCPURegister(instruction), field, /* needs_null_check */ true);
- } else {
- codegen_->Load(field_type, OutputCPURegister(instruction), field);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- // For IRIW sequential consistency kLoadAny is not sufficient.
- codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
- }
+ // Note that a potential implicit null check is handled in this
+ // CodeGeneratorARM64::LoadAcquire call.
+ // NB: LoadAcquire will record the pc info if needed.
+ codegen_->LoadAcquire(
+ instruction, OutputCPURegister(instruction), field, /* needs_null_check */ true);
} else {
codegen_->Load(field_type, OutputCPURegister(instruction), field);
codegen_->MaybeRecordImplicitNullCheck(instruction);
@@ -1791,7 +1770,6 @@ void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
CPURegister source = value;
Offset offset = field_info.GetFieldOffset();
Primitive::Type field_type = field_info.GetFieldType();
- bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
{
// We use a block to end the scratch scope before the write barrier, thus
@@ -1807,15 +1785,8 @@ void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
}
if (field_info.IsVolatile()) {
- if (use_acquire_release) {
- codegen_->StoreRelease(field_type, source, HeapOperand(obj, offset));
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- } else {
- codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
- codegen_->Store(field_type, source, HeapOperand(obj, offset));
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
- }
+ codegen_->StoreRelease(field_type, source, HeapOperand(obj, offset));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
} else {
codegen_->Store(field_type, source, HeapOperand(obj, offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index fa119bbeb1..961fe62932 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1132,11 +1132,11 @@ size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint3
}
void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
- stream << MipsManagedRegister::FromCoreRegister(Register(reg));
+ stream << Register(reg);
}
void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
- stream << MipsManagedRegister::FromFRegister(FRegister(reg));
+ stream << FRegister(reg);
}
void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
@@ -5287,12 +5287,27 @@ void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invo
codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
}
-void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet*) {
- UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips";
+void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
}
-void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet*) {
- UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips";
+void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ uint32_t method_offset = 0;
+ if (instruction->GetTableKind() == HClassTableGet::kVTable) {
+ method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ instruction->GetIndex(), kMipsPointerSize).SizeValue();
+ } else {
+ method_offset = mirror::Class::EmbeddedImTableEntryOffset(
+ instruction->GetIndex() % mirror::Class::kImtSize, kMipsPointerSize).Uint32Value();
+ }
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ method_offset);
}
#undef __
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 3c928dedde..3e1563c66b 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -106,7 +106,7 @@ Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type)
}
#define __ down_cast<CodeGeneratorMIPS64*>(codegen)->GetAssembler()->
-#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value()
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value()
class BoundsCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 {
public:
@@ -437,7 +437,7 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph,
#undef __
#define __ down_cast<Mips64Assembler*>(GetAssembler())->
-#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, x).Int32Value()
+#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, x).Int32Value()
void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) {
// Ensure that we fix up branches.
@@ -486,12 +486,12 @@ void ParallelMoveResolverMIPS64::EmitSwap(size_t index) {
void ParallelMoveResolverMIPS64::RestoreScratch(int reg) {
// Pop reg
__ Ld(GpuRegister(reg), SP, 0);
- __ DecreaseFrameSize(kMips64WordSize);
+ __ DecreaseFrameSize(kMips64DoublewordSize);
}
void ParallelMoveResolverMIPS64::SpillScratch(int reg) {
// Push reg
- __ IncreaseFrameSize(kMips64WordSize);
+ __ IncreaseFrameSize(kMips64DoublewordSize);
__ Sd(GpuRegister(reg), SP, 0);
}
@@ -503,7 +503,7 @@ void ParallelMoveResolverMIPS64::Exchange(int index1, int index2, bool double_sl
// automatically unspilled when the scratch scope object is destroyed).
ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
// If V0 spills onto the stack, SP-relative offsets need to be adjusted.
- int stack_offset = ensure_scratch.IsSpilled() ? kMips64WordSize : 0;
+ int stack_offset = ensure_scratch.IsSpilled() ? kMips64DoublewordSize : 0;
__ LoadFromOffset(load_type,
GpuRegister(ensure_scratch.GetRegister()),
SP,
@@ -523,7 +523,9 @@ static dwarf::Reg DWARFReg(GpuRegister reg) {
return dwarf::Reg::Mips64Core(static_cast<int>(reg));
}
-// TODO: mapping of floating-point registers to DWARF
+static dwarf::Reg DWARFReg(FpuRegister reg) {
+ return dwarf::Reg::Mips64Fp(static_cast<int>(reg));
+}
void CodeGeneratorMIPS64::GenerateFrameEntry() {
__ Bind(&frame_entry_label_);
@@ -562,7 +564,7 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() {
for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
GpuRegister reg = kCoreCalleeSaves[i];
if (allocated_registers_.ContainsCoreRegister(reg)) {
- ofs -= kMips64WordSize;
+ ofs -= kMips64DoublewordSize;
__ Sd(reg, SP, ofs);
__ cfi().RelOffset(DWARFReg(reg), ofs);
}
@@ -571,9 +573,9 @@ void CodeGeneratorMIPS64::GenerateFrameEntry() {
for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
FpuRegister reg = kFpuCalleeSaves[i];
if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
- ofs -= kMips64WordSize;
+ ofs -= kMips64DoublewordSize;
__ Sdc1(reg, SP, ofs);
- // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
+ __ cfi().RelOffset(DWARFReg(reg), ofs);
}
}
@@ -609,8 +611,8 @@ void CodeGeneratorMIPS64::GenerateFrameExit() {
FpuRegister reg = kFpuCalleeSaves[i];
if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
__ Ldc1(reg, SP, ofs);
- ofs += kMips64WordSize;
- // TODO: __ cfi().Restore(DWARFReg(reg));
+ ofs += kMips64DoublewordSize;
+ __ cfi().Restore(DWARFReg(reg));
}
}
@@ -618,7 +620,7 @@ void CodeGeneratorMIPS64::GenerateFrameExit() {
GpuRegister reg = kCoreCalleeSaves[i];
if (allocated_registers_.ContainsCoreRegister(reg)) {
__ Ld(reg, SP, ofs);
- ofs += kMips64WordSize;
+ ofs += kMips64DoublewordSize;
__ cfi().Restore(DWARFReg(reg));
}
}
@@ -976,7 +978,7 @@ void CodeGeneratorMIPS64::MarkGCCard(GpuRegister object,
__ LoadFromOffset(kLoadDoubleword,
card,
TR,
- Thread::CardTableOffset<kMips64WordSize>().Int32Value());
+ Thread::CardTableOffset<kMips64DoublewordSize>().Int32Value());
__ Dsrl(temp, object, gc::accounting::CardTable::kCardShift);
__ Daddu(temp, card, temp);
__ Sb(card, temp, 0);
@@ -994,10 +996,11 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const {
blocked_core_registers_[SP] = true;
blocked_core_registers_[RA] = true;
- // AT and TMP(T8) are used as temporary/scratch registers
- // (similar to how AT is used by MIPS assemblers).
+ // AT, TMP(T8) and TMP2(T3) are used as temporary/scratch
+ // registers (similar to how AT is used by MIPS assemblers).
blocked_core_registers_[AT] = true;
blocked_core_registers_[TMP] = true;
+ blocked_core_registers_[TMP2] = true;
blocked_fpu_registers_[FTMP] = true;
// Reserve suspend and thread registers.
@@ -1021,22 +1024,22 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const {
size_t CodeGeneratorMIPS64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
__ StoreToOffset(kStoreDoubleword, GpuRegister(reg_id), SP, stack_index);
- return kMips64WordSize;
+ return kMips64DoublewordSize;
}
size_t CodeGeneratorMIPS64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
__ LoadFromOffset(kLoadDoubleword, GpuRegister(reg_id), SP, stack_index);
- return kMips64WordSize;
+ return kMips64DoublewordSize;
}
size_t CodeGeneratorMIPS64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
__ StoreFpuToOffset(kStoreDoubleword, FpuRegister(reg_id), SP, stack_index);
- return kMips64WordSize;
+ return kMips64DoublewordSize;
}
size_t CodeGeneratorMIPS64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
__ LoadFpuFromOffset(kLoadDoubleword, FpuRegister(reg_id), SP, stack_index);
- return kMips64WordSize;
+ return kMips64DoublewordSize;
}
void CodeGeneratorMIPS64::DumpCoreRegister(std::ostream& stream, int reg) const {
@@ -1051,7 +1054,7 @@ void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint,
HInstruction* instruction,
uint32_t dex_pc,
SlowPathCode* slow_path) {
- InvokeRuntime(GetThreadOffset<kMips64WordSize>(entrypoint).Int32Value(),
+ InvokeRuntime(GetThreadOffset<kMips64DoublewordSize>(entrypoint).Int32Value(),
instruction,
dex_pc,
slow_path);
@@ -1091,7 +1094,7 @@ void InstructionCodeGeneratorMIPS64::GenerateSuspendCheck(HSuspendCheck* instruc
__ LoadFromOffset(kLoadUnsignedHalfword,
TMP,
TR,
- Thread::ThreadFlagsOffset<kMips64WordSize>().Int32Value());
+ Thread::ThreadFlagsOffset<kMips64DoublewordSize>().Int32Value());
if (successor == nullptr) {
__ Bnezc(TMP, slow_path->GetEntryLabel());
__ Bind(slow_path->GetReturnLabel());
@@ -3014,7 +3017,7 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeInterface(HInvokeInterface* invo
invoke->GetImtIndex() % mirror::Class::kImtSize, kMips64PointerSize).Uint32Value();
Location receiver = invoke->GetLocations()->InAt(0);
uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
- Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize);
+ Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize);
// Set the hidden argument.
__ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<GpuRegister>(),
@@ -3190,7 +3193,7 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
T9,
callee_method.AsRegister<GpuRegister>(),
ArtMethod::EntryPointFromQuickCompiledCodeOffset(
- kMips64WordSize).Int32Value());
+ kMips64DoublewordSize).Int32Value());
// T9()
__ Jalr(T9);
__ Nop();
@@ -3228,7 +3231,7 @@ void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t
size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kMips64PointerSize).SizeValue();
uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
- Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize);
+ Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize);
// temp = object->GetClass();
__ LoadFromOffset(kLoadUnsignedWord, temp, receiver, class_offset);
@@ -3306,7 +3309,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
}
static int32_t GetExceptionTlsOffset() {
- return Thread::ExceptionOffset<kMips64WordSize>().Int32Value();
+ return Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value();
}
void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) {
@@ -3546,7 +3549,8 @@ void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction)
if (instruction->IsStringAlloc()) {
// String is allocated through StringFactory. Call NewEmptyString entry point.
GpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<GpuRegister>();
- MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize);
+ MemberOffset code_offset =
+ ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64DoublewordSize);
__ LoadFromOffset(kLoadDoubleword, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
__ LoadFromOffset(kLoadDoubleword, T9, temp, code_offset.Int32Value());
__ Jalr(T9);
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 08e56158b8..c836f837de 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -27,10 +27,6 @@
namespace art {
namespace mips64 {
-// Use a local definition to prevent copying mistakes.
-static constexpr size_t kMips64WordSize = kMips64PointerSize;
-
-
// InvokeDexCallingConvention registers
static constexpr GpuRegister kParameterCoreRegisters[] =
@@ -274,9 +270,9 @@ class CodeGeneratorMIPS64 : public CodeGenerator {
void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- size_t GetWordSize() const OVERRIDE { return kMips64WordSize; }
+ size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; }
- size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64WordSize; }
+ size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; }
uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
return assembler_.GetLabelLocation(GetLabelOf(block));
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 18d70daf47..da054baa1c 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2688,6 +2688,8 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) {
locations->SetInAt(0, Location::RequiresFpuRegister());
if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
DCHECK(add->InputAt(1)->IsEmittedAtUseSite());
+ } else if (add->InputAt(1)->IsConstant()) {
+ locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
locations->SetInAt(1, Location::Any());
}
@@ -2804,6 +2806,8 @@ void LocationsBuilderX86::VisitSub(HSub* sub) {
locations->SetInAt(0, Location::RequiresFpuRegister());
if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
DCHECK(sub->InputAt(1)->IsEmittedAtUseSite());
+ } else if (sub->InputAt(1)->IsConstant()) {
+ locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
locations->SetInAt(1, Location::Any());
}
@@ -2918,6 +2922,8 @@ void LocationsBuilderX86::VisitMul(HMul* mul) {
locations->SetInAt(0, Location::RequiresFpuRegister());
if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
DCHECK(mul->InputAt(1)->IsEmittedAtUseSite());
+ } else if (mul->InputAt(1)->IsConstant()) {
+ locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
locations->SetInAt(1, Location::Any());
}
@@ -3415,6 +3421,8 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) {
locations->SetInAt(0, Location::RequiresFpuRegister());
if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
DCHECK(div->InputAt(1)->IsEmittedAtUseSite());
+ } else if (div->InputAt(1)->IsConstant()) {
+ locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
locations->SetInAt(1, Location::Any());
}
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index ae15fcf381..9566c29adf 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -93,7 +93,7 @@ InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
DCHECK(induction_analysis != nullptr);
}
-void InductionVarRange::GetInductionRange(HInstruction* context,
+bool InductionVarRange::GetInductionRange(HInstruction* context,
HInstruction* instruction,
/*out*/Value* min_val,
/*out*/Value* max_val,
@@ -111,12 +111,9 @@ void InductionVarRange::GetInductionRange(HInstruction* context,
*min_val = GetVal(info, trip, in_body, /* is_min */ true);
*max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
*needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
- } else {
- // No loop to analyze.
- *min_val = Value();
- *max_val = Value();
- *needs_finite_test = false;
+ return true;
}
+ return false; // Nothing known
}
bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const {
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index 974b8fba06..3cb7b4bfd5 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -60,13 +60,13 @@ class InductionVarRange {
* Given a context denoted by the first instruction, returns a possibly conservative
* lower and upper bound on the instruction's value in the output parameters min_val
* and max_val, respectively. The need_finite_test flag denotes if an additional finite-test
- * is needed to protect the range evaluation inside its loop.
+ * is needed to protect the range evaluation inside its loop. Returns false on failure.
*/
- void GetInductionRange(HInstruction* context,
+ bool GetInductionRange(HInstruction* context,
HInstruction* instruction,
- /*out*/Value* min_val,
- /*out*/Value* max_val,
- /*out*/bool* needs_finite_test);
+ /*out*/ Value* min_val,
+ /*out*/ Value* max_val,
+ /*out*/ bool* needs_finite_test);
/** Refines the values with induction of next outer loop. Returns true on change. */
bool RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const;
@@ -79,8 +79,8 @@ class InductionVarRange {
*/
bool CanGenerateCode(HInstruction* context,
HInstruction* instruction,
- /*out*/bool* needs_finite_test,
- /*out*/bool* needs_taken_test);
+ /*out*/ bool* needs_finite_test,
+ /*out*/ bool* needs_taken_test);
/**
* Generates the actual code in the HIR for the lower and upper bound expressions on the
@@ -101,8 +101,8 @@ class InductionVarRange {
HInstruction* instruction,
HGraph* graph,
HBasicBlock* block,
- /*out*/HInstruction** lower,
- /*out*/HInstruction** upper);
+ /*out*/ HInstruction** lower,
+ /*out*/ HInstruction** upper);
/**
* Generates explicit taken-test for the loop in the given context. Code is generated in
@@ -113,7 +113,7 @@ class InductionVarRange {
void GenerateTakenTest(HInstruction* context,
HGraph* graph,
HBasicBlock* block,
- /*out*/HInstruction** taken_test);
+ /*out*/ HInstruction** taken_test);
private:
bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const;
@@ -168,17 +168,17 @@ class InductionVarRange {
HInstruction* instruction,
HGraph* graph,
HBasicBlock* block,
- /*out*/HInstruction** lower,
- /*out*/HInstruction** upper,
- /*out*/HInstruction** taken_test,
- /*out*/bool* needs_finite_test,
- /*out*/bool* needs_taken_test) const;
+ /*out*/ HInstruction** lower,
+ /*out*/ HInstruction** upper,
+ /*out*/ HInstruction** taken_test,
+ /*out*/ bool* needs_finite_test,
+ /*out*/ bool* needs_taken_test) const;
bool GenerateCode(HInductionVarAnalysis::InductionInfo* info,
HInductionVarAnalysis::InductionInfo* trip,
HGraph* graph,
HBasicBlock* block,
- /*out*/HInstruction** result,
+ /*out*/ HInstruction** result,
bool in_body,
bool is_min) const;
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index a839d2dee8..9b91b53813 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -392,8 +392,8 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction,
<< invoke_instruction->DebugName();
// This optimization only works under JIT for now.
DCHECK(Runtime::Current()->UseJit());
- if (graph_->GetInstructionSet() == kMips || graph_->GetInstructionSet() == kMips64) {
- // TODO: Support HClassTableGet for mips and mips64.
+ if (graph_->GetInstructionSet() == kMips64) {
+ // TODO: Support HClassTableGet for mips64.
return false;
}
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 7d3a7238dc..c1e38633fc 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -46,6 +46,10 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
bool TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
+ // `op` should be either HOr or HAnd.
+ // De Morgan's laws:
+ // ~a & ~b = ~(a | b) and ~a | ~b = ~(a & b)
+ bool TryDeMorganNegationFactoring(HBinaryOperation* op);
void VisitShift(HBinaryOperation* shift);
void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
@@ -164,6 +168,54 @@ bool InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop(HBinaryOperation
return true;
}
+bool InstructionSimplifierVisitor::TryDeMorganNegationFactoring(HBinaryOperation* op) {
+ DCHECK(op->IsAnd() || op->IsOr()) << op->DebugName();
+ Primitive::Type type = op->GetType();
+ HInstruction* left = op->GetLeft();
+ HInstruction* right = op->GetRight();
+
+ // We can apply De Morgan's laws if both inputs are Not's and are only used
+ // by `op`.
+ if (left->IsNot() &&
+ right->IsNot() &&
+ left->HasOnlyOneNonEnvironmentUse() &&
+ right->HasOnlyOneNonEnvironmentUse()) {
+ // Replace code looking like
+ // NOT nota, a
+ // NOT notb, b
+ // AND dst, nota, notb (respectively OR)
+ // with
+ // OR or, a, b (respectively AND)
+ // NOT dest, or
+ HInstruction* src_left = left->AsNot()->GetInput();
+ HInstruction* src_right = right->AsNot()->GetInput();
+ uint32_t dex_pc = op->GetDexPc();
+
+ // Remove the negations on the inputs.
+ left->ReplaceWith(src_left);
+ right->ReplaceWith(src_right);
+ left->GetBlock()->RemoveInstruction(left);
+ right->GetBlock()->RemoveInstruction(right);
+
+ // Replace the `HAnd` or `HOr`.
+ HBinaryOperation* hbin;
+ if (op->IsAnd()) {
+ hbin = new (GetGraph()->GetArena()) HOr(type, src_left, src_right, dex_pc);
+ } else {
+ hbin = new (GetGraph()->GetArena()) HAnd(type, src_left, src_right, dex_pc);
+ }
+ HNot* hnot = new (GetGraph()->GetArena()) HNot(type, hbin, dex_pc);
+
+ op->GetBlock()->InsertInstructionBefore(hbin, op);
+ op->GetBlock()->ReplaceAndRemoveInstructionWith(op, hnot);
+
+ RecordSimplification();
+ return true;
+ }
+
+ return false;
+}
+
void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
HConstant* input_cst = instruction->GetConstantRight();
@@ -813,7 +865,10 @@ void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
// src
instruction->ReplaceWith(instruction->GetLeft());
instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
}
+
+ TryDeMorganNegationFactoring(instruction);
}
void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
@@ -1127,6 +1182,8 @@ void InstructionSimplifierVisitor::VisitOr(HOr* instruction) {
return;
}
+ if (TryDeMorganNegationFactoring(instruction)) return;
+
TryReplaceWithRotate(instruction);
}
@@ -1249,6 +1306,26 @@ void InstructionSimplifierVisitor::VisitXor(HXor* instruction) {
return;
}
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+ if (left->IsNot() &&
+ right->IsNot() &&
+ left->HasOnlyOneNonEnvironmentUse() &&
+ right->HasOnlyOneNonEnvironmentUse()) {
+ // Replace code looking like
+ // NOT nota, a
+ // NOT notb, b
+ // XOR dst, nota, notb
+ // with
+ // XOR dst, a, b
+ instruction->ReplaceInput(left->AsNot()->GetInput(), 0);
+ instruction->ReplaceInput(right->AsNot()->GetInput(), 1);
+ left->GetBlock()->RemoveInstruction(left);
+ right->GetBlock()->RemoveInstruction(right);
+ RecordSimplification();
+ return;
+ }
+
TryReplaceWithRotate(instruction);
}
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 1376695a75..5dce83a69c 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -780,7 +780,6 @@ static void GenUnsafeGet(HInvoke* invoke,
Register offset = XRegisterFrom(offset_loc); // Long offset.
Location trg_loc = locations->Out();
Register trg = RegisterFrom(trg_loc, type);
- bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease();
if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case.
@@ -788,19 +787,11 @@ static void GenUnsafeGet(HInvoke* invoke,
Register temp = temps.AcquireW();
codegen->GenerateArrayLoadWithBakerReadBarrier(
invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
- if (is_volatile && !use_acquire_release) {
- __ Dmb(InnerShareable, BarrierReads);
- }
} else {
// Other cases.
MemOperand mem_op(base.X(), offset);
if (is_volatile) {
- if (use_acquire_release) {
- codegen->LoadAcquire(invoke, trg, mem_op, /* needs_null_check */ true);
- } else {
- codegen->Load(type, trg, mem_op);
- __ Dmb(InnerShareable, BarrierReads);
- }
+ codegen->LoadAcquire(invoke, trg, mem_op, /* needs_null_check */ true);
} else {
codegen->Load(type, trg, mem_op);
}
@@ -914,8 +905,6 @@ static void GenUnsafePut(LocationSummary* locations,
Register offset = XRegisterFrom(locations->InAt(2)); // Long offset.
Register value = RegisterFrom(locations->InAt(3), type);
Register source = value;
- bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease();
-
MemOperand mem_op(base.X(), offset);
{
@@ -932,15 +921,7 @@ static void GenUnsafePut(LocationSummary* locations,
}
if (is_volatile || is_ordered) {
- if (use_acquire_release) {
- codegen->StoreRelease(type, source, mem_op);
- } else {
- __ Dmb(InnerShareable, BarrierAll);
- codegen->Store(type, source, mem_op);
- if (is_volatile) {
- __ Dmb(InnerShareable, BarrierReads);
- }
- }
+ codegen->StoreRelease(type, source, mem_op);
} else {
codegen->Store(type, source, mem_op);
}
@@ -1037,7 +1018,6 @@ static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena,
}
static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM64* codegen) {
- bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease();
vixl::MacroAssembler* masm = codegen->GetAssembler()->vixl_masm_;
Register out = WRegisterFrom(locations->Out()); // Boolean result.
@@ -1078,43 +1058,20 @@ static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGenerat
// result = tmp_value != 0;
vixl::Label loop_head, exit_loop;
- if (use_acquire_release) {
- __ Bind(&loop_head);
- // TODO: When `type == Primitive::kPrimNot`, add a read barrier for
- // the reference stored in the object before attempting the CAS,
- // similar to the one in the art::Unsafe_compareAndSwapObject JNI
- // implementation.
- //
- // Note that this code is not (yet) used when read barriers are
- // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject).
- DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier));
- __ Ldaxr(tmp_value, MemOperand(tmp_ptr));
- __ Cmp(tmp_value, expected);
- __ B(&exit_loop, ne);
- __ Stlxr(tmp_32, value, MemOperand(tmp_ptr));
- __ Cbnz(tmp_32, &loop_head);
- } else {
- // Emit a `Dmb(InnerShareable, BarrierAll)` (DMB ISH) instruction
- // instead of a `Dmb(InnerShareable, BarrierWrites)` (DMB ISHST)
- // one, as the latter allows a preceding load to be delayed past
- // the STXR instruction below.
- __ Dmb(InnerShareable, BarrierAll);
- __ Bind(&loop_head);
- // TODO: When `type == Primitive::kPrimNot`, add a read barrier for
- // the reference stored in the object before attempting the CAS,
- // similar to the one in the art::Unsafe_compareAndSwapObject JNI
- // implementation.
- //
- // Note that this code is not (yet) used when read barriers are
- // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject).
- DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier));
- __ Ldxr(tmp_value, MemOperand(tmp_ptr));
- __ Cmp(tmp_value, expected);
- __ B(&exit_loop, ne);
- __ Stxr(tmp_32, value, MemOperand(tmp_ptr));
- __ Cbnz(tmp_32, &loop_head);
- __ Dmb(InnerShareable, BarrierAll);
- }
+ __ Bind(&loop_head);
+ // TODO: When `type == Primitive::kPrimNot`, add a read barrier for
+ // the reference stored in the object before attempting the CAS,
+ // similar to the one in the art::Unsafe_compareAndSwapObject JNI
+ // implementation.
+ //
+ // Note that this code is not (yet) used when read barriers are
+ // enabled (see IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject).
+ DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier));
+ __ Ldaxr(tmp_value, MemOperand(tmp_ptr));
+ __ Cmp(tmp_value, expected);
+ __ B(&exit_loop, ne);
+ __ Stlxr(tmp_32, value, MemOperand(tmp_ptr));
+ __ Cbnz(tmp_32, &loop_head);
__ Bind(&exit_loop);
__ Cset(out, eq);
@@ -1527,6 +1484,181 @@ void IntrinsicCodeGeneratorARM64::VisitLongSignum(HInvoke* invoke) {
GenSignum(invoke->GetLocations(), /* is_long */ true, GetVIXLAssembler());
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
+ DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
+
+ LocationSummary* const locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
+ DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(1)->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
+
+ LocationSummary* const locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+
+ locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(calling_convention.GetReturnLocation(invoke->GetType()));
+}
+
+static void GenFPToFPCall(HInvoke* invoke,
+ vixl::MacroAssembler* masm,
+ CodeGeneratorARM64* codegen,
+ QuickEntrypointEnum entry) {
+ __ Ldr(lr, MemOperand(tr, GetThreadOffset<kArm64WordSize>(entry).Int32Value()));
+ __ Blr(lr);
+ codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCos);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSin);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAcos);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAsin);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCbrt);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCosh);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExp);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExpm1);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog10);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSinh);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTan);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTanh);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathAtan2(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan2);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathHypot(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickHypot);
+}
+
+void IntrinsicLocationsBuilderARM64::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickNextAfter);
+}
+
// Unimplemented intrinsics.
#define UNIMPLEMENTED_INTRINSIC(Name) \
@@ -1542,24 +1674,6 @@ UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
-UNIMPLEMENTED_INTRINSIC(MathCos)
-UNIMPLEMENTED_INTRINSIC(MathSin)
-UNIMPLEMENTED_INTRINSIC(MathAcos)
-UNIMPLEMENTED_INTRINSIC(MathAsin)
-UNIMPLEMENTED_INTRINSIC(MathAtan)
-UNIMPLEMENTED_INTRINSIC(MathAtan2)
-UNIMPLEMENTED_INTRINSIC(MathCbrt)
-UNIMPLEMENTED_INTRINSIC(MathCosh)
-UNIMPLEMENTED_INTRINSIC(MathExp)
-UNIMPLEMENTED_INTRINSIC(MathExpm1)
-UNIMPLEMENTED_INTRINSIC(MathHypot)
-UNIMPLEMENTED_INTRINSIC(MathLog)
-UNIMPLEMENTED_INTRINSIC(MathLog10)
-UNIMPLEMENTED_INTRINSIC(MathNextAfter)
-UNIMPLEMENTED_INTRINSIC(MathSinh)
-UNIMPLEMENTED_INTRINSIC(MathTan)
-UNIMPLEMENTED_INTRINSIC(MathTanh)
-
UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index cba84fa3e3..f681d1fd56 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1429,8 +1429,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) {
__ LoadFromOffset(kLoadDoubleword,
TMP,
TR,
- QUICK_ENTRYPOINT_OFFSET(kMips64WordSize,
- pStringCompareTo).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pStringCompareTo).Int32Value());
__ Jalr(TMP);
__ Nop();
__ Bind(slow_path->GetExitLabel());
@@ -1583,7 +1582,7 @@ static void GenerateStringIndexOf(HInvoke* invoke,
__ LoadFromOffset(kLoadDoubleword,
TMP,
TR,
- QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pIndexOf).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pIndexOf).Int32Value());
__ Jalr(TMP);
__ Nop();
@@ -1659,7 +1658,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke
__ LoadFromOffset(kLoadDoubleword,
TMP,
TR,
- QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromBytes).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize,
+ pAllocStringFromBytes).Int32Value());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
__ Jalr(TMP);
__ Nop();
@@ -1685,7 +1685,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke
__ LoadFromOffset(kLoadDoubleword,
TMP,
TR,
- QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromChars).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize,
+ pAllocStringFromChars).Int32Value());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
__ Jalr(TMP);
__ Nop();
@@ -1716,7 +1717,8 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invok
__ LoadFromOffset(kLoadDoubleword,
TMP,
TR,
- QUICK_ENTRYPOINT_OFFSET(kMips64WordSize, pAllocStringFromString).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize,
+ pAllocStringFromString).Int32Value());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
__ Jalr(TMP);
__ Nop();
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index c4492c8f92..9a97f54d54 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -55,13 +55,13 @@ class ReferenceInfo : public ArenaObject<kArenaAllocMisc> {
is_singleton_and_not_returned_ = false;
return;
}
- if (use->IsPhi() || use->IsInvoke() ||
+ if (use->IsPhi() || use->IsSelect() || use->IsInvoke() ||
(use->IsInstanceFieldSet() && (reference_ == use->InputAt(1))) ||
(use->IsUnresolvedInstanceFieldSet() && (reference_ == use->InputAt(1))) ||
(use->IsStaticFieldSet() && (reference_ == use->InputAt(1))) ||
(use->IsUnresolvedStaticFieldSet() && (reference_ == use->InputAt(0))) ||
(use->IsArraySet() && (reference_ == use->InputAt(2)))) {
- // reference_ is merged to a phi, passed to a callee, or stored to heap.
+ // reference_ is merged to a phi/HSelect, passed to a callee, or stored to heap.
// reference_ isn't the only name that can refer to its value anymore.
is_singleton_ = false;
is_singleton_and_not_returned_ = false;
diff --git a/compiler/optimizing/optimizing_cfi_test_expected.inc b/compiler/optimizing/optimizing_cfi_test_expected.inc
index de857295c7..fc66823b04 100644
--- a/compiler/optimizing/optimizing_cfi_test_expected.inc
+++ b/compiler/optimizing/optimizing_cfi_test_expected.inc
@@ -198,8 +198,9 @@ static constexpr uint8_t expected_asm_kMips64[] = {
};
static constexpr uint8_t expected_cfi_kMips64[] = {
0x44, 0x0E, 0x28, 0x44, 0x9F, 0x02, 0x44, 0x91, 0x04, 0x44, 0x90, 0x06,
- 0x4C, 0x0E, 0x40, 0x44, 0x0A, 0x44, 0x0E, 0x28, 0x4C, 0xD0, 0x44, 0xD1,
- 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40,
+ 0x44, 0xB9, 0x08, 0x44, 0xB8, 0x0A, 0x44, 0x0E, 0x40, 0x44, 0x0A, 0x44,
+ 0x0E, 0x28, 0x44, 0xF8, 0x44, 0xF9, 0x44, 0xD0, 0x44, 0xD1, 0x44, 0xDF,
+ 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40,
};
// 0x00000000: daddiu r29, r29, -40
// 0x00000004: .cfi_def_cfa_offset: 40
@@ -210,7 +211,9 @@ static constexpr uint8_t expected_cfi_kMips64[] = {
// 0x0000000c: sd r16, +16(r29)
// 0x00000010: .cfi_offset: r16 at cfa-24
// 0x00000010: sdc1 f25, +8(r29)
+// 0x00000014: .cfi_offset: r57 at cfa-32
// 0x00000014: sdc1 f24, +0(r29)
+// 0x00000018: .cfi_offset: r56 at cfa-40
// 0x00000018: daddiu r29, r29, -24
// 0x0000001c: .cfi_def_cfa_offset: 64
// 0x0000001c: sd r4, +0(r29)
@@ -218,7 +221,9 @@ static constexpr uint8_t expected_cfi_kMips64[] = {
// 0x00000020: daddiu r29, r29, 24
// 0x00000024: .cfi_def_cfa_offset: 40
// 0x00000024: ldc1 f24, +0(r29)
+// 0x00000028: .cfi_restore: r56
// 0x00000028: ldc1 f25, +8(r29)
+// 0x0000002c: .cfi_restore: r57
// 0x0000002c: ld r16, +16(r29)
// 0x00000030: .cfi_restore: r16
// 0x00000030: ld r17, +24(r29)
@@ -427,9 +432,9 @@ static constexpr uint8_t expected_asm_kMips64_adjust_tail[] = {
};
static constexpr uint8_t expected_cfi_kMips64_adjust[] = {
0x44, 0x0E, 0x28, 0x44, 0x9F, 0x02, 0x44, 0x91, 0x04, 0x44, 0x90, 0x06,
- 0x4C, 0x0E, 0x40, 0x04, 0x14, 0x00, 0x02, 0x00, 0x0A, 0x44, 0x0E, 0x28,
- 0x4C, 0xD0, 0x44, 0xD1, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E,
- 0x40,
+ 0x44, 0xB9, 0x08, 0x44, 0xB8, 0x0A, 0x44, 0x0E, 0x40, 0x04, 0x14, 0x00,
+ 0x02, 0x00, 0x0A, 0x44, 0x0E, 0x28, 0x44, 0xF8, 0x44, 0xF9, 0x44, 0xD0,
+ 0x44, 0xD1, 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40,
};
// 0x00000000: daddiu r29, r29, -40
// 0x00000004: .cfi_def_cfa_offset: 40
@@ -440,7 +445,9 @@ static constexpr uint8_t expected_cfi_kMips64_adjust[] = {
// 0x0000000c: sd r16, +16(r29)
// 0x00000010: .cfi_offset: r16 at cfa-24
// 0x00000010: sdc1 f25, +8(r29)
+// 0x00000014: .cfi_offset: r57 at cfa-32
// 0x00000014: sdc1 f24, +0(r29)
+// 0x00000018: .cfi_offset: r56 at cfa-40
// 0x00000018: daddiu r29, r29, -24
// 0x0000001c: .cfi_def_cfa_offset: 64
// 0x0000001c: sd r4, +0(r29)
@@ -454,7 +461,9 @@ static constexpr uint8_t expected_cfi_kMips64_adjust[] = {
// 0x00020030: daddiu r29, r29, 24
// 0x00020034: .cfi_def_cfa_offset: 40
// 0x00020034: ldc1 f24, +0(r29)
+// 0x00020038: .cfi_restore: r56
// 0x00020038: ldc1 f25, +8(r29)
+// 0x0002003c: .cfi_restore: r57
// 0x0002003c: ld r16, +16(r29)
// 0x00020040: .cfi_restore: r16
// 0x00020040: ld r17, +24(r29)
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 7ed3c84f13..1dd35080a6 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -174,6 +174,38 @@ void SsaLivenessAnalysis::ComputeLiveness() {
ComputeLiveInAndLiveOutSets();
}
+static void RecursivelyProcessInputs(HInstruction* current,
+ HInstruction* actual_user,
+ BitVector* live_in) {
+ for (size_t i = 0, e = current->InputCount(); i < e; ++i) {
+ HInstruction* input = current->InputAt(i);
+ bool has_in_location = current->GetLocations()->InAt(i).IsValid();
+ bool has_out_location = input->GetLocations()->Out().IsValid();
+
+ if (has_in_location) {
+ DCHECK(has_out_location)
+ << "Instruction " << current->DebugName() << current->GetId()
+ << " expects an input value at index " << i << " but "
+ << input->DebugName() << input->GetId() << " does not produce one.";
+ DCHECK(input->HasSsaIndex());
+ // `input` generates a result used by `current`. Add use and update
+ // the live-in set.
+ input->GetLiveInterval()->AddUse(current, /* environment */ nullptr, i, actual_user);
+ live_in->SetBit(input->GetSsaIndex());
+ } else if (has_out_location) {
+ // `input` generates a result but it is not used by `current`.
+ } else {
+ // `input` is inlined into `current`. Walk over its inputs and record
+ // uses at `current`.
+ DCHECK(input->IsEmittedAtUseSite());
+ // Check that the inlined input is not a phi. Recursing on loop phis could
+ // lead to an infinite loop.
+ DCHECK(!input->IsPhi());
+ RecursivelyProcessInputs(input, actual_user, live_in);
+ }
+ }
+}
+
void SsaLivenessAnalysis::ComputeLiveRanges() {
// Do a post order visit, adding inputs of instructions live in the block where
// that instruction is defined, and killing instructions that are being visited.
@@ -261,35 +293,7 @@ void SsaLivenessAnalysis::ComputeLiveRanges() {
DCHECK(!current->HasEnvironmentUses());
}
} else {
- for (size_t i = 0, e = current->InputCount(); i < e; ++i) {
- HInstruction* input = current->InputAt(i);
- bool has_in_location = current->GetLocations()->InAt(i).IsValid();
- bool has_out_location = input->GetLocations()->Out().IsValid();
-
- if (has_in_location) {
- DCHECK(has_out_location);
- DCHECK(input->HasSsaIndex());
- // `Input` generates a result used by `current`. Add use and update
- // the live-in set.
- input->GetLiveInterval()->AddUse(current, /* environment */ nullptr, i);
- live_in->SetBit(input->GetSsaIndex());
- } else if (has_out_location) {
- // `Input` generates a result but it is not used by `current`.
- } else {
- // `Input` is inlined into `current`. Walk over its inputs and record
- // uses at `current`.
- DCHECK(input->IsEmittedAtUseSite());
- for (size_t i2 = 0, e2 = input->InputCount(); i2 < e2; ++i2) {
- HInstruction* inlined_input = input->InputAt(i2);
- DCHECK(inlined_input->HasSsaIndex()) << "Recursive inlining not allowed.";
- if (input->GetLocations()->InAt(i2).IsValid()) {
- live_in->SetBit(inlined_input->GetSsaIndex());
- inlined_input->GetLiveInterval()->AddUse(
- /* owner */ input, /* environment */ nullptr, i2, /* actual_user */ current);
- }
- }
- }
- }
+ RecursivelyProcessInputs(current, current, live_in);
}
}
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index f9ff2df8bb..ab480cafd5 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -300,10 +300,17 @@ void Mips64Assembler::Dshd(GpuRegister rd, GpuRegister rt) {
EmitRtd(0x1f, rt, rd, 0x5, 0x24);
}
-void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size_less_one) {
- DCHECK(0 <= pos && pos < 32) << pos;
- DCHECK(0 <= size_less_one && size_less_one < 32) << size_less_one;
- EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size_less_one), pos, 3);
+void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
+ CHECK(IsUint<5>(pos)) << pos;
+ CHECK(IsUint<5>(size - 1)) << size;
+ EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
+}
+
+void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
+ CHECK(IsUint<5>(pos - 32)) << pos;
+ CHECK(IsUint<5>(size - 1)) << size;
+ CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
+ EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
}
void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
@@ -311,22 +318,22 @@ void Mips64Assembler::Wsbh(GpuRegister rd, GpuRegister rt) {
}
void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
- DCHECK((-256 <= imm9) && (imm9 < 256));
+ CHECK(IsInt<9>(imm9));
EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
}
void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
- DCHECK((-256 <= imm9) && (imm9 < 256));
+ CHECK(IsInt<9>(imm9));
EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
}
void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
- DCHECK((-256 <= imm9) && (imm9 < 256));
+ CHECK(IsInt<9>(imm9));
EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
}
void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
- DCHECK((-256 <= imm9) && (imm9 < 256));
+ CHECK(IsInt<9>(imm9));
EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
}
@@ -967,10 +974,18 @@ void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
}
+void Mips64Assembler::Mfhc1(GpuRegister rt, FpuRegister fs) {
+ EmitFR(0x11, 0x03, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
+}
+
void Mips64Assembler::Mtc1(GpuRegister rt, FpuRegister fs) {
EmitFR(0x11, 0x04, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
}
+void Mips64Assembler::Mthc1(GpuRegister rt, FpuRegister fs) {
+ EmitFR(0x11, 0x07, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
+}
+
void Mips64Assembler::Dmfc1(GpuRegister rt, FpuRegister fs) {
EmitFR(0x11, 0x01, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
}
@@ -1787,11 +1802,13 @@ void Mips64Assembler::Bc1nez(FpuRegister ft, Mips64Label* label) {
void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base,
int32_t offset) {
- if (!IsInt<16>(offset)) {
- LoadConst32(AT, offset);
+ if (!IsInt<16>(offset) ||
+ (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
+ !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
+ LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Daddu(AT, AT, base);
base = AT;
- offset = 0;
+ offset &= (kMips64DoublewordSize - 1);
}
switch (type) {
@@ -1808,32 +1825,51 @@ void Mips64Assembler::LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuR
Lhu(reg, base, offset);
break;
case kLoadWord:
+ CHECK_ALIGNED(offset, kMips64WordSize);
Lw(reg, base, offset);
break;
case kLoadUnsignedWord:
+ CHECK_ALIGNED(offset, kMips64WordSize);
Lwu(reg, base, offset);
break;
case kLoadDoubleword:
- Ld(reg, base, offset);
+ if (!IsAligned<kMips64DoublewordSize>(offset)) {
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ Lwu(reg, base, offset);
+ Lwu(TMP2, base, offset + kMips64WordSize);
+ Dinsu(reg, TMP2, 32, 32);
+ } else {
+ Ld(reg, base, offset);
+ }
break;
}
}
void Mips64Assembler::LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base,
int32_t offset) {
- if (!IsInt<16>(offset)) {
- LoadConst32(AT, offset);
+ if (!IsInt<16>(offset) ||
+ (type == kLoadDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
+ !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
+ LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Daddu(AT, AT, base);
base = AT;
- offset = 0;
+ offset &= (kMips64DoublewordSize - 1);
}
switch (type) {
case kLoadWord:
+ CHECK_ALIGNED(offset, kMips64WordSize);
Lwc1(reg, base, offset);
break;
case kLoadDoubleword:
- Ldc1(reg, base, offset);
+ if (!IsAligned<kMips64DoublewordSize>(offset)) {
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ Lwc1(reg, base, offset);
+ Lw(TMP2, base, offset + kMips64WordSize);
+ Mthc1(TMP2, reg);
+ } else {
+ Ldc1(reg, base, offset);
+ }
break;
default:
LOG(FATAL) << "UNREACHABLE";
@@ -1869,11 +1905,13 @@ void Mips64Assembler::EmitLoad(ManagedRegister m_dst, GpuRegister src_register,
void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base,
int32_t offset) {
- if (!IsInt<16>(offset)) {
- LoadConst32(AT, offset);
+ if (!IsInt<16>(offset) ||
+ (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
+ !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
+ LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Daddu(AT, AT, base);
base = AT;
- offset = 0;
+ offset &= (kMips64DoublewordSize - 1);
}
switch (type) {
@@ -1884,10 +1922,18 @@ void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuR
Sh(reg, base, offset);
break;
case kStoreWord:
+ CHECK_ALIGNED(offset, kMips64WordSize);
Sw(reg, base, offset);
break;
case kStoreDoubleword:
- Sd(reg, base, offset);
+ if (!IsAligned<kMips64DoublewordSize>(offset)) {
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ Sw(reg, base, offset);
+ Dsrl32(TMP2, reg, 0);
+ Sw(TMP2, base, offset + kMips64WordSize);
+ } else {
+ Sd(reg, base, offset);
+ }
break;
default:
LOG(FATAL) << "UNREACHABLE";
@@ -1896,19 +1942,29 @@ void Mips64Assembler::StoreToOffset(StoreOperandType type, GpuRegister reg, GpuR
void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base,
int32_t offset) {
- if (!IsInt<16>(offset)) {
- LoadConst32(AT, offset);
+ if (!IsInt<16>(offset) ||
+ (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) &&
+ !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) {
+ LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1));
Daddu(AT, AT, base);
base = AT;
- offset = 0;
+ offset &= (kMips64DoublewordSize - 1);
}
switch (type) {
case kStoreWord:
+ CHECK_ALIGNED(offset, kMips64WordSize);
Swc1(reg, base, offset);
break;
case kStoreDoubleword:
- Sdc1(reg, base, offset);
+ if (!IsAligned<kMips64DoublewordSize>(offset)) {
+ CHECK_ALIGNED(offset, kMips64WordSize);
+ Mfhc1(TMP2, reg);
+ Swc1(reg, base, offset);
+ Sw(TMP2, base, offset + kMips64WordSize);
+ } else {
+ Sdc1(reg, base, offset);
+ }
break;
default:
LOG(FATAL) << "UNREACHABLE";
@@ -2053,7 +2109,7 @@ void Mips64Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
}
-void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
+void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
FrameOffset fr_offs,
ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
@@ -2062,7 +2118,7 @@ void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSiz
StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
}
-void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs) {
+void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs) {
StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
}
@@ -2080,7 +2136,7 @@ void Mips64Assembler::Load(ManagedRegister mdest, FrameOffset src, size_t size)
}
void Mips64Assembler::LoadFromThread64(ManagedRegister mdest,
- ThreadOffset<kMipsDoublewordSize> src,
+ ThreadOffset<kMips64DoublewordSize> src,
size_t size) {
return EmitLoad(mdest, S1, src.Int32Value(), size);
}
@@ -2102,7 +2158,7 @@ void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, Membe
// Negate the 32-bit ref
Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
// And constrain it to 32 bits (zero-extend into bits 32 through 63) as on Arm64 and x86/64
- Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 31);
+ Dext(dest.AsGpuRegister(), dest.AsGpuRegister(), 0, 32);
}
}
@@ -2115,7 +2171,7 @@ void Mips64Assembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
}
void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest,
- ThreadOffset<kMipsDoublewordSize> offs) {
+ ThreadOffset<kMips64DoublewordSize> offs) {
Mips64ManagedRegister dest = mdest.AsMips64();
CHECK(dest.IsGpuRegister());
LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
@@ -2160,7 +2216,7 @@ void Mips64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
}
void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
- ThreadOffset<kMipsDoublewordSize> thr_offs,
+ ThreadOffset<kMips64DoublewordSize> thr_offs,
ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
CHECK(scratch.IsGpuRegister()) << scratch;
@@ -2168,7 +2224,7 @@ void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
}
-void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs,
+void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs,
FrameOffset fr_offs,
ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
@@ -2372,7 +2428,7 @@ void Mips64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscr
// TODO: place reference map on call
}
-void Mips64Assembler::CallFromThread64(ThreadOffset<kMipsDoublewordSize> offset ATTRIBUTE_UNUSED,
+void Mips64Assembler::CallFromThread64(ThreadOffset<kMips64DoublewordSize> offset ATTRIBUTE_UNUSED,
ManagedRegister mscratch ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
}
@@ -2392,7 +2448,7 @@ void Mips64Assembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjus
LoadFromOffset(kLoadDoubleword,
scratch.AsGpuRegister(),
S1,
- Thread::ExceptionOffset<kMipsDoublewordSize>().Int32Value());
+ Thread::ExceptionOffset<kMips64DoublewordSize>().Int32Value());
Bnezc(scratch.AsGpuRegister(), exception_blocks_.back().Entry());
}
@@ -2409,7 +2465,7 @@ void Mips64Assembler::EmitExceptionPoll(Mips64ExceptionSlowPath* exception) {
LoadFromOffset(kLoadDoubleword,
T9,
S1,
- QUICK_ENTRYPOINT_OFFSET(kMipsDoublewordSize, pDeliverException).Int32Value());
+ QUICK_ENTRYPOINT_OFFSET(kMips64DoublewordSize, pDeliverException).Int32Value());
Jr(T9);
Nop();
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 3262640ce7..71f5e00166 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -31,7 +31,8 @@
namespace art {
namespace mips64 {
-static constexpr size_t kMipsDoublewordSize = 8;
+static constexpr size_t kMips64WordSize = 4;
+static constexpr size_t kMips64DoublewordSize = 8;
enum LoadOperandType {
kLoadSignedByte,
@@ -151,7 +152,8 @@ class Mips64Assembler FINAL : public Assembler {
void Seh(GpuRegister rd, GpuRegister rt);
void Dsbh(GpuRegister rd, GpuRegister rt);
void Dshd(GpuRegister rd, GpuRegister rt);
- void Dext(GpuRegister rs, GpuRegister rt, int pos, int size_less_one); // MIPS64
+ void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64
+ void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
void Wsbh(GpuRegister rd, GpuRegister rt);
void Sc(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
@@ -301,7 +303,9 @@ class Mips64Assembler FINAL : public Assembler {
void Cvtdl(FpuRegister fd, FpuRegister fs);
void Mfc1(GpuRegister rt, FpuRegister fs);
+ void Mfhc1(GpuRegister rt, FpuRegister fs);
void Mtc1(GpuRegister rt, FpuRegister fs);
+ void Mthc1(GpuRegister rt, FpuRegister fs);
void Dmfc1(GpuRegister rt, FpuRegister fs); // MIPS64
void Dmtc1(GpuRegister rt, FpuRegister fs); // MIPS64
void Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
@@ -378,10 +382,10 @@ class Mips64Assembler FINAL : public Assembler {
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
- void StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs, FrameOffset fr_offs,
+ void StoreStackOffsetToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs, FrameOffset fr_offs,
ManagedRegister mscratch) OVERRIDE;
- void StoreStackPointerToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs) OVERRIDE;
+ void StoreStackPointerToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
ManagedRegister mscratch) OVERRIDE;
@@ -390,7 +394,7 @@ class Mips64Assembler FINAL : public Assembler {
void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
void LoadFromThread64(ManagedRegister mdest,
- ThreadOffset<kMipsDoublewordSize> src,
+ ThreadOffset<kMips64DoublewordSize> src,
size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -401,15 +405,15 @@ class Mips64Assembler FINAL : public Assembler {
void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
void LoadRawPtrFromThread64(ManagedRegister mdest,
- ThreadOffset<kMipsDoublewordSize> offs) OVERRIDE;
+ ThreadOffset<kMips64DoublewordSize> offs) OVERRIDE;
// Copying routines.
void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
- void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<kMipsDoublewordSize> thr_offs,
+ void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<kMips64DoublewordSize> thr_offs,
ManagedRegister mscratch) OVERRIDE;
- void CopyRawPtrToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs, FrameOffset fr_offs,
+ void CopyRawPtrToThread64(ThreadOffset<kMips64DoublewordSize> thr_offs, FrameOffset fr_offs,
ManagedRegister mscratch) OVERRIDE;
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
@@ -466,7 +470,7 @@ class Mips64Assembler FINAL : public Assembler {
// Call to address held at [base+offset].
void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
- void CallFromThread64(ThreadOffset<kMipsDoublewordSize> offset,
+ void CallFromThread64(ThreadOffset<kMips64DoublewordSize> offset,
ManagedRegister mscratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index 7d79be2731..b758d64c1e 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -543,6 +543,30 @@ TEST_F(AssemblerMIPS64Test, TruncLD) {
DriverStr(RepeatFF(&mips64::Mips64Assembler::TruncLD, "trunc.l.d ${reg1}, ${reg2}"), "trunc.l.d");
}
+TEST_F(AssemblerMIPS64Test, Mfc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Mfc1, "mfc1 ${reg1}, ${reg2}"), "Mfc1");
+}
+
+TEST_F(AssemblerMIPS64Test, Mfhc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Mfhc1, "mfhc1 ${reg1}, ${reg2}"), "Mfhc1");
+}
+
+TEST_F(AssemblerMIPS64Test, Mtc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Mtc1, "mtc1 ${reg1}, ${reg2}"), "Mtc1");
+}
+
+TEST_F(AssemblerMIPS64Test, Mthc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Mthc1, "mthc1 ${reg1}, ${reg2}"), "Mthc1");
+}
+
+TEST_F(AssemblerMIPS64Test, Dmfc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Dmfc1, "dmfc1 ${reg1}, ${reg2}"), "Dmfc1");
+}
+
+TEST_F(AssemblerMIPS64Test, Dmtc1) {
+ DriverStr(RepeatRF(&mips64::Mips64Assembler::Dmtc1, "dmtc1 ${reg1}, ${reg2}"), "Dmtc1");
+}
+
////////////////
// CALL / JMP //
////////////////
@@ -827,6 +851,44 @@ TEST_F(AssemblerMIPS64Test, Dshd) {
DriverStr(RepeatRR(&mips64::Mips64Assembler::Dshd, "dshd ${reg1}, ${reg2}"), "dshd");
}
+TEST_F(AssemblerMIPS64Test, Dext) {
+ std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters();
+ std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters();
+ WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16);
+ std::ostringstream expected;
+ for (mips64::GpuRegister* reg1 : reg1_registers) {
+ for (mips64::GpuRegister* reg2 : reg2_registers) {
+ for (int32_t pos = 0; pos < 32; pos++) {
+ for (int32_t size = 1; size <= 32; size++) {
+ __ Dext(*reg1, *reg2, pos, size);
+ expected << "dext $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+ }
+ }
+ }
+ }
+
+ DriverStr(expected.str(), "Dext");
+}
+
+TEST_F(AssemblerMIPS64Test, Dinsu) {
+ std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters();
+ std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters();
+ WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16);
+ std::ostringstream expected;
+ for (mips64::GpuRegister* reg1 : reg1_registers) {
+ for (mips64::GpuRegister* reg2 : reg2_registers) {
+ for (int32_t pos = 32; pos < 64; pos++) {
+ for (int32_t size = 1; pos + size <= 64; size++) {
+ __ Dinsu(*reg1, *reg2, pos, size);
+ expected << "dinsu $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+ }
+ }
+ }
+ }
+
+ DriverStr(expected.str(), "Dinsu");
+}
+
TEST_F(AssemblerMIPS64Test, Wsbh) {
DriverStr(RepeatRR(&mips64::Mips64Assembler::Wsbh, "wsbh ${reg1}, ${reg2}"), "wsbh");
}
@@ -942,4 +1004,638 @@ TEST_F(AssemblerMIPS64Test, Dclo) {
DriverStr(RepeatRR(&mips64::Mips64Assembler::Dclo, "dclo ${reg1}, ${reg2}"), "dclo");
}
+TEST_F(AssemblerMIPS64Test, LoadFromOffset) {
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 1);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x7FFF);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x8001);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadSignedByte, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 1);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x7FFF);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x8001);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadUnsignedByte, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 2);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x7FFE);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x8002);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadSignedHalfword, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 2);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x7FFE);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x8002);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadUnsignedHalfword, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 4);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x7FFC);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x8004);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadWord, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 4);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x7FFC);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x8004);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadUnsignedWord, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A0, 0);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 4);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 256);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 1000);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x7FFC);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x8000);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x8004);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x10000);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0x12345678);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, -256);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, -32768);
+ __ LoadFromOffset(mips64::kLoadDoubleword, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ const char* expected =
+ "lb $a0, 0($a0)\n"
+ "lb $a0, 0($a1)\n"
+ "lb $a0, 1($a1)\n"
+ "lb $a0, 256($a1)\n"
+ "lb $a0, 1000($a1)\n"
+ "lb $a0, 0x7FFF($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lb $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lb $a0, 1($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lb $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lb $a0, 0($at)\n"
+ "lb $a0, -256($a1)\n"
+ "lb $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lb $a0, 0($at)\n"
+
+ "lbu $a0, 0($a0)\n"
+ "lbu $a0, 0($a1)\n"
+ "lbu $a0, 1($a1)\n"
+ "lbu $a0, 256($a1)\n"
+ "lbu $a0, 1000($a1)\n"
+ "lbu $a0, 0x7FFF($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lbu $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lbu $a0, 1($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lbu $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lbu $a0, 0($at)\n"
+ "lbu $a0, -256($a1)\n"
+ "lbu $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lbu $a0, 0($at)\n"
+
+ "lh $a0, 0($a0)\n"
+ "lh $a0, 0($a1)\n"
+ "lh $a0, 2($a1)\n"
+ "lh $a0, 256($a1)\n"
+ "lh $a0, 1000($a1)\n"
+ "lh $a0, 0x7FFE($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lh $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lh $a0, 2($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lh $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lh $a0, 0($at)\n"
+ "lh $a0, -256($a1)\n"
+ "lh $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lh $a0, 0($at)\n"
+
+ "lhu $a0, 0($a0)\n"
+ "lhu $a0, 0($a1)\n"
+ "lhu $a0, 2($a1)\n"
+ "lhu $a0, 256($a1)\n"
+ "lhu $a0, 1000($a1)\n"
+ "lhu $a0, 0x7FFE($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lhu $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lhu $a0, 2($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lhu $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lhu $a0, 0($at)\n"
+ "lhu $a0, -256($a1)\n"
+ "lhu $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lhu $a0, 0($at)\n"
+
+ "lw $a0, 0($a0)\n"
+ "lw $a0, 0($a1)\n"
+ "lw $a0, 4($a1)\n"
+ "lw $a0, 256($a1)\n"
+ "lw $a0, 1000($a1)\n"
+ "lw $a0, 0x7FFC($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lw $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lw $a0, 4($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lw $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lw $a0, 0($at)\n"
+ "lw $a0, -256($a1)\n"
+ "lw $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lw $a0, 0($at)\n"
+
+ "lwu $a0, 0($a0)\n"
+ "lwu $a0, 0($a1)\n"
+ "lwu $a0, 4($a1)\n"
+ "lwu $a0, 256($a1)\n"
+ "lwu $a0, 1000($a1)\n"
+ "lwu $a0, 0x7FFC($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 4($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 0($at)\n"
+ "lwu $a0, -256($a1)\n"
+ "lwu $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 0($at)\n"
+
+ "ld $a0, 0($a0)\n"
+ "ld $a0, 0($a1)\n"
+ "lwu $a0, 4($a1)\n"
+ "lwu $t3, 8($a1)\n"
+ "dins $a0, $t3, 32, 32\n"
+ "ld $a0, 256($a1)\n"
+ "ld $a0, 1000($a1)\n"
+ "ori $at, $zero, 0x7FF8\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 4($at)\n"
+ "lwu $t3, 8($at)\n"
+ "dins $a0, $t3, 32, 32\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "ld $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "lwu $a0, 4($at)\n"
+ "lwu $t3, 8($at)\n"
+ "dins $a0, $t3, 32, 32\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "ld $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "ld $a0, 0($at)\n"
+ "ld $a0, -256($a1)\n"
+ "ld $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "ld $a0, 0($at)\n";
+ DriverStr(expected, "LoadFromOffset");
+}
+
+TEST_F(AssemblerMIPS64Test, LoadFpuFromOffset) {
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 4);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 256);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x7FFC);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x8000);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x8004);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x10000);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0x12345678);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, -256);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, -32768);
+ __ LoadFpuFromOffset(mips64::kLoadWord, mips64::F0, mips64::A0, 0xABCDEF00);
+
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 4);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 256);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x7FFC);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x8000);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x8004);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x10000);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0x12345678);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, -256);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, -32768);
+ __ LoadFpuFromOffset(mips64::kLoadDoubleword, mips64::F0, mips64::A0, 0xABCDEF00);
+
+ const char* expected =
+ "lwc1 $f0, 0($a0)\n"
+ "lwc1 $f0, 4($a0)\n"
+ "lwc1 $f0, 256($a0)\n"
+ "lwc1 $f0, 0x7FFC($a0)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 4($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 0($at)\n"
+ "lwc1 $f0, -256($a0)\n"
+ "lwc1 $f0, -32768($a0)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 0($at)\n"
+
+ "ldc1 $f0, 0($a0)\n"
+ "lwc1 $f0, 4($a0)\n"
+ "lw $t3, 8($a0)\n"
+ "mthc1 $t3, $f0\n"
+ "ldc1 $f0, 256($a0)\n"
+ "ori $at, $zero, 0x7FF8\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 4($at)\n"
+ "lw $t3, 8($at)\n"
+ "mthc1 $t3, $f0\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "ldc1 $f0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "lwc1 $f0, 4($at)\n"
+ "lw $t3, 8($at)\n"
+ "mthc1 $t3, $f0\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a0\n"
+ "ldc1 $f0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a0\n"
+ "ldc1 $f0, 0($at)\n"
+ "ldc1 $f0, -256($a0)\n"
+ "ldc1 $f0, -32768($a0)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a0\n"
+ "ldc1 $f0, 0($at)\n";
+ DriverStr(expected, "LoadFpuFromOffset");
+}
+
+TEST_F(AssemblerMIPS64Test, StoreToOffset) {
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A0, 0);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 1);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 256);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 1000);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x7FFF);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x8000);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x8001);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x10000);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0x12345678);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, -256);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, -32768);
+ __ StoreToOffset(mips64::kStoreByte, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A0, 0);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 2);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 256);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 1000);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x7FFE);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x8000);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x8002);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x10000);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0x12345678);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, -256);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, -32768);
+ __ StoreToOffset(mips64::kStoreHalfword, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A0, 0);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 4);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 256);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 1000);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x7FFC);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x8000);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x8004);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x10000);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0x12345678);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, -256);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, -32768);
+ __ StoreToOffset(mips64::kStoreWord, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A0, 0);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 4);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 256);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 1000);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x7FFC);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x8000);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x8004);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x10000);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0x12345678);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, -256);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, -32768);
+ __ StoreToOffset(mips64::kStoreDoubleword, mips64::A0, mips64::A1, 0xABCDEF00);
+
+ const char* expected =
+ "sb $a0, 0($a0)\n"
+ "sb $a0, 0($a1)\n"
+ "sb $a0, 1($a1)\n"
+ "sb $a0, 256($a1)\n"
+ "sb $a0, 1000($a1)\n"
+ "sb $a0, 0x7FFF($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sb $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sb $a0, 1($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "sb $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "sb $a0, 0($at)\n"
+ "sb $a0, -256($a1)\n"
+ "sb $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "sb $a0, 0($at)\n"
+
+ "sh $a0, 0($a0)\n"
+ "sh $a0, 0($a1)\n"
+ "sh $a0, 2($a1)\n"
+ "sh $a0, 256($a1)\n"
+ "sh $a0, 1000($a1)\n"
+ "sh $a0, 0x7FFE($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sh $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sh $a0, 2($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "sh $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "sh $a0, 0($at)\n"
+ "sh $a0, -256($a1)\n"
+ "sh $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "sh $a0, 0($at)\n"
+
+ "sw $a0, 0($a0)\n"
+ "sw $a0, 0($a1)\n"
+ "sw $a0, 4($a1)\n"
+ "sw $a0, 256($a1)\n"
+ "sw $a0, 1000($a1)\n"
+ "sw $a0, 0x7FFC($a1)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 4($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 0($at)\n"
+ "sw $a0, -256($a1)\n"
+ "sw $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 0($at)\n"
+
+ "sd $a0, 0($a0)\n"
+ "sd $a0, 0($a1)\n"
+ "sw $a0, 4($a1)\n"
+ "dsrl32 $t3, $a0, 0\n"
+ "sw $t3, 8($a1)\n"
+ "sd $a0, 256($a1)\n"
+ "sd $a0, 1000($a1)\n"
+ "ori $at, $zero, 0x7FF8\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 4($at)\n"
+ "dsrl32 $t3, $a0, 0\n"
+ "sw $t3, 8($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sd $a0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a1\n"
+ "sw $a0, 4($at)\n"
+ "dsrl32 $t3, $a0, 0\n"
+ "sw $t3, 8($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a1\n"
+ "sd $a0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a1\n"
+ "sd $a0, 0($at)\n"
+ "sd $a0, -256($a1)\n"
+ "sd $a0, -32768($a1)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a1\n"
+ "sd $a0, 0($at)\n";
+ DriverStr(expected, "StoreToOffset");
+}
+
+TEST_F(AssemblerMIPS64Test, StoreFpuToOffset) {
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 4);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 256);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x7FFC);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x8000);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x8004);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x10000);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0x12345678);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, -256);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, -32768);
+ __ StoreFpuToOffset(mips64::kStoreWord, mips64::F0, mips64::A0, 0xABCDEF00);
+
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 4);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 256);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x7FFC);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x8000);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x8004);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x10000);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0x12345678);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, -256);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, -32768);
+ __ StoreFpuToOffset(mips64::kStoreDoubleword, mips64::F0, mips64::A0, 0xABCDEF00);
+
+ const char* expected =
+ "swc1 $f0, 0($a0)\n"
+ "swc1 $f0, 4($a0)\n"
+ "swc1 $f0, 256($a0)\n"
+ "swc1 $f0, 0x7FFC($a0)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "swc1 $f0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "swc1 $f0, 4($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a0\n"
+ "swc1 $f0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a0\n"
+ "swc1 $f0, 0($at)\n"
+ "swc1 $f0, -256($a0)\n"
+ "swc1 $f0, -32768($a0)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a0\n"
+ "swc1 $f0, 0($at)\n"
+
+ "sdc1 $f0, 0($a0)\n"
+ "mfhc1 $t3, $f0\n"
+ "swc1 $f0, 4($a0)\n"
+ "sw $t3, 8($a0)\n"
+ "sdc1 $f0, 256($a0)\n"
+ "ori $at, $zero, 0x7FF8\n"
+ "daddu $at, $at, $a0\n"
+ "mfhc1 $t3, $f0\n"
+ "swc1 $f0, 4($at)\n"
+ "sw $t3, 8($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "sdc1 $f0, 0($at)\n"
+ "ori $at, $zero, 0x8000\n"
+ "daddu $at, $at, $a0\n"
+ "mfhc1 $t3, $f0\n"
+ "swc1 $f0, 4($at)\n"
+ "sw $t3, 8($at)\n"
+ "lui $at, 1\n"
+ "daddu $at, $at, $a0\n"
+ "sdc1 $f0, 0($at)\n"
+ "lui $at, 0x1234\n"
+ "ori $at, 0x5678\n"
+ "daddu $at, $at, $a0\n"
+ "sdc1 $f0, 0($at)\n"
+ "sdc1 $f0, -256($a0)\n"
+ "sdc1 $f0, -32768($a0)\n"
+ "lui $at, 0xABCD\n"
+ "ori $at, 0xEF00\n"
+ "daddu $at, $at, $a0\n"
+ "sdc1 $f0, 0($at)\n";
+ DriverStr(expected, "StoreFpuToOffset");
+}
+
+#undef __
+
} // namespace art