summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/arm/assembler_arm.h6
-rw-r--r--compiler/utils/arm64/assembler_arm64.h7
-rw-r--r--compiler/utils/assembler.h104
-rw-r--r--compiler/utils/label.h129
-rw-r--r--compiler/utils/mips/assembler_mips.h7
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc202
-rw-r--r--compiler/utils/mips64/assembler_mips64.h50
-rw-r--r--compiler/utils/x86/assembler_x86.cc34
-rw-r--r--compiler/utils/x86/assembler_x86.h12
-rw-r--r--compiler/utils/x86/assembler_x86_test.cc63
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.cc72
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.h20
-rw-r--r--compiler/utils/x86_64/assembler_x86_64_test.cc130
13 files changed, 731 insertions, 105 deletions
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index a4d1837748..967b191d32 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -834,8 +834,6 @@ class ArmAssembler : public Assembler {
static bool IsInstructionForExceptionHandling(uintptr_t pc);
- virtual void Bind(Label* label) = 0;
-
virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
@@ -985,6 +983,10 @@ class ArmAssembler : public Assembler {
}
}
+ void Jump(Label* label) OVERRIDE {
+ b(label);
+ }
+
protected:
// Returns whether or not the given register is used for passing parameters.
static int RegisterCompare(const Register* reg1, const Register* reg2) {
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index 8e85fe96ab..7b25b8f3f5 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -193,6 +193,13 @@ class Arm64Assembler FINAL : public Assembler {
// Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
void MaybeUnpoisonHeapReference(vixl::Register reg);
+ void Bind(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+ UNIMPLEMENTED(FATAL) << "Do not use Bind for ARM64";
+ }
+ void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+ UNIMPLEMENTED(FATAL) << "Do not use Jump for ARM64";
+ }
+
private:
static vixl::Register reg_x(int code) {
CHECK(code < kNumberOfXRegisters) << code;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 64d76b881d..1088cb1bbd 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -23,6 +23,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "arm/constants_arm.h"
+#include "label.h"
#include "managed_register.h"
#include "memory_region.h"
#include "mips/constants_mips.h"
@@ -35,106 +36,6 @@ namespace art {
class Assembler;
class AssemblerBuffer;
-class AssemblerFixup;
-
-namespace arm {
- class ArmAssembler;
- class Arm32Assembler;
- class Thumb2Assembler;
-}
-namespace arm64 {
- class Arm64Assembler;
-}
-namespace mips {
- class MipsAssembler;
-}
-namespace mips64 {
- class Mips64Assembler;
-}
-namespace x86 {
- class X86Assembler;
- class NearLabel;
-}
-namespace x86_64 {
- class X86_64Assembler;
- class NearLabel;
-}
-
-class ExternalLabel {
- public:
- ExternalLabel(const char* name_in, uintptr_t address_in)
- : name_(name_in), address_(address_in) {
- DCHECK(name_in != nullptr);
- }
-
- const char* name() const { return name_; }
- uintptr_t address() const {
- return address_;
- }
-
- private:
- const char* name_;
- const uintptr_t address_;
-};
-
-class Label {
- public:
- Label() : position_(0) {}
-
- ~Label() {
- // Assert if label is being destroyed with unresolved branches pending.
- CHECK(!IsLinked());
- }
-
- // Returns the position for bound and linked labels. Cannot be used
- // for unused labels.
- int Position() const {
- CHECK(!IsUnused());
- return IsBound() ? -position_ - sizeof(void*) : position_ - sizeof(void*);
- }
-
- int LinkPosition() const {
- CHECK(IsLinked());
- return position_ - sizeof(void*);
- }
-
- bool IsBound() const { return position_ < 0; }
- bool IsUnused() const { return position_ == 0; }
- bool IsLinked() const { return position_ > 0; }
-
- private:
- int position_;
-
- void Reinitialize() {
- position_ = 0;
- }
-
- void BindTo(int position) {
- CHECK(!IsBound());
- position_ = -position - sizeof(void*);
- CHECK(IsBound());
- }
-
- void LinkTo(int position) {
- CHECK(!IsBound());
- position_ = position + sizeof(void*);
- CHECK(IsLinked());
- }
-
- friend class arm::ArmAssembler;
- friend class arm::Arm32Assembler;
- friend class arm::Thumb2Assembler;
- friend class arm64::Arm64Assembler;
- 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);
-};
-
// Assembler fixups are positions in generated code that require processing
// after the code has been copied to executable memory. This includes building
@@ -534,6 +435,9 @@ class Assembler {
// and branch to a ExceptionSlowPath if it is.
virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
+ virtual void Bind(Label* label) = 0;
+ virtual void Jump(Label* label) = 0;
+
virtual ~Assembler() {}
/**
diff --git a/compiler/utils/label.h b/compiler/utils/label.h
new file mode 100644
index 0000000000..ff4a1a4333
--- /dev/null
+++ b/compiler/utils/label.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 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_UTILS_LABEL_H_
+#define ART_COMPILER_UTILS_LABEL_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+namespace art {
+
+class Assembler;
+class AssemblerBuffer;
+class AssemblerFixup;
+
+namespace arm {
+ class ArmAssembler;
+ class Arm32Assembler;
+ class Thumb2Assembler;
+}
+namespace arm64 {
+ class Arm64Assembler;
+}
+namespace mips {
+ class MipsAssembler;
+}
+namespace mips64 {
+ class Mips64Assembler;
+}
+namespace x86 {
+ class X86Assembler;
+ class NearLabel;
+}
+namespace x86_64 {
+ class X86_64Assembler;
+ class NearLabel;
+}
+
+class ExternalLabel {
+ public:
+ ExternalLabel(const char* name_in, uintptr_t address_in)
+ : name_(name_in), address_(address_in) {
+ DCHECK(name_in != nullptr);
+ }
+
+ const char* name() const { return name_; }
+ uintptr_t address() const {
+ return address_;
+ }
+
+ private:
+ const char* name_;
+ const uintptr_t address_;
+};
+
+class Label {
+ public:
+ Label() : position_(0) {}
+
+ ~Label() {
+ // Assert if label is being destroyed with unresolved branches pending.
+ CHECK(!IsLinked());
+ }
+
+ // Returns the position for bound and linked labels. Cannot be used
+ // for unused labels.
+ int Position() const {
+ CHECK(!IsUnused());
+ return IsBound() ? -position_ - sizeof(void*) : position_ - sizeof(void*);
+ }
+
+ int LinkPosition() const {
+ CHECK(IsLinked());
+ return position_ - sizeof(void*);
+ }
+
+ bool IsBound() const { return position_ < 0; }
+ bool IsUnused() const { return position_ == 0; }
+ bool IsLinked() const { return position_ > 0; }
+
+ private:
+ int position_;
+
+ void Reinitialize() {
+ position_ = 0;
+ }
+
+ void BindTo(int position) {
+ CHECK(!IsBound());
+ position_ = -position - sizeof(void*);
+ CHECK(IsBound());
+ }
+
+ void LinkTo(int position) {
+ CHECK(!IsBound());
+ position_ = position + sizeof(void*);
+ CHECK(IsLinked());
+ }
+
+ friend class arm::ArmAssembler;
+ friend class arm::Arm32Assembler;
+ friend class arm::Thumb2Assembler;
+ friend class arm64::Arm64Assembler;
+ 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);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_LABEL_H_
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 6c8b162d62..378a59cb3e 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -150,6 +150,13 @@ class MipsAssembler FINAL : public Assembler {
void EmitJump(Label* label, bool link);
void Bind(Label* label, bool is_jump);
+ void Bind(Label* label) OVERRIDE {
+ Bind(label, false);
+ }
+ void Jump(Label* label) OVERRIDE {
+ EmitJump(label, false);
+ }
+
//
// Overridden common assembler high-level functionality
//
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 24ea9e25db..b078f3e4cf 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -44,6 +44,32 @@ void Mips64Assembler::EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegis
Emit(encoding);
}
+void Mips64Assembler::EmitRsd(int opcode, GpuRegister rs, GpuRegister rd,
+ int shamt, int funct) {
+ CHECK_NE(rs, kNoGpuRegister);
+ CHECK_NE(rd, kNoGpuRegister);
+ uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
+ static_cast<uint32_t>(rs) << kRsShift |
+ static_cast<uint32_t>(ZERO) << kRtShift |
+ static_cast<uint32_t>(rd) << kRdShift |
+ shamt << kShamtShift |
+ funct;
+ Emit(encoding);
+}
+
+void Mips64Assembler::EmitRtd(int opcode, GpuRegister rt, GpuRegister rd,
+ int shamt, int funct) {
+ CHECK_NE(rt, kNoGpuRegister);
+ CHECK_NE(rd, kNoGpuRegister);
+ uint32_t encoding = static_cast<uint32_t>(opcode) << kOpcodeShift |
+ static_cast<uint32_t>(ZERO) << kRsShift |
+ static_cast<uint32_t>(rt) << kRtShift |
+ static_cast<uint32_t>(rd) << kRdShift |
+ shamt << kShamtShift |
+ funct;
+ Emit(encoding);
+}
+
void Mips64Assembler::EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm) {
CHECK_NE(rs, kNoGpuRegister);
CHECK_NE(rt, kNoGpuRegister);
@@ -235,6 +261,14 @@ void Mips64Assembler::Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
EmitR(0, rs, rt, rd, 0, 0x27);
}
+void Mips64Assembler::Bitswap(GpuRegister rd, GpuRegister rt) {
+ EmitRtd(0x1f, rt, rd, 0x0, 0x20);
+}
+
+void Mips64Assembler::Dbitswap(GpuRegister rd, GpuRegister rt) {
+ EmitRtd(0x1f, rt, rd, 0x0, 0x24);
+}
+
void Mips64Assembler::Seb(GpuRegister rd, GpuRegister rt) {
EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x10, 0x20);
}
@@ -243,12 +277,44 @@ void Mips64Assembler::Seh(GpuRegister rd, GpuRegister rt) {
EmitR(0x1f, static_cast<GpuRegister>(0), rt, rd, 0x18, 0x20);
}
+void Mips64Assembler::Dsbh(GpuRegister rd, GpuRegister rt) {
+ EmitRtd(0x1f, rt, rd, 0x2, 0x24);
+}
+
+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::Wsbh(GpuRegister rd, GpuRegister rt) {
+ EmitRtd(0x1f, rt, rd, 2, 0x20);
+}
+
+void Mips64Assembler::Sc(GpuRegister rt, GpuRegister base, int16_t imm9) {
+ DCHECK((-256 <= imm9) && (imm9 < 256));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x26);
+}
+
+void Mips64Assembler::Scd(GpuRegister rt, GpuRegister base, int16_t imm9) {
+ DCHECK((-256 <= imm9) && (imm9 < 256));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x27);
+}
+
+void Mips64Assembler::Ll(GpuRegister rt, GpuRegister base, int16_t imm9) {
+ DCHECK((-256 <= imm9) && (imm9 < 256));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x36);
+}
+
+void Mips64Assembler::Lld(GpuRegister rt, GpuRegister base, int16_t imm9) {
+ DCHECK((-256 <= imm9) && (imm9 < 256));
+ EmitI(0x1f, base, rt, ((imm9 & 0x1FF) << 7) | 0x37);
+}
+
void Mips64Assembler::Sll(GpuRegister rd, GpuRegister rt, int shamt) {
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x00);
}
@@ -257,6 +323,10 @@ void Mips64Assembler::Srl(GpuRegister rd, GpuRegister rt, int shamt) {
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x02);
}
+void Mips64Assembler::Rotr(GpuRegister rd, GpuRegister rt, int shamt) {
+ EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x02);
+}
+
void Mips64Assembler::Sra(GpuRegister rd, GpuRegister rt, int shamt) {
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x03);
}
@@ -414,6 +484,30 @@ void Mips64Assembler::Jal(uint32_t addr26) {
Nop();
}
+void Mips64Assembler::Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+ EmitR(0, rs, rt, rd, 0, 0x35);
+}
+
+void Mips64Assembler::Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt) {
+ EmitR(0, rs, rt, rd, 0, 0x37);
+}
+
+void Mips64Assembler::Clz(GpuRegister rd, GpuRegister rs) {
+ EmitRsd(0, rs, rd, 0x01, 0x10);
+}
+
+void Mips64Assembler::Clo(GpuRegister rd, GpuRegister rs) {
+ EmitRsd(0, rs, rd, 0x01, 0x11);
+}
+
+void Mips64Assembler::Dclz(GpuRegister rd, GpuRegister rs) {
+ EmitRsd(0, rs, rd, 0x01, 0x12);
+}
+
+void Mips64Assembler::Dclo(GpuRegister rd, GpuRegister rs) {
+ EmitRsd(0, rs, rd, 0x01, 0x13);
+}
+
void Mips64Assembler::Jalr(GpuRegister rd, GpuRegister rs) {
EmitR(0, rs, static_cast<GpuRegister>(0), rd, 0, 0x09);
Nop();
@@ -543,6 +637,22 @@ void Mips64Assembler::DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
EmitFR(0x11, 0x11, ft, fs, fd, 0x3);
}
+void Mips64Assembler::SqrtS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x4);
+}
+
+void Mips64Assembler::SqrtD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x4);
+}
+
+void Mips64Assembler::AbsS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x5);
+}
+
+void Mips64Assembler::AbsD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x5);
+}
+
void Mips64Assembler::MovS(FpuRegister fd, FpuRegister fs) {
EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x6);
}
@@ -559,6 +669,94 @@ void Mips64Assembler::NegD(FpuRegister fd, FpuRegister fs) {
EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x7);
}
+void Mips64Assembler::RoundLS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x8);
+}
+
+void Mips64Assembler::RoundLD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x8);
+}
+
+void Mips64Assembler::RoundWS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xc);
+}
+
+void Mips64Assembler::RoundWD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xc);
+}
+
+void Mips64Assembler::CeilLS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xa);
+}
+
+void Mips64Assembler::CeilLD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xa);
+}
+
+void Mips64Assembler::CeilWS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xe);
+}
+
+void Mips64Assembler::CeilWD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xe);
+}
+
+void Mips64Assembler::FloorLS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xb);
+}
+
+void Mips64Assembler::FloorLD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xb);
+}
+
+void Mips64Assembler::FloorWS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0xf);
+}
+
+void Mips64Assembler::FloorWD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0xf);
+}
+
+void Mips64Assembler::SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x10, ft, fs, fd, 0x10);
+}
+
+void Mips64Assembler::SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x11, ft, fs, fd, 0x10);
+}
+
+void Mips64Assembler::RintS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1a);
+}
+
+void Mips64Assembler::RintD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1a);
+}
+
+void Mips64Assembler::ClassS(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x1b);
+}
+
+void Mips64Assembler::ClassD(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x11, static_cast<FpuRegister>(0), fs, fd, 0x1b);
+}
+
+void Mips64Assembler::MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x10, ft, fs, fd, 0x1c);
+}
+
+void Mips64Assembler::MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x11, ft, fs, fd, 0x1c);
+}
+
+void Mips64Assembler::MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x10, ft, fs, fd, 0x1e);
+}
+
+void Mips64Assembler::MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft) {
+ EmitFR(0x11, 0x11, ft, fs, fd, 0x1e);
+}
+
void Mips64Assembler::Cvtsw(FpuRegister fd, FpuRegister fs) {
EmitFR(0x11, 0x14, static_cast<FpuRegister>(0), fs, fd, 0x20);
}
@@ -575,6 +773,10 @@ void Mips64Assembler::Cvtds(FpuRegister fd, FpuRegister fs) {
EmitFR(0x11, 0x10, static_cast<FpuRegister>(0), fs, fd, 0x21);
}
+void Mips64Assembler::Cvtdl(FpuRegister fd, FpuRegister fs) {
+ EmitFR(0x11, 0x15, static_cast<FpuRegister>(0), fs, fd, 0x21);
+}
+
void Mips64Assembler::Mfc1(GpuRegister rt, FpuRegister fs) {
EmitFR(0x11, 0x00, static_cast<FpuRegister>(rt), fs, static_cast<FpuRegister>(0), 0x0);
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 31130ea43d..c170313728 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -90,12 +90,22 @@ class Mips64Assembler FINAL : public Assembler {
void Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16);
void Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+ void Bitswap(GpuRegister rd, GpuRegister rt); // R6
+ void Dbitswap(GpuRegister rd, GpuRegister rt); // R6
void Seb(GpuRegister rd, GpuRegister rt); // R2+
void Seh(GpuRegister rd, GpuRegister rt); // R2+
+ void Dsbh(GpuRegister rd, GpuRegister rt); // R2+
+ void Dshd(GpuRegister rd, GpuRegister rt); // R2+
void Dext(GpuRegister rs, GpuRegister rt, int pos, int size_less_one); // 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);
+ void Ll(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
+ void Lld(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
void Sll(GpuRegister rd, GpuRegister rt, int shamt);
void Srl(GpuRegister rd, GpuRegister rt, int shamt);
+ void Rotr(GpuRegister rd, GpuRegister rt, int shamt);
void Sra(GpuRegister rd, GpuRegister rt, int shamt);
void Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
void Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
@@ -133,6 +143,12 @@ class Mips64Assembler FINAL : public Assembler {
void Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
void Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16);
void Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
+ void Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+ void Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt);
+ void Clz(GpuRegister rd, GpuRegister rs);
+ void Clo(GpuRegister rd, GpuRegister rs);
+ void Dclz(GpuRegister rd, GpuRegister rs);
+ void Dclo(GpuRegister rd, GpuRegister rs);
void Beq(GpuRegister rs, GpuRegister rt, uint16_t imm16);
void Bne(GpuRegister rs, GpuRegister rt, uint16_t imm16);
@@ -165,15 +181,42 @@ class Mips64Assembler FINAL : public Assembler {
void SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
void MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
void DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void SqrtS(FpuRegister fd, FpuRegister fs);
+ void SqrtD(FpuRegister fd, FpuRegister fs);
+ void AbsS(FpuRegister fd, FpuRegister fs);
+ void AbsD(FpuRegister fd, FpuRegister fs);
void MovS(FpuRegister fd, FpuRegister fs);
void MovD(FpuRegister fd, FpuRegister fs);
void NegS(FpuRegister fd, FpuRegister fs);
void NegD(FpuRegister fd, FpuRegister fs);
+ void RoundLS(FpuRegister fd, FpuRegister fs);
+ void RoundLD(FpuRegister fd, FpuRegister fs);
+ void RoundWS(FpuRegister fd, FpuRegister fs);
+ void RoundWD(FpuRegister fd, FpuRegister fs);
+ void CeilLS(FpuRegister fd, FpuRegister fs);
+ void CeilLD(FpuRegister fd, FpuRegister fs);
+ void CeilWS(FpuRegister fd, FpuRegister fs);
+ void CeilWD(FpuRegister fd, FpuRegister fs);
+ void FloorLS(FpuRegister fd, FpuRegister fs);
+ void FloorLD(FpuRegister fd, FpuRegister fs);
+ void FloorWS(FpuRegister fd, FpuRegister fs);
+ void FloorWD(FpuRegister fd, FpuRegister fs);
+ void SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void RintS(FpuRegister fd, FpuRegister fs);
+ void RintD(FpuRegister fd, FpuRegister fs);
+ void ClassS(FpuRegister fd, FpuRegister fs);
+ void ClassD(FpuRegister fd, FpuRegister fs);
+ void MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
+ void MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
void Cvtsw(FpuRegister fd, FpuRegister fs);
void Cvtdw(FpuRegister fd, FpuRegister fs);
void Cvtsd(FpuRegister fd, FpuRegister fs);
void Cvtds(FpuRegister fd, FpuRegister fs);
+ void Cvtdl(FpuRegister fd, FpuRegister fs);
void Mfc1(GpuRegister rt, FpuRegister fs);
void Mtc1(GpuRegister rt, FpuRegister fs);
@@ -197,7 +240,10 @@ class Mips64Assembler FINAL : public Assembler {
void Addiu32(GpuRegister rt, GpuRegister rs, int32_t value, GpuRegister rtmp = AT);
void Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp = AT); // MIPS64
- void Bind(Label* label); // R6
+ void Bind(Label* label) OVERRIDE; // R6
+ void Jump(Label* label) OVERRIDE {
+ B(label);
+ }
void B(Label* label); // R6
void Jalr(Label* label, GpuRegister indirect_reg = RA); // R6
// TODO: implement common for R6 and non-R6 interface for conditional branches?
@@ -342,6 +388,8 @@ class Mips64Assembler FINAL : public Assembler {
private:
void EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, int shamt, int funct);
+ void EmitRsd(int opcode, GpuRegister rs, GpuRegister rd, int shamt, int funct);
+ void EmitRtd(int opcode, GpuRegister rt, GpuRegister rd, int shamt, int funct);
void EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm);
void EmitI21(int opcode, GpuRegister rs, uint32_t imm21);
void EmitJ(int opcode, uint32_t addr26);
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index e3962b4d69..04e815aa1d 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -158,6 +158,20 @@ void X86Assembler::bswapl(Register dst) {
EmitUint8(0xC8 + dst);
}
+void X86Assembler::bsfl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitRegisterOperand(dst, src);
+}
+
+void X86Assembler::bsfl(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitOperand(dst, src);
+}
+
void X86Assembler::bsrl(Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
@@ -1423,6 +1437,26 @@ void X86Assembler::shrd(Register dst, Register src, const Immediate& imm) {
}
+void X86Assembler::roll(Register reg, const Immediate& imm) {
+ EmitGenericShift(0, Operand(reg), imm);
+}
+
+
+void X86Assembler::roll(Register operand, Register shifter) {
+ EmitGenericShift(0, Operand(operand), shifter);
+}
+
+
+void X86Assembler::rorl(Register reg, const Immediate& imm) {
+ EmitGenericShift(1, Operand(reg), imm);
+}
+
+
+void X86Assembler::rorl(Register operand, Register shifter) {
+ EmitGenericShift(1, Operand(operand), shifter);
+}
+
+
void X86Assembler::negl(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF7);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 7d7b3d347b..93ecdf52fe 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -319,9 +319,16 @@ class X86Assembler FINAL : public Assembler {
void movntl(const Address& dst, Register src);
void bswapl(Register dst);
+ void bsfl(Register dst, Register src);
+ void bsfl(Register dst, const Address& src);
void bsrl(Register dst, Register src);
void bsrl(Register dst, const Address& src);
+ void rorl(Register reg, const Immediate& imm);
+ void rorl(Register operand, Register shifter);
+ void roll(Register reg, const Immediate& imm);
+ void roll(Register operand, Register shifter);
+
void movzxb(Register dst, ByteRegister src);
void movzxb(Register dst, const Address& src);
void movsxb(Register dst, ByteRegister src);
@@ -593,7 +600,10 @@ class X86Assembler FINAL : public Assembler {
//
int PreferredLoopAlignment() { return 16; }
void Align(int alignment, int offset);
- void Bind(Label* label);
+ void Bind(Label* label) OVERRIDE;
+ void Jump(Label* label) OVERRIDE {
+ jmp(label);
+ }
void Bind(NearLabel* label);
//
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 9ac54afc11..16f9db43fb 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -32,6 +32,10 @@ TEST(AssemblerX86, CreateBuffer) {
class AssemblerX86Test : public AssemblerTest<x86::X86Assembler, x86::Register,
x86::XmmRegister, x86::Immediate> {
+ public:
+ typedef AssemblerTest<x86::X86Assembler, x86::Register,
+ x86::XmmRegister, x86::Immediate> Base;
+
protected:
std::string GetArchitectureString() OVERRIDE {
return "x86";
@@ -230,6 +234,19 @@ TEST_F(AssemblerX86Test, RepMovsw) {
DriverStr(expected, "rep_movsw");
}
+TEST_F(AssemblerX86Test, Bsfl) {
+ DriverStr(RepeatRR(&x86::X86Assembler::bsfl, "bsfl %{reg2}, %{reg1}"), "bsfl");
+}
+
+TEST_F(AssemblerX86Test, BsflAddress) {
+ GetAssembler()->bsfl(x86::Register(x86::EDI), x86::Address(
+ x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
+ const char* expected =
+ "bsfl 0xc(%EDI,%EBX,4), %EDI\n";
+
+ DriverStr(expected, "bsfl_address");
+}
+
TEST_F(AssemblerX86Test, Bsrl) {
DriverStr(RepeatRR(&x86::X86Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl");
}
@@ -243,6 +260,52 @@ TEST_F(AssemblerX86Test, BsrlAddress) {
DriverStr(expected, "bsrl_address");
}
+// Rorl only allows CL as the shift count.
+std::string rorl_fn(AssemblerX86Test::Base* assembler_test, x86::X86Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86::Register*> registers = assembler_test->GetRegisters();
+
+ x86::Register shifter(x86::ECX);
+ for (auto reg : registers) {
+ assembler->rorl(*reg, shifter);
+ str << "rorl %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86Test, RorlReg) {
+ DriverFn(&rorl_fn, "rorl");
+}
+
+TEST_F(AssemblerX86Test, RorlImm) {
+ DriverStr(RepeatRI(&x86::X86Assembler::rorl, 1U, "rorl ${imm}, %{reg}"), "rorli");
+}
+
+// Roll only allows CL as the shift count.
+std::string roll_fn(AssemblerX86Test::Base* assembler_test, x86::X86Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86::Register*> registers = assembler_test->GetRegisters();
+
+ x86::Register shifter(x86::ECX);
+ for (auto reg : registers) {
+ assembler->roll(*reg, shifter);
+ str << "roll %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86Test, RollReg) {
+ DriverFn(&roll_fn, "roll");
+}
+
+TEST_F(AssemblerX86Test, RollImm) {
+ DriverStr(RepeatRI(&x86::X86Assembler::roll, 1U, "roll ${imm}, %{reg}"), "rolli");
+}
+
/////////////////
// Near labels //
/////////////////
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 88ea9900fe..89d7915f04 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1866,6 +1866,46 @@ void X86_64Assembler::sarq(CpuRegister operand, CpuRegister shifter) {
}
+void X86_64Assembler::roll(CpuRegister reg, const Immediate& imm) {
+ EmitGenericShift(false, 0, reg, imm);
+}
+
+
+void X86_64Assembler::roll(CpuRegister operand, CpuRegister shifter) {
+ EmitGenericShift(false, 0, operand, shifter);
+}
+
+
+void X86_64Assembler::rorl(CpuRegister reg, const Immediate& imm) {
+ EmitGenericShift(false, 1, reg, imm);
+}
+
+
+void X86_64Assembler::rorl(CpuRegister operand, CpuRegister shifter) {
+ EmitGenericShift(false, 1, operand, shifter);
+}
+
+
+void X86_64Assembler::rolq(CpuRegister reg, const Immediate& imm) {
+ EmitGenericShift(true, 0, reg, imm);
+}
+
+
+void X86_64Assembler::rolq(CpuRegister operand, CpuRegister shifter) {
+ EmitGenericShift(true, 0, operand, shifter);
+}
+
+
+void X86_64Assembler::rorq(CpuRegister reg, const Immediate& imm) {
+ EmitGenericShift(true, 1, reg, imm);
+}
+
+
+void X86_64Assembler::rorq(CpuRegister operand, CpuRegister shifter) {
+ EmitGenericShift(true, 1, operand, shifter);
+}
+
+
void X86_64Assembler::negl(CpuRegister reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(reg);
@@ -2140,6 +2180,38 @@ void X86_64Assembler::bswapq(CpuRegister dst) {
EmitUint8(0xC8 + dst.LowBits());
}
+void X86_64Assembler::bsfl(CpuRegister dst, CpuRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+void X86_64Assembler::bsfl(CpuRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitOperand(dst.LowBits(), src);
+}
+
+void X86_64Assembler::bsfq(CpuRegister dst, CpuRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+void X86_64Assembler::bsfq(CpuRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xBC);
+ EmitOperand(dst.LowBits(), src);
+}
+
void X86_64Assembler::bsrl(CpuRegister dst, CpuRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(dst, src);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index c38aba5e91..255f551675 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -633,11 +633,26 @@ class X86_64Assembler FINAL : public Assembler {
void bswapl(CpuRegister dst);
void bswapq(CpuRegister dst);
+ void bsfl(CpuRegister dst, CpuRegister src);
+ void bsfl(CpuRegister dst, const Address& src);
+ void bsfq(CpuRegister dst, CpuRegister src);
+ void bsfq(CpuRegister dst, const Address& src);
+
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 rorl(CpuRegister reg, const Immediate& imm);
+ void rorl(CpuRegister operand, CpuRegister shifter);
+ void roll(CpuRegister reg, const Immediate& imm);
+ void roll(CpuRegister operand, CpuRegister shifter);
+
+ void rorq(CpuRegister reg, const Immediate& imm);
+ void rorq(CpuRegister operand, CpuRegister shifter);
+ void rolq(CpuRegister reg, const Immediate& imm);
+ void rolq(CpuRegister operand, CpuRegister shifter);
+
void repne_scasw();
void repe_cmpsw();
void repe_cmpsl();
@@ -665,7 +680,10 @@ class X86_64Assembler FINAL : public Assembler {
//
int PreferredLoopAlignment() { return 16; }
void Align(int alignment, int offset);
- void Bind(Label* label);
+ void Bind(Label* label) OVERRIDE;
+ void Jump(Label* label) OVERRIDE {
+ jmp(label);
+ }
void Bind(NearLabel* label);
//
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 9e64b47c92..82378f724a 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -495,6 +495,98 @@ TEST_F(AssemblerX86_64Test, SarqImm) {
DriverStr(RepeatRI(&x86_64::X86_64Assembler::sarq, 1U, "sarq ${imm}, %{reg}"), "sarqi");
}
+// Rorl only allows CL as the shift count.
+std::string rorl_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+ x86_64::CpuRegister shifter(x86_64::RCX);
+ for (auto reg : registers) {
+ assembler->rorl(*reg, shifter);
+ str << "rorl %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RorlReg) {
+ DriverFn(&rorl_fn, "rorl");
+}
+
+TEST_F(AssemblerX86_64Test, RorlImm) {
+ DriverStr(Repeatri(&x86_64::X86_64Assembler::rorl, 1U, "rorl ${imm}, %{reg}"), "rorli");
+}
+
+// Roll only allows CL as the shift count.
+std::string roll_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+ x86_64::CpuRegister shifter(x86_64::RCX);
+ for (auto reg : registers) {
+ assembler->roll(*reg, shifter);
+ str << "roll %cl, %" << assembler_test->GetSecondaryRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RollReg) {
+ DriverFn(&roll_fn, "roll");
+}
+
+TEST_F(AssemblerX86_64Test, RollImm) {
+ DriverStr(Repeatri(&x86_64::X86_64Assembler::roll, 1U, "roll ${imm}, %{reg}"), "rolli");
+}
+
+// Rorq only allows CL as the shift count.
+std::string rorq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+ x86_64::CpuRegister shifter(x86_64::RCX);
+ for (auto reg : registers) {
+ assembler->rorq(*reg, shifter);
+ str << "rorq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RorqReg) {
+ DriverFn(&rorq_fn, "rorq");
+}
+
+TEST_F(AssemblerX86_64Test, RorqImm) {
+ DriverStr(RepeatRI(&x86_64::X86_64Assembler::rorq, 1U, "rorq ${imm}, %{reg}"), "rorqi");
+}
+
+// Rolq only allows CL as the shift count.
+std::string rolq_fn(AssemblerX86_64Test::Base* assembler_test, x86_64::X86_64Assembler* assembler) {
+ std::ostringstream str;
+
+ std::vector<x86_64::CpuRegister*> registers = assembler_test->GetRegisters();
+
+ x86_64::CpuRegister shifter(x86_64::RCX);
+ for (auto reg : registers) {
+ assembler->rolq(*reg, shifter);
+ str << "rolq %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
+ }
+
+ return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RolqReg) {
+ DriverFn(&rolq_fn, "rolq");
+}
+
+TEST_F(AssemblerX86_64Test, RolqImm) {
+ DriverStr(RepeatRI(&x86_64::X86_64Assembler::rolq, 1U, "rolq ${imm}, %{reg}"), "rolqi");
+}
+
TEST_F(AssemblerX86_64Test, CmpqRegs) {
DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq");
}
@@ -1141,6 +1233,44 @@ TEST_F(AssemblerX86_64Test, Bswapq) {
DriverStr(RepeatR(&x86_64::X86_64Assembler::bswapq, "bswap %{reg}"), "bswapq");
}
+TEST_F(AssemblerX86_64Test, Bsfl) {
+ DriverStr(Repeatrr(&x86_64::X86_64Assembler::bsfl, "bsfl %{reg2}, %{reg1}"), "bsfl");
+}
+
+TEST_F(AssemblerX86_64Test, BsflAddress) {
+ GetAssembler()->bsfl(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()->bsfl(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()->bsfl(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 =
+ "bsfl 0xc(%RDI,%RBX,4), %R10d\n"
+ "bsfl 0xc(%R10,%RBX,4), %edi\n"
+ "bsfl 0xc(%RDI,%R9,4), %edi\n";
+
+ DriverStr(expected, "bsfl_address");
+}
+
+TEST_F(AssemblerX86_64Test, Bsfq) {
+ DriverStr(RepeatRR(&x86_64::X86_64Assembler::bsfq, "bsfq %{reg2}, %{reg1}"), "bsfq");
+}
+
+TEST_F(AssemblerX86_64Test, BsfqAddress) {
+ GetAssembler()->bsfq(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()->bsfq(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()->bsfq(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 =
+ "bsfq 0xc(%RDI,%RBX,4), %R10\n"
+ "bsfq 0xc(%R10,%RBX,4), %RDI\n"
+ "bsfq 0xc(%RDI,%R9,4), %RDI\n";
+
+ DriverStr(expected, "bsfq_address");
+}
+
TEST_F(AssemblerX86_64Test, Bsrl) {
DriverStr(Repeatrr(&x86_64::X86_64Assembler::bsrl, "bsrl %{reg2}, %{reg1}"), "bsrl");
}