diff options
Diffstat (limited to 'compiler')
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(¤t_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(¤t_abbrev_, name); + EncodeUnsignedLeb128(¤t_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(¤t_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(¤t_abbrev_, name); - EncodeUnsignedLeb128(¤t_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 |