diff options
Diffstat (limited to 'compiler/utils')
| -rw-r--r-- | compiler/utils/arm/assembler_arm.h | 2 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 20 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 8 | ||||
| -rw-r--r-- | compiler/utils/arm64/assembler_arm64.h | 2 | ||||
| -rw-r--r-- | compiler/utils/assembler.cc | 24 | ||||
| -rw-r--r-- | compiler/utils/assembler.h | 4 | ||||
| -rw-r--r-- | compiler/utils/assembler_thumb_test.cc | 6 | ||||
| -rw-r--r-- | compiler/utils/dedupe_set.h | 2 | ||||
| -rw-r--r-- | compiler/utils/dex_cache_arrays_layout.h | 2 | ||||
| -rw-r--r-- | compiler/utils/managed_register.h | 2 | ||||
| -rw-r--r-- | compiler/utils/mips/assembler_mips.cc | 48 | ||||
| -rw-r--r-- | compiler/utils/mips/assembler_mips.h | 17 | ||||
| -rw-r--r-- | compiler/utils/mips64/assembler_mips64.h | 2 | ||||
| -rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 145 | ||||
| -rw-r--r-- | compiler/utils/x86/assembler_x86.h | 40 | ||||
| -rw-r--r-- | compiler/utils/x86/assembler_x86_test.cc | 86 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 168 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.h | 45 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64_test.cc | 151 |
19 files changed, 720 insertions, 54 deletions
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 5d85d11054..ef60fefe4d 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -888,7 +888,7 @@ class ArmAssembler : public Assembler { // Slowpath entered when Thread::Current()->_exception is non-null class ArmExceptionSlowPath FINAL : public SlowPath { public: - explicit ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust) + ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust) : scratch_(scratch), stack_adjust_(stack_adjust) { } void Emit(Assembler *sp_asm) OVERRIDE; diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index b499dddb0c..4e918e9574 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -3299,17 +3299,17 @@ void Thumb2Assembler::StoreToOffset(StoreOperandType type, Register tmp_reg = kNoRegister; if (!Address::CanHoldStoreOffsetThumb(type, offset)) { CHECK_NE(base, IP); - if (reg != IP && - (type != kStoreWordPair || reg + 1 != IP)) { + if ((reg != IP) && + ((type != kStoreWordPair) || (reg + 1 != IP))) { tmp_reg = IP; } else { // Be careful not to use IP twice (for `reg` (or `reg` + 1 in - // the case of a word-pair store)) and to build the Address - // object used by the store instruction(s) below). Instead, - // save R5 on the stack (or R6 if R5 is not available), use it - // as secondary temporary register, and restore it after the - // store instruction has been emitted. - tmp_reg = base != R5 ? R5 : R6; + // the case of a word-pair store) and `base`) to build the + // Address object used by the store instruction(s) below. + // Instead, save R5 on the stack (or R6 if R5 is already used by + // `base`), use it as secondary temporary register, and restore + // it after the store instruction has been emitted. + tmp_reg = (base != R5) ? R5 : R6; Push(tmp_reg); if (base == SP) { offset += kRegisterSize; @@ -3338,8 +3338,8 @@ void Thumb2Assembler::StoreToOffset(StoreOperandType type, LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } - if (tmp_reg != kNoRegister && tmp_reg != IP) { - DCHECK(tmp_reg == R5 || tmp_reg == R6); + if ((tmp_reg != kNoRegister) && (tmp_reg != IP)) { + CHECK((tmp_reg == R5) || (tmp_reg == R6)); Pop(tmp_reg); } } diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 004853f224..84f5cb16fb 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -1011,4 +1011,12 @@ TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiBDueToAlignmentOnSecondPass) __ GetAdjustedPosition(label.Position())); } +TEST_F(AssemblerThumb2Test, Clz) { + __ clz(arm::R0, arm::R1); + + const char* expected = "clz r0, r1\n"; + + DriverStr(expected, "clz"); +} + } // namespace art diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h index 05882a30b0..8e85fe96ab 100644 --- a/compiler/utils/arm64/assembler_arm64.h +++ b/compiler/utils/arm64/assembler_arm64.h @@ -254,7 +254,7 @@ class Arm64Assembler FINAL : public Assembler { class Arm64Exception { private: - explicit Arm64Exception(Arm64ManagedRegister scratch, size_t stack_adjust) + Arm64Exception(Arm64ManagedRegister scratch, size_t stack_adjust) : scratch_(scratch), stack_adjust_(stack_adjust) { } diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc index 6d8a98931f..496ca95ff9 100644 --- a/compiler/utils/assembler.cc +++ b/compiler/utils/assembler.cc @@ -19,13 +19,25 @@ #include <algorithm> #include <vector> +#ifdef ART_ENABLE_CODEGEN_arm #include "arm/assembler_arm32.h" #include "arm/assembler_thumb2.h" +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 #include "arm64/assembler_arm64.h" +#endif +#ifdef ART_ENABLE_CODEGEN_mips #include "mips/assembler_mips.h" +#endif +#ifdef ART_ENABLE_CODEGEN_mips64 #include "mips64/assembler_mips64.h" +#endif +#ifdef ART_ENABLE_CODEGEN_x86 #include "x86/assembler_x86.h" +#endif +#ifdef ART_ENABLE_CODEGEN_x86_64 #include "x86_64/assembler_x86_64.h" +#endif #include "globals.h" #include "memory_region.h" @@ -112,20 +124,32 @@ void DebugFrameOpCodeWriterForAssembler::ImplicitlyAdvancePC() { Assembler* Assembler::Create(InstructionSet instruction_set) { switch (instruction_set) { +#ifdef ART_ENABLE_CODEGEN_arm case kArm: return new arm::Arm32Assembler(); case kThumb2: return new arm::Thumb2Assembler(); +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 case kArm64: return new arm64::Arm64Assembler(); +#endif +#ifdef ART_ENABLE_CODEGEN_mips case kMips: return new mips::MipsAssembler(); +#endif +#ifdef ART_ENABLE_CODEGEN_mips64 case kMips64: return new mips64::Mips64Assembler(); +#endif +#ifdef ART_ENABLE_CODEGEN_x86 case kX86: return new x86::X86Assembler(); +#endif +#ifdef ART_ENABLE_CODEGEN_x86_64 case kX86_64: return new x86_64::X86_64Assembler(); +#endif default: LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; return nullptr; diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h index 3097cd55c0..64d76b881d 100644 --- a/compiler/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -53,9 +53,11 @@ namespace mips64 { } namespace x86 { class X86Assembler; + class NearLabel; } namespace x86_64 { class X86_64Assembler; + class NearLabel; } class ExternalLabel { @@ -126,7 +128,9 @@ class Label { friend class mips::MipsAssembler; friend class mips64::Mips64Assembler; friend class x86::X86Assembler; + friend class x86::NearLabel; friend class x86_64::X86_64Assembler; + friend class x86_64::NearLabel; DISALLOW_COPY_AND_ASSIGN(Label); }; diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc index 20f61f942b..cb01cea8ef 100644 --- a/compiler/utils/assembler_thumb_test.cc +++ b/compiler/utils/assembler_thumb_test.cc @@ -32,7 +32,7 @@ namespace arm { // Include results file (generated manually) #include "assembler_thumb_test_expected.cc.inc" -#ifndef HAVE_ANDROID_OS +#ifndef __ANDROID__ // This controls whether the results are printed to the // screen or compared against the expected output. // To generate new expected output, set this to true and @@ -72,7 +72,7 @@ void InitResults() { } std::string GetToolsDir() { -#ifndef HAVE_ANDROID_OS +#ifndef __ANDROID__ // This will only work on the host. There is no as, objcopy or objdump on the device. static std::string toolsdir; @@ -89,7 +89,7 @@ std::string GetToolsDir() { } void DumpAndCheck(std::vector<uint8_t>& code, const char* testname, const char* const* results) { -#ifndef HAVE_ANDROID_OS +#ifndef __ANDROID__ static std::string toolsdir = GetToolsDir(); ScratchFile file; diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index 8cdb180740..2c4a689096 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -99,7 +99,7 @@ class DedupeSet { return hashed_key.store_ptr; } - explicit DedupeSet(const char* set_name, SwapAllocator<void>& alloc) + DedupeSet(const char* set_name, SwapAllocator<void>& alloc) : allocator_(alloc), hash_time_(0) { for (HashType i = 0; i < kShard; ++i) { std::ostringstream oss; diff --git a/compiler/utils/dex_cache_arrays_layout.h b/compiler/utils/dex_cache_arrays_layout.h index 8f98ea11ba..2a109bd11e 100644 --- a/compiler/utils/dex_cache_arrays_layout.h +++ b/compiler/utils/dex_cache_arrays_layout.h @@ -37,7 +37,7 @@ class DexCacheArraysLayout { } // Construct a layout for a particular dex file. - explicit DexCacheArraysLayout(size_t pointer_size, const DexFile* dex_file); + DexCacheArraysLayout(size_t pointer_size, const DexFile* dex_file); bool Valid() const { return Size() != 0u; diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h index bb62bca3b9..893daff719 100644 --- a/compiler/utils/managed_register.h +++ b/compiler/utils/managed_register.h @@ -95,7 +95,7 @@ class ManagedRegisterSpill : public ManagedRegister { explicit ManagedRegisterSpill(const ManagedRegister& other) : ManagedRegister(other), size_(-1), spill_offset_(-1) { } - explicit ManagedRegisterSpill(const ManagedRegister& other, int32_t size) + ManagedRegisterSpill(const ManagedRegister& other, int32_t size) : ManagedRegister(other), size_(size), spill_offset_(-1) { } int32_t getSpillOffset() { diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index c09dfcce4f..c5fae92f3c 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -359,23 +359,19 @@ void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) { } void MipsAssembler::AddD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x0); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x0); } void MipsAssembler::SubD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x1); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x1); } void MipsAssembler::MulD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x2); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x2); } void MipsAssembler::DivD(DRegister fd, DRegister fs, DRegister ft) { - EmitFR(0x11, 0x11, static_cast<FRegister>(ft), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x3); + EmitFR(0x11, 0x11, ConvertDRegToFReg(ft), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x3); } void MipsAssembler::MovS(FRegister fd, FRegister fs) { @@ -383,32 +379,31 @@ void MipsAssembler::MovS(FRegister fd, FRegister fs) { } void MipsAssembler::MovD(DRegister fd, DRegister fs) { - EmitFR(0x11, 0x11, static_cast<FRegister>(0), static_cast<FRegister>(fs), - static_cast<FRegister>(fd), 0x6); + EmitFR(0x11, 0x11, static_cast<FRegister>(0), ConvertDRegToFReg(fs), ConvertDRegToFReg(fd), 0x6); } void MipsAssembler::Mfc1(Register rt, FRegister fs) { - EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0); + EmitFR(0x11, 0x00, ConvertRegToFReg(rt), fs, static_cast<FRegister>(0), 0x0); } void MipsAssembler::Mtc1(FRegister ft, Register rs) { - EmitFR(0x11, 0x04, ft, static_cast<FRegister>(rs), static_cast<FRegister>(0), 0x0); + EmitFR(0x11, 0x04, ft, ConvertRegToFReg(rs), static_cast<FRegister>(0), 0x0); } void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) { - EmitI(0x31, rs, static_cast<Register>(ft), imm16); + EmitI(0x31, rs, ConvertFRegToReg(ft), imm16); } void MipsAssembler::Ldc1(DRegister ft, Register rs, uint16_t imm16) { - EmitI(0x35, rs, static_cast<Register>(ft), imm16); + EmitI(0x35, rs, ConvertDRegToReg(ft), imm16); } void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) { - EmitI(0x39, rs, static_cast<Register>(ft), imm16); + EmitI(0x39, rs, ConvertFRegToReg(ft), imm16); } void MipsAssembler::Sdc1(DRegister ft, Register rs, uint16_t imm16) { - EmitI(0x3d, rs, static_cast<Register>(ft), imm16); + EmitI(0x3d, rs, ConvertDRegToReg(ft), imm16); } void MipsAssembler::Break() { @@ -529,7 +524,7 @@ void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register } } -void MipsAssembler::StoreFToOffset(FRegister reg, Register base, int32_t offset) { +void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) { Swc1(reg, base, offset); } @@ -566,9 +561,22 @@ void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, StoreToOffset(kStoreWord, method_reg.AsMips().AsCoreRegister(), SP, 0); // Write out entry spills. + int32_t offset = frame_size + kFramePointerSize; for (size_t i = 0; i < entry_spills.size(); ++i) { - Register reg = entry_spills.at(i).AsMips().AsCoreRegister(); - StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize)); + MipsManagedRegister reg = entry_spills.at(i).AsMips(); + if (reg.IsNoRegister()) { + ManagedRegisterSpill spill = entry_spills.at(i); + offset += spill.getSize(); + } else if (reg.IsCoreRegister()) { + StoreToOffset(kStoreWord, reg.AsCoreRegister(), SP, offset); + offset += 4; + } else if (reg.IsFRegister()) { + StoreSToOffset(reg.AsFRegister(), SP, offset); + offset += 4; + } else if (reg.IsDRegister()) { + StoreDToOffset(reg.AsDRegister(), SP, offset); + offset += 8; + } } } @@ -624,7 +632,7 @@ void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { StoreToOffset(kStoreWord, src.AsRegisterPairHigh(), SP, dest.Int32Value() + 4); } else if (src.IsFRegister()) { - StoreFToOffset(src.AsFRegister(), SP, dest.Int32Value()); + StoreSToOffset(src.AsFRegister(), SP, dest.Int32Value()); } else { CHECK(src.IsDRegister()); StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value()); diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 0d1b82ce7b..6c8b162d62 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -141,7 +141,7 @@ class MipsAssembler FINAL : public Assembler { void LoadSFromOffset(FRegister reg, Register base, int32_t offset); void LoadDFromOffset(DRegister reg, Register base, int32_t offset); void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset); - void StoreFToOffset(FRegister reg, Register base, int32_t offset); + void StoreSToOffset(FRegister reg, Register base, int32_t offset); void StoreDToOffset(DRegister reg, Register base, int32_t offset); // Emit data (e.g. encoded instruction or immediate) to the instruction stream. @@ -277,13 +277,26 @@ class MipsAssembler FINAL : public Assembler { int32_t EncodeBranchOffset(int offset, int32_t inst, bool is_jump); int DecodeBranchOffset(int32_t inst, bool is_jump); + FRegister ConvertDRegToFReg(DRegister reg) { + return static_cast<FRegister>(reg * 2); + } + Register ConvertDRegToReg(DRegister reg) { + return static_cast<Register>(reg * 2); + } + Register ConvertFRegToReg(FRegister reg) { + return static_cast<Register>(reg); + } + FRegister ConvertRegToFReg(Register reg) { + return static_cast<FRegister>(reg); + } + DISALLOW_COPY_AND_ASSIGN(MipsAssembler); }; // Slowpath entered when Thread::Current()->_exception is non-null class MipsExceptionSlowPath FINAL : public SlowPath { public: - explicit MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust) + MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust) : scratch_(scratch), stack_adjust_(stack_adjust) {} virtual void Emit(Assembler *sp_asm) OVERRIDE; private: diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 47b146a28c..31130ea43d 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -354,7 +354,7 @@ class Mips64Assembler FINAL : public Assembler { // Slowpath entered when Thread::Current()->_exception is non-null class Mips64ExceptionSlowPath FINAL : public SlowPath { public: - explicit Mips64ExceptionSlowPath(Mips64ManagedRegister scratch, size_t stack_adjust) + Mips64ExceptionSlowPath(Mips64ManagedRegister scratch, size_t stack_adjust) : scratch_(scratch), stack_adjust_(stack_adjust) {} virtual void Emit(Assembler *sp_asm) OVERRIDE; private: diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index fa85ada864..a03f857e88 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -145,12 +145,33 @@ void X86Assembler::movl(const Address& dst, Label* lbl) { EmitLabel(lbl, dst.length_ + 5); } +void X86Assembler::movntl(const Address& dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xC3); + EmitOperand(src, dst); +} + void X86Assembler::bswapl(Register dst) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); EmitUint8(0xC8 + dst); } +void X86Assembler::bsrl(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitRegisterOperand(dst, src); +} + +void X86Assembler::bsrl(Register dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitOperand(dst, src); +} + void X86Assembler::movzxb(Register dst, ByteRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); @@ -1194,11 +1215,26 @@ void X86Assembler::imull(Register dst, Register src) { } -void X86Assembler::imull(Register reg, const Immediate& imm) { +void X86Assembler::imull(Register dst, Register src, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - EmitUint8(0x69); - EmitOperand(reg, Operand(reg)); - EmitImmediate(imm); + // See whether imm can be represented as a sign-extended 8bit value. + int32_t v32 = static_cast<int32_t>(imm.value()); + if (IsInt<8>(v32)) { + // Sign-extension works. + EmitUint8(0x6B); + EmitOperand(dst, Operand(src)); + EmitUint8(static_cast<uint8_t>(v32 & 0xFF)); + } else { + // Not representable, use full immediate. + EmitUint8(0x69); + EmitOperand(dst, Operand(src)); + EmitImmediate(imm); + } +} + + +void X86Assembler::imull(Register reg, const Immediate& imm) { + imull(reg, reg, imm); } @@ -1474,6 +1510,38 @@ void X86Assembler::j(Condition condition, Label* label) { } +void X86Assembler::j(Condition condition, NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0x70 + condition); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0x70 + condition); + EmitLabelLink(label); + } +} + + +void X86Assembler::jecxz(NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0xE3); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xE3); + EmitLabelLink(label); + } +} + + void X86Assembler::jmp(Register reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xFF); @@ -1507,6 +1575,22 @@ void X86Assembler::jmp(Label* label) { } +void X86Assembler::jmp(NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0xEB); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xEB); + EmitLabelLink(label); + } +} + + void X86Assembler::repne_scasw() { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1515,6 +1599,29 @@ void X86Assembler::repne_scasw() { } +void X86Assembler::repe_cmpsw() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + +void X86Assembler::repe_cmpsl() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + +void X86Assembler::rep_movsw() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0xF3); + EmitUint8(0xA5); +} + + X86Assembler* X86Assembler::lock() { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF0); @@ -1616,6 +1723,21 @@ void X86Assembler::Bind(Label* label) { } +void X86Assembler::Bind(NearLabel* label) { + int bound = buffer_.Size(); + CHECK(!label->IsBound()); // Labels can only be bound once. + while (label->IsLinked()) { + int position = label->LinkPosition(); + uint8_t delta = buffer_.Load<uint8_t>(position); + int offset = bound - (position + 1); + CHECK(IsInt<8>(offset)); + buffer_.Store<int8_t>(position, offset); + label->position_ = delta != 0u ? label->position_ - delta : 0; + } + label->BindTo(bound); +} + + void X86Assembler::EmitOperand(int reg_or_opcode, const Operand& operand) { CHECK_GE(reg_or_opcode, 0); CHECK_LT(reg_or_opcode, 8); @@ -1677,6 +1799,21 @@ void X86Assembler::EmitLabelLink(Label* label) { } +void X86Assembler::EmitLabelLink(NearLabel* label) { + CHECK(!label->IsBound()); + int position = buffer_.Size(); + if (label->IsLinked()) { + // Save the delta in the byte that we have to play with. + uint32_t delta = position - label->LinkPosition(); + CHECK(IsUint<8>(delta)); + EmitUint8(delta & 0xFF); + } else { + EmitUint8(0); + } + label->LinkTo(position); +} + + void X86Assembler::EmitGenericShift(int reg_or_opcode, const Operand& operand, const Immediate& imm) { diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index d1b4e1dc5f..0c90f2801a 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -203,9 +203,33 @@ class Address : public Operand { }; +// This is equivalent to the Label class, used in a slightly different context. We +// inherit the functionality of the Label class, but prevent unintended +// derived-to-base conversions by making the base class private. +class NearLabel : private Label { + public: + NearLabel() : Label() {} + + // Expose the Label routines that we need. + using Label::Position; + using Label::LinkPosition; + using Label::IsBound; + using Label::IsUnused; + using Label::IsLinked; + + private: + using Label::BindTo; + using Label::LinkTo; + + friend class x86::X86Assembler; + + DISALLOW_COPY_AND_ASSIGN(NearLabel); +}; + + class X86Assembler FINAL : public Assembler { public: - explicit X86Assembler() {} + X86Assembler() {} virtual ~X86Assembler() {} /* @@ -231,7 +255,11 @@ class X86Assembler FINAL : public Assembler { void movl(const Address& dst, const Immediate& imm); void movl(const Address& dst, Label* lbl); + void movntl(const Address& dst, Register src); + void bswapl(Register dst); + void bsrl(Register dst, Register src); + void bsrl(Register dst, const Address& src); void movzxb(Register dst, ByteRegister src); void movzxb(Register dst, const Address& src); @@ -409,6 +437,7 @@ class X86Assembler FINAL : public Assembler { void imull(Register dst, Register src); void imull(Register reg, const Immediate& imm); + void imull(Register dst, Register src, const Immediate& imm); void imull(Register reg, const Address& address); void imull(Register reg); @@ -459,12 +488,18 @@ class X86Assembler FINAL : public Assembler { void hlt(); void j(Condition condition, Label* label); + void j(Condition condition, NearLabel* label); + void jecxz(NearLabel* label); void jmp(Register reg); void jmp(const Address& address); void jmp(Label* label); + void jmp(NearLabel* label); void repne_scasw(); + void repe_cmpsw(); + void repe_cmpsl(); + void rep_movsw(); X86Assembler* lock(); void cmpxchgl(const Address& address, Register reg); @@ -498,6 +533,7 @@ class X86Assembler FINAL : public Assembler { int PreferredLoopAlignment() { return 16; } void Align(int alignment, int offset); void Bind(Label* label); + void Bind(NearLabel* label); // // Overridden common assembler high-level functionality @@ -644,7 +680,7 @@ class X86Assembler FINAL : public Assembler { void EmitComplex(int rm, const Operand& operand, const Immediate& immediate); void EmitLabel(Label* label, int instruction_size); void EmitLabelLink(Label* label); - void EmitNearLabelLink(Label* label); + void EmitLabelLink(NearLabel* label); void EmitGenericShift(int rm, const Operand& operand, const Immediate& imm); void EmitGenericShift(int rm, const Operand& operand, Register shifter); diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index aacc57bb0c..9ac54afc11 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -105,6 +105,16 @@ TEST_F(AssemblerX86Test, Movl) { DriverStr(expected, "movl"); } +TEST_F(AssemblerX86Test, Movntl) { + GetAssembler()->movntl(x86::Address(x86::EDI, x86::EBX, x86::TIMES_4, 12), x86::EAX); + GetAssembler()->movntl(x86::Address(x86::EDI, 0), x86::EAX); + const char* expected = + "movntil %EAX, 0xc(%EDI,%EBX,4)\n" + "movntil %EAX, (%EDI)\n"; + + DriverStr(expected, "movntl"); +} + TEST_F(AssemblerX86Test, psrlq) { GetAssembler()->psrlq(x86::XMM0, CreateImmediate(32)); const char* expected = "psrlq $0x20, %xmm0\n"; @@ -196,4 +206,80 @@ TEST_F(AssemblerX86Test, Repnescasw) { DriverStr(expected, "Repnescasw"); } +TEST_F(AssemblerX86Test, Repecmpsw) { + GetAssembler()->repe_cmpsw(); + const char* expected = "repe cmpsw\n"; + DriverStr(expected, "Repecmpsw"); +} + +TEST_F(AssemblerX86Test, Repecmpsl) { + GetAssembler()->repe_cmpsl(); + const char* expected = "repe cmpsl\n"; + DriverStr(expected, "Repecmpsl"); +} + +TEST_F(AssemblerX86Test, RepneScasw) { + GetAssembler()->repne_scasw(); + const char* expected = "repne scasw\n"; + DriverStr(expected, "repne_scasw"); +} + +TEST_F(AssemblerX86Test, RepMovsw) { + GetAssembler()->rep_movsw(); + const char* expected = "rep movsw\n"; + DriverStr(expected, "rep_movsw"); +} + +TEST_F(AssemblerX86Test, Bsrl) { + DriverStr(RepeatRR(&x86::X86Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl"); +} + +TEST_F(AssemblerX86Test, BsrlAddress) { + GetAssembler()->bsrl(x86::Register(x86::EDI), x86::Address( + x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12)); + const char* expected = + "bsrl 0xc(%EDI,%EBX,4), %EDI\n"; + + DriverStr(expected, "bsrl_address"); +} + +///////////////// +// Near labels // +///////////////// + +TEST_F(AssemblerX86Test, Jecxz) { + x86::NearLabel target; + GetAssembler()->jecxz(&target); + GetAssembler()->addl(x86::EDI, x86::Address(x86::ESP, 4)); + GetAssembler()->Bind(&target); + const char* expected = + "jecxz 1f\n" + "addl 4(%ESP),%EDI\n" + "1:\n"; + + DriverStr(expected, "jecxz"); +} + +TEST_F(AssemblerX86Test, NearLabel) { + // Test both forward and backward branches. + x86::NearLabel start, target; + GetAssembler()->Bind(&start); + GetAssembler()->j(x86::kEqual, &target); + GetAssembler()->jmp(&target); + GetAssembler()->jecxz(&target); + GetAssembler()->addl(x86::EDI, x86::Address(x86::ESP, 4)); + GetAssembler()->Bind(&target); + GetAssembler()->j(x86::kNotEqual, &start); + GetAssembler()->jmp(&start); + const char* expected = + "1: je 2f\n" + "jmp 2f\n" + "jecxz 2f\n" + "addl 4(%ESP),%EDI\n" + "2: jne 1b\n" + "jmp 1b\n"; + + DriverStr(expected, "near_label"); +} + } // namespace art diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index f35f51c494..88ea9900fe 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -194,6 +194,21 @@ void X86_64Assembler::movl(const Address& dst, const Immediate& imm) { EmitImmediate(imm); } +void X86_64Assembler::movntl(const Address& dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(src, dst); + EmitUint8(0x0F); + EmitUint8(0xC3); + EmitOperand(src.LowBits(), dst); +} + +void X86_64Assembler::movntq(const Address& dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(src, dst); + EmitUint8(0x0F); + EmitUint8(0xC3); + EmitOperand(src.LowBits(), dst); +} void X86_64Assembler::cmov(Condition c, CpuRegister dst, CpuRegister src) { cmov(c, dst, src, true); @@ -1672,28 +1687,33 @@ void X86_64Assembler::imull(CpuRegister dst, CpuRegister src) { EmitOperand(dst.LowBits(), Operand(src)); } -void X86_64Assembler::imull(CpuRegister reg, const Immediate& imm) { +void X86_64Assembler::imull(CpuRegister dst, CpuRegister src, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); CHECK(imm.is_int32()); // imull only supports 32b immediate. - EmitOptionalRex32(reg, reg); + EmitOptionalRex32(dst, src); // See whether imm can be represented as a sign-extended 8bit value. int32_t v32 = static_cast<int32_t>(imm.value()); if (IsInt<8>(v32)) { // Sign-extension works. EmitUint8(0x6B); - EmitOperand(reg.LowBits(), Operand(reg)); + EmitOperand(dst.LowBits(), Operand(src)); EmitUint8(static_cast<uint8_t>(v32 & 0xFF)); } else { // Not representable, use full immediate. EmitUint8(0x69); - EmitOperand(reg.LowBits(), Operand(reg)); + EmitOperand(dst.LowBits(), Operand(src)); EmitImmediate(imm); } } +void X86_64Assembler::imull(CpuRegister reg, const Immediate& imm) { + imull(reg, reg, imm); +} + + void X86_64Assembler::imull(CpuRegister reg, const Address& address) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(reg, address); @@ -1951,6 +1971,38 @@ void X86_64Assembler::j(Condition condition, Label* label) { } +void X86_64Assembler::j(Condition condition, NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0x70 + condition); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0x70 + condition); + EmitLabelLink(label); + } +} + + +void X86_64Assembler::jrcxz(NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0xE3); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xE3); + EmitLabelLink(label); + } +} + + void X86_64Assembler::jmp(CpuRegister reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(reg); @@ -1986,6 +2038,30 @@ void X86_64Assembler::jmp(Label* label) { } +void X86_64Assembler::jmp(NearLabel* label) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (label->IsBound()) { + static const int kShortSize = 2; + int offset = label->Position() - buffer_.Size(); + CHECK_LE(offset, 0); + CHECK(IsInt<8>(offset - kShortSize)); + EmitUint8(0xEB); + EmitUint8((offset - kShortSize) & 0xFF); + } else { + EmitUint8(0xEB); + EmitLabelLink(label); + } +} + + +void X86_64Assembler::rep_movsw() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0xF3); + EmitUint8(0xA5); +} + + X86_64Assembler* X86_64Assembler::lock() { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF0); @@ -2064,6 +2140,37 @@ void X86_64Assembler::bswapq(CpuRegister dst) { EmitUint8(0xC8 + dst.LowBits()); } +void X86_64Assembler::bsrl(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitRegisterOperand(dst.LowBits(), src.LowBits()); +} + +void X86_64Assembler::bsrl(CpuRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitOperand(dst.LowBits(), src); +} + +void X86_64Assembler::bsrq(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitRegisterOperand(dst.LowBits(), src.LowBits()); +} + +void X86_64Assembler::bsrq(CpuRegister dst, const Address& src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitOperand(dst.LowBits(), src); +} void X86_64Assembler::repne_scasw() { AssemblerBuffer::EnsureCapacity ensured(&buffer_); @@ -2073,6 +2180,29 @@ void X86_64Assembler::repne_scasw() { } +void X86_64Assembler::repe_cmpsw() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + +void X86_64Assembler::repe_cmpsl() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + +void X86_64Assembler::repe_cmpsq() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitRex64(); + EmitUint8(0xA7); +} + + void X86_64Assembler::LoadDoubleConstant(XmmRegister dst, double value) { // TODO: Need to have a code constants table. int64_t constant = bit_cast<int64_t, double>(value); @@ -2105,6 +2235,21 @@ void X86_64Assembler::Bind(Label* label) { } +void X86_64Assembler::Bind(NearLabel* label) { + int bound = buffer_.Size(); + CHECK(!label->IsBound()); // Labels can only be bound once. + while (label->IsLinked()) { + int position = label->LinkPosition(); + uint8_t delta = buffer_.Load<uint8_t>(position); + int offset = bound - (position + 1); + CHECK(IsInt<8>(offset)); + buffer_.Store<int8_t>(position, offset); + label->position_ = delta != 0u ? label->position_ - delta : 0; + } + label->BindTo(bound); +} + + void X86_64Assembler::EmitOperand(uint8_t reg_or_opcode, const Operand& operand) { CHECK_GE(reg_or_opcode, 0); CHECK_LT(reg_or_opcode, 8); @@ -2174,6 +2319,21 @@ void X86_64Assembler::EmitLabelLink(Label* label) { } +void X86_64Assembler::EmitLabelLink(NearLabel* label) { + CHECK(!label->IsBound()); + int position = buffer_.Size(); + if (label->IsLinked()) { + // Save the delta in the byte that we have to play with. + uint32_t delta = position - label->LinkPosition(); + CHECK(IsUint<8>(delta)); + EmitUint8(delta & 0xFF); + } else { + EmitUint8(0); + } + label->LinkTo(position); +} + + void X86_64Assembler::EmitGenericShift(bool wide, int reg_or_opcode, CpuRegister reg, diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 61ffeab1e8..c38aba5e91 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -302,6 +302,30 @@ class ConstantArea { }; +// This is equivalent to the Label class, used in a slightly different context. We +// inherit the functionality of the Label class, but prevent unintended +// derived-to-base conversions by making the base class private. +class NearLabel : private Label { + public: + NearLabel() : Label() {} + + // Expose the Label routines that we need. + using Label::Position; + using Label::LinkPosition; + using Label::IsBound; + using Label::IsUnused; + using Label::IsLinked; + + private: + using Label::BindTo; + using Label::LinkTo; + + friend class x86_64::X86_64Assembler; + + DISALLOW_COPY_AND_ASSIGN(NearLabel); +}; + + class X86_64Assembler FINAL : public Assembler { public: X86_64Assembler() {} @@ -326,10 +350,13 @@ class X86_64Assembler FINAL : public Assembler { void movq(CpuRegister dst, CpuRegister src); void movl(CpuRegister dst, CpuRegister src); + void movntl(const Address& dst, CpuRegister src); + void movntq(const Address& dst, CpuRegister src); + void movq(CpuRegister dst, const Address& src); void movl(CpuRegister dst, const Address& src); void movq(const Address& dst, CpuRegister src); - void movq(const Address& dst, const Immediate& src); + void movq(const Address& dst, const Immediate& imm); void movl(const Address& dst, CpuRegister src); void movl(const Address& dst, const Immediate& imm); @@ -539,6 +566,7 @@ class X86_64Assembler FINAL : public Assembler { void imull(CpuRegister dst, CpuRegister src); void imull(CpuRegister reg, const Immediate& imm); + void imull(CpuRegister dst, CpuRegister src, const Immediate& imm); void imull(CpuRegister reg, const Address& address); void imulq(CpuRegister src); @@ -584,10 +612,13 @@ class X86_64Assembler FINAL : public Assembler { void hlt(); void j(Condition condition, Label* label); + void j(Condition condition, NearLabel* label); + void jrcxz(NearLabel* label); void jmp(CpuRegister reg); void jmp(const Address& address); void jmp(Label* label); + void jmp(NearLabel* label); X86_64Assembler* lock(); void cmpxchgl(const Address& address, CpuRegister reg); @@ -602,7 +633,16 @@ class X86_64Assembler FINAL : public Assembler { void bswapl(CpuRegister dst); void bswapq(CpuRegister dst); + void bsrl(CpuRegister dst, CpuRegister src); + void bsrl(CpuRegister dst, const Address& src); + void bsrq(CpuRegister dst, CpuRegister src); + void bsrq(CpuRegister dst, const Address& src); + void repne_scasw(); + void repe_cmpsw(); + void repe_cmpsl(); + void repe_cmpsq(); + void rep_movsw(); // // Macros for High-level operations. @@ -626,6 +666,7 @@ class X86_64Assembler FINAL : public Assembler { int PreferredLoopAlignment() { return 16; } void Align(int alignment, int offset); void Bind(Label* label); + void Bind(NearLabel* label); // // Overridden common assembler high-level functionality @@ -796,7 +837,7 @@ class X86_64Assembler FINAL : public Assembler { void EmitComplex(uint8_t rm, const Operand& operand, const Immediate& immediate); void EmitLabel(Label* label, int instruction_size); void EmitLabelLink(Label* label); - void EmitNearLabelLink(Label* label); + void EmitLabelLink(NearLabel* label); void EmitGenericShift(bool wide, int rm, CpuRegister reg, const Immediate& imm); void EmitGenericShift(bool wide, int rm, CpuRegister operand, CpuRegister shifter); diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 6da5c35731..9e64b47c92 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -35,7 +35,7 @@ TEST(AssemblerX86_64, CreateBuffer) { ASSERT_EQ(static_cast<size_t>(5), buffer.Size()); } -#ifdef HAVE_ANDROID_OS +#ifdef __ANDROID__ static constexpr size_t kRandomIterations = 1000; // Devices might be puny, don't stress them... #else static constexpr size_t kRandomIterations = 100000; // Hosts are pretty powerful. @@ -674,6 +674,46 @@ TEST_F(AssemblerX86_64Test, MovqAddrImm) { DriverStr(expected, "movq"); } +TEST_F(AssemblerX86_64Test, Movntl) { + GetAssembler()->movntl(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntl(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntl(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntl(x86_64::Address(x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntl(x86_64::Address( + x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0), x86_64::CpuRegister(x86_64::R9)); + const char* expected = + "movntil %EAX, 0xc(%RDI,%RBX,4)\n" + "movntil %EAX, 0xc(%RDI,%R9,4)\n" + "movntil %EAX, 0xc(%RDI,%R9,4)\n" + "movntil %EAX, (%R13)\n" + "movntil %R9d, (%R13,%R9,1)\n"; + + DriverStr(expected, "movntl"); +} + +TEST_F(AssemblerX86_64Test, Movntq) { + GetAssembler()->movntq(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntq(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntq(x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntq(x86_64::Address(x86_64::CpuRegister(x86_64::R13), 0), x86_64::CpuRegister(x86_64::RAX)); + GetAssembler()->movntq(x86_64::Address( + x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0), x86_64::CpuRegister(x86_64::R9)); + const char* expected = + "movntiq %RAX, 0xc(%RDI,%RBX,4)\n" + "movntiq %RAX, 0xc(%RDI,%R9,4)\n" + "movntiq %RAX, 0xc(%RDI,%R9,4)\n" + "movntiq %RAX, (%R13)\n" + "movntiq %R9, (%R13,%R9,1)\n"; + + DriverStr(expected, "movntq"); +} + TEST_F(AssemblerX86_64Test, Cvtsi2ssAddr) { GetAssembler()->cvtsi2ss(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0), @@ -796,6 +836,18 @@ TEST_F(AssemblerX86_64Test, Xorq) { DriverStr(expected, "xorq"); } +TEST_F(AssemblerX86_64Test, RepneScasw) { + GetAssembler()->repne_scasw(); + const char* expected = "repne scasw\n"; + DriverStr(expected, "repne_scasw"); +} + +TEST_F(AssemblerX86_64Test, RepMovsw) { + GetAssembler()->rep_movsw(); + const char* expected = "rep movsw\n"; + DriverStr(expected, "rep_movsw"); +} + TEST_F(AssemblerX86_64Test, Movsxd) { DriverStr(RepeatRr(&x86_64::X86_64Assembler::movsxd, "movsxd %{reg2}, %{reg1}"), "movsxd"); } @@ -1089,6 +1141,85 @@ TEST_F(AssemblerX86_64Test, Bswapq) { DriverStr(RepeatR(&x86_64::X86_64Assembler::bswapq, "bswap %{reg}"), "bswapq"); } +TEST_F(AssemblerX86_64Test, Bsrl) { + DriverStr(Repeatrr(&x86_64::X86_64Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl"); +} + +TEST_F(AssemblerX86_64Test, BsrlAddress) { + GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::R10), x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12)); + GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address( + x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12)); + GetAssembler()->bsrl(x86_64::CpuRegister(x86_64::RDI), x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12)); + const char* expected = + "bsrl 0xc(%RDI,%RBX,4), %R10d\n" + "bsrl 0xc(%R10,%RBX,4), %edi\n" + "bsrl 0xc(%RDI,%R9,4), %edi\n"; + + DriverStr(expected, "bsrl_address"); +} + +TEST_F(AssemblerX86_64Test, Bsrq) { + DriverStr(RepeatRR(&x86_64::X86_64Assembler::bsrq, "bsrq %{reg2}, %{reg1}"), "bsrq"); +} + +TEST_F(AssemblerX86_64Test, BsrqAddress) { + GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::R10), x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12)); + GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address( + x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12)); + GetAssembler()->bsrq(x86_64::CpuRegister(x86_64::RDI), x86_64::Address( + x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12)); + const char* expected = + "bsrq 0xc(%RDI,%RBX,4), %R10\n" + "bsrq 0xc(%R10,%RBX,4), %RDI\n" + "bsrq 0xc(%RDI,%R9,4), %RDI\n"; + + DriverStr(expected, "bsrq_address"); +} + +///////////////// +// Near labels // +///////////////// + +TEST_F(AssemblerX86_64Test, Jrcxz) { + x86_64::NearLabel target; + GetAssembler()->jrcxz(&target); + GetAssembler()->addl(x86_64::CpuRegister(x86_64::RDI), + x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4)); + GetAssembler()->Bind(&target); + const char* expected = + "jrcxz 1f\n" + "addl 4(%RSP),%EDI\n" + "1:\n"; + + DriverStr(expected, "jrcxz"); +} + +TEST_F(AssemblerX86_64Test, NearLabel) { + // Test both forward and backward branches. + x86_64::NearLabel start, target; + GetAssembler()->Bind(&start); + GetAssembler()->j(x86_64::kEqual, &target); + GetAssembler()->jmp(&target); + GetAssembler()->jrcxz(&target); + GetAssembler()->addl(x86_64::CpuRegister(x86_64::RDI), + x86_64::Address(x86_64::CpuRegister(x86_64::RSP), 4)); + GetAssembler()->Bind(&target); + GetAssembler()->j(x86_64::kNotEqual, &start); + GetAssembler()->jmp(&start); + const char* expected = + "1: je 2f\n" + "jmp 2f\n" + "jrcxz 2f\n" + "addl 4(%RSP),%EDI\n" + "2: jne 1b\n" + "jmp 1b\n"; + + DriverStr(expected, "near_label"); +} + std::string setcc_test_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) { // From Condition @@ -1263,4 +1394,22 @@ TEST_F(AssemblerX86_64Test, Repnescasw) { DriverStr(expected, "Repnescasw"); } +TEST_F(AssemblerX86_64Test, Repecmpsw) { + GetAssembler()->repe_cmpsw(); + const char* expected = "repe cmpsw\n"; + DriverStr(expected, "Repecmpsw"); +} + +TEST_F(AssemblerX86_64Test, Repecmpsl) { + GetAssembler()->repe_cmpsl(); + const char* expected = "repe cmpsl\n"; + DriverStr(expected, "Repecmpsl"); +} + +TEST_F(AssemblerX86_64Test, Repecmpsq) { + GetAssembler()->repe_cmpsq(); + const char* expected = "repe cmpsq\n"; + DriverStr(expected, "Repecmpsq"); +} + } // namespace art |