Commit dba47f64 authored by jing.bao's avatar jing.bao Committed by Commit bot

[ia32] Introduce BMI instructions.

BUG=v8:4015
LOG=n

Review URL: https://codereview.chromium.org/1069683002

Cr-Commit-Position: refs/heads/master@{#27683}
parent a0486f12
......@@ -122,6 +122,10 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
OSHasAVXSupport()) {
supported_ |= 1u << FMA3;
}
if (cpu.has_bmi1() && FLAG_enable_bmi1) supported_ |= 1u << BMI1;
if (cpu.has_bmi2() && FLAG_enable_bmi2) supported_ |= 1u << BMI2;
if (cpu.has_lzcnt() && FLAG_enable_lzcnt) supported_ |= 1u << LZCNT;
if (cpu.has_popcnt() && FLAG_enable_popcnt) supported_ |= 1u << POPCNT;
if (strcmp(FLAG_mcpu, "auto") == 0) {
if (cpu.is_atom()) supported_ |= 1u << ATOM;
} else if (strcmp(FLAG_mcpu, "atom") == 0) {
......@@ -132,9 +136,13 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
void CpuFeatures::PrintTarget() { }
void CpuFeatures::PrintFeatures() {
printf("SSE3=%d SSE4_1=%d AVX=%d FMA3=%d ATOM=%d\n",
printf(
"SSE3=%d SSE4_1=%d AVX=%d FMA3=%d BMI1=%d BMI2=%d LZCNT=%d POPCNT=%d "
"ATOM=%d\n",
CpuFeatures::IsSupported(SSE3), CpuFeatures::IsSupported(SSE4_1),
CpuFeatures::IsSupported(AVX), CpuFeatures::IsSupported(FMA3),
CpuFeatures::IsSupported(BMI1), CpuFeatures::IsSupported(BMI2),
CpuFeatures::IsSupported(LZCNT), CpuFeatures::IsSupported(POPCNT),
CpuFeatures::IsSupported(ATOM));
}
......@@ -2657,6 +2665,67 @@ void Assembler::vss(byte op, XMMRegister dst, XMMRegister src1,
}
void Assembler::bmi1(byte op, Register reg, Register vreg, const Operand& rm) {
DCHECK(IsEnabled(BMI1));
EnsureSpace ensure_space(this);
emit_vex_prefix(vreg, kLZ, kNone, k0F38, kW0);
EMIT(op);
emit_operand(reg, rm);
}
void Assembler::tzcnt(Register dst, const Operand& src) {
DCHECK(IsEnabled(BMI1));
EnsureSpace ensure_space(this);
EMIT(0xF3);
EMIT(0x0F);
EMIT(0xBC);
emit_operand(dst, src);
}
void Assembler::lzcnt(Register dst, const Operand& src) {
DCHECK(IsEnabled(LZCNT));
EnsureSpace ensure_space(this);
EMIT(0xF3);
EMIT(0x0F);
EMIT(0xBD);
emit_operand(dst, src);
}
void Assembler::popcnt(Register dst, const Operand& src) {
DCHECK(IsEnabled(POPCNT));
EnsureSpace ensure_space(this);
EMIT(0xF3);
EMIT(0x0F);
EMIT(0xB8);
emit_operand(dst, src);
}
void Assembler::bmi2(SIMDPrefix pp, byte op, Register reg, Register vreg,
const Operand& rm) {
DCHECK(IsEnabled(BMI2));
EnsureSpace ensure_space(this);
emit_vex_prefix(vreg, kLZ, pp, k0F38, kW0);
EMIT(op);
emit_operand(reg, rm);
}
void Assembler::rorx(Register dst, const Operand& src, byte imm8) {
DCHECK(IsEnabled(BMI2));
DCHECK(is_uint8(imm8));
Register vreg = {0}; // VEX.vvvv unused
EnsureSpace ensure_space(this);
emit_vex_prefix(vreg, kLZ, kF2, k0F3A, kW0);
EMIT(0xF0);
emit_operand(dst, src);
EMIT(imm8);
}
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
Register ireg = { reg.code() };
emit_operand(ireg, adr);
......@@ -2682,7 +2751,8 @@ void Assembler::emit_vex_prefix(XMMRegister vreg, VectorLength l, SIMDPrefix pp,
LeadingOpcode mm, VexW w) {
if (mm != k0F || w != kW0) {
EMIT(0xc4);
EMIT(0xc0 | mm);
// Change RXB from "110" to "111" to align with gdb disassembler.
EMIT(0xe0 | mm);
EMIT(w | ((~vreg.code() & 0xf) << 3) | l | pp);
} else {
EMIT(0xc5);
......@@ -2691,6 +2761,13 @@ void Assembler::emit_vex_prefix(XMMRegister vreg, VectorLength l, SIMDPrefix pp,
}
void Assembler::emit_vex_prefix(Register vreg, VectorLength l, SIMDPrefix pp,
LeadingOpcode mm, VexW w) {
XMMRegister ivreg = {vreg.code()};
emit_vex_prefix(ivreg, l, pp, mm, w);
}
void Assembler::GrowBuffer() {
DCHECK(buffer_overflow());
if (!own_buffer_) FATAL("external code buffer is too small");
......
......@@ -1314,6 +1314,90 @@ class Assembler : public AssemblerBase {
}
void vss(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
// BMI instruction
void andn(Register dst, Register src1, Register src2) {
andn(dst, src1, Operand(src2));
}
void andn(Register dst, Register src1, const Operand& src2) {
bmi1(0xf2, dst, src1, src2);
}
void bextr(Register dst, Register src1, Register src2) {
bextr(dst, Operand(src1), src2);
}
void bextr(Register dst, const Operand& src1, Register src2) {
bmi1(0xf7, dst, src2, src1);
}
void blsi(Register dst, Register src) { blsi(dst, Operand(src)); }
void blsi(Register dst, const Operand& src) {
Register ireg = {3};
bmi1(0xf3, ireg, dst, src);
}
void blsmsk(Register dst, Register src) { blsmsk(dst, Operand(src)); }
void blsmsk(Register dst, const Operand& src) {
Register ireg = {2};
bmi1(0xf3, ireg, dst, src);
}
void blsr(Register dst, Register src) { blsr(dst, Operand(src)); }
void blsr(Register dst, const Operand& src) {
Register ireg = {1};
bmi1(0xf3, ireg, dst, src);
}
void tzcnt(Register dst, Register src) { tzcnt(dst, Operand(src)); }
void tzcnt(Register dst, const Operand& src);
void lzcnt(Register dst, Register src) { lzcnt(dst, Operand(src)); }
void lzcnt(Register dst, const Operand& src);
void popcnt(Register dst, Register src) { popcnt(dst, Operand(src)); }
void popcnt(Register dst, const Operand& src);
void bzhi(Register dst, Register src1, Register src2) {
bzhi(dst, Operand(src1), src2);
}
void bzhi(Register dst, const Operand& src1, Register src2) {
bmi2(kNone, 0xf5, dst, src2, src1);
}
void mulx(Register dst1, Register dst2, Register src) {
mulx(dst1, dst2, Operand(src));
}
void mulx(Register dst1, Register dst2, const Operand& src) {
bmi2(kF2, 0xf6, dst1, dst2, src);
}
void pdep(Register dst, Register src1, Register src2) {
pdep(dst, src1, Operand(src2));
}
void pdep(Register dst, Register src1, const Operand& src2) {
bmi2(kF2, 0xf5, dst, src1, src2);
}
void pext(Register dst, Register src1, Register src2) {
pext(dst, src1, Operand(src2));
}
void pext(Register dst, Register src1, const Operand& src2) {
bmi2(kF3, 0xf5, dst, src1, src2);
}
void sarx(Register dst, Register src1, Register src2) {
sarx(dst, Operand(src1), src2);
}
void sarx(Register dst, const Operand& src1, Register src2) {
bmi2(kF3, 0xf7, dst, src2, src1);
}
void shlx(Register dst, Register src1, Register src2) {
shlx(dst, Operand(src1), src2);
}
void shlx(Register dst, const Operand& src1, Register src2) {
bmi2(k66, 0xf7, dst, src2, src1);
}
void shrx(Register dst, Register src1, Register src2) {
shrx(dst, Operand(src1), src2);
}
void shrx(Register dst, const Operand& src1, Register src2) {
bmi2(kF2, 0xf7, dst, src2, src1);
}
void rorx(Register dst, Register src, byte imm8) {
rorx(dst, Operand(src), imm8);
}
void rorx(Register dst, const Operand& src, byte imm8);
// Prefetch src position into cache level.
// Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a
// non-temporal
......@@ -1425,11 +1509,13 @@ class Assembler : public AssemblerBase {
// Emit vex prefix
enum SIMDPrefix { kNone = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 };
enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128 };
enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128, kLZ = kL128 };
enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 };
enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x2 };
enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x3 };
inline void emit_vex_prefix(XMMRegister v, VectorLength l, SIMDPrefix pp,
LeadingOpcode m, VexW w);
inline void emit_vex_prefix(Register v, VectorLength l, SIMDPrefix pp,
LeadingOpcode m, VexW w);
// labels
void print(Label* L);
......@@ -1441,6 +1527,11 @@ class Assembler : public AssemblerBase {
inline void emit_disp(Label* L, Displacement::Type type);
inline void emit_near_disp(Label* L);
// Most BMI instructions are similiar.
void bmi1(byte op, Register reg, Register vreg, const Operand& rm);
void bmi2(SIMDPrefix pp, byte op, Register reg, Register vreg,
const Operand& rm);
// record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
......
......@@ -299,6 +299,12 @@ class DisassemblerIA32 {
return (checked & 4) != 1;
}
bool vex_none() {
DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
return (checked & 3) == 0;
}
bool vex_66() {
DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
......@@ -804,6 +810,11 @@ int DisassemblerIA32::AVXInstruction(byte* data) {
NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0xf7:
AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%s", NameOfCPURegister(vvvv));
break;
default:
UnimplementedInstruction();
}
......@@ -881,6 +892,99 @@ int DisassemblerIA32::AVXInstruction(byte* data) {
default:
UnimplementedInstruction();
}
} else if (vex_none() && vex_0f38()) {
int mod, regop, rm, vvvv = vex_vreg();
get_modrm(*current, &mod, &regop, &rm);
const char* mnem = "?";
switch (opcode) {
case 0xf2:
AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
NameOfCPURegister(vvvv));
current += PrintRightOperand(current);
break;
case 0xf5:
AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%s", NameOfCPURegister(vvvv));
break;
case 0xf7:
AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%s", NameOfCPURegister(vvvv));
break;
case 0xf3:
switch (regop) {
case 1:
mnem = "blsr";
break;
case 2:
mnem = "blsmsk";
break;
case 3:
mnem = "blsi";
break;
default:
UnimplementedInstruction();
}
AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
current += PrintRightOperand(current);
mnem = "?";
break;
default:
UnimplementedInstruction();
}
} else if (vex_f2() && vex_0f38()) {
int mod, regop, rm, vvvv = vex_vreg();
get_modrm(*current, &mod, &regop, &rm);
switch (opcode) {
case 0xf5:
AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
NameOfCPURegister(vvvv));
current += PrintRightOperand(current);
break;
case 0xf6:
AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
NameOfCPURegister(vvvv));
current += PrintRightOperand(current);
break;
case 0xf7:
AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%s", NameOfCPURegister(vvvv));
break;
default:
UnimplementedInstruction();
}
} else if (vex_f3() && vex_0f38()) {
int mod, regop, rm, vvvv = vex_vreg();
get_modrm(*current, &mod, &regop, &rm);
switch (opcode) {
case 0xf5:
AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
NameOfCPURegister(vvvv));
current += PrintRightOperand(current);
break;
case 0xf7:
AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%s", NameOfCPURegister(vvvv));
break;
default:
UnimplementedInstruction();
}
} else if (vex_f2() && vex_0f3a()) {
int mod, regop, rm;
get_modrm(*current, &mod, &regop, &rm);
switch (opcode) {
case 0xf0:
AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(",%d", *current & 0x1f);
current += 1;
break;
default:
UnimplementedInstruction();
}
} else {
UnimplementedInstruction();
}
......@@ -1900,6 +2004,24 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
get_modrm(*data, &mod, &regop, &rm);
data += PrintRightXMMOperand(data);
AppendToBuffer(",%s", NameOfXMMRegister(regop));
} else if (b2 == 0xB8) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
data += PrintRightOperand(data);
} else if (b2 == 0xBC) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
data += PrintRightOperand(data);
} else if (b2 == 0xBD) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
data += PrintRightOperand(data);
} else {
const char* mnem = "?";
switch (b2) {
......
......@@ -2450,7 +2450,11 @@ void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
// TODO(intel): Add support for LZCNT (with ABM/BMI1).
if (CpuFeatures::IsSupported(LZCNT)) {
CpuFeatureScope scope(this, LZCNT);
lzcnt(dst, src);
return;
}
Label not_zero_src;
bsr(dst, src);
j(not_zero, &not_zero_src, Label::kNear);
......
......@@ -1044,6 +1044,352 @@ TEST(AssemblerX64FMA_ss) {
}
TEST(AssemblerIa32BMI1) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(BMI1)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[1024];
MacroAssembler assm(isolate, buffer, sizeof buffer);
{
CpuFeatureScope fscope(&assm, BMI1);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
// andn
__ mov(edx, Immediate(0x20000000u));
__ mov(eax, Immediate(1)); // Test number
__ andn(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x55667788u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ andn(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667788u)); // expected result
__ j(not_equal, &exit);
// bextr
__ mov(edx, Immediate(0x00002808u));
__ inc(eax);
__ bextr(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x00556677u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ bextr(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x00556677u)); // expected result
__ j(not_equal, &exit);
// blsi
__ inc(eax);
__ blsi(ebx, ecx);
__ cmp(ebx, Immediate(0x00000008u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsi(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x00000008u)); // expected result
__ j(not_equal, &exit);
// blsmsk
__ inc(eax);
__ blsmsk(ebx, ecx);
__ cmp(ebx, Immediate(0x0000000fu)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsmsk(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x0000000fu)); // expected result
__ j(not_equal, &exit);
// blsr
__ inc(eax);
__ blsr(ebx, ecx);
__ cmp(ebx, Immediate(0x55667780u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ blsr(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667780u)); // expected result
__ j(not_equal, &exit);
// tzcnt
__ inc(eax);
__ tzcnt(ebx, ecx);
__ cmp(ebx, Immediate(3)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ tzcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(3)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
OFStream os(stdout);
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32LZCNT) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(LZCNT)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, buffer, sizeof buffer);
{
CpuFeatureScope fscope(&assm, LZCNT);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
__ mov(eax, Immediate(1)); // Test number
__ lzcnt(ebx, ecx);
__ cmp(ebx, Immediate(1)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ lzcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(1)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
OFStream os(stdout);
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32POPCNT) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(POPCNT)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[256];
MacroAssembler assm(isolate, buffer, sizeof buffer);
{
CpuFeatureScope fscope(&assm, POPCNT);
Label exit;
__ push(ebx); // save ebx
__ mov(ecx, Immediate(0x11111100u)); // source operand
__ push(ecx); // For memory operand
__ mov(eax, Immediate(1)); // Test number
__ popcnt(ebx, ecx);
__ cmp(ebx, Immediate(6)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ popcnt(ebx, Operand(esp, 0));
__ cmp(ebx, Immediate(6)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
OFStream os(stdout);
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32BMI2) {
CcTest::InitializeVM();
if (!CpuFeatures::IsSupported(BMI2)) return;
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
HandleScope scope(isolate);
v8::internal::byte buffer[2048];
MacroAssembler assm(isolate, buffer, sizeof buffer);
{
CpuFeatureScope fscope(&assm, BMI2);
Label exit;
__ push(ebx); // save ebx
__ push(esi); // save esi
__ mov(ecx, Immediate(0x55667788u)); // source operand
__ push(ecx); // For memory operand
// bzhi
__ mov(edx, Immediate(9));
__ mov(eax, Immediate(1)); // Test number
__ bzhi(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x00000188u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ bzhi(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x00000188u)); // expected result
__ j(not_equal, &exit);
// mulx
__ mov(edx, Immediate(0x00001000u));
__ inc(eax);
__ mulx(ebx, esi, ecx);
__ cmp(ebx, Immediate(0x00000556u)); // expected result
__ j(not_equal, &exit);
__ cmp(esi, Immediate(0x67788000u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ mulx(ebx, esi, Operand(esp, 0));
__ cmp(ebx, Immediate(0x00000556u)); // expected result
__ j(not_equal, &exit);
__ cmp(esi, Immediate(0x67788000u)); // expected result
__ j(not_equal, &exit);
// pdep
__ mov(edx, Immediate(0xfffffff0u));
__ inc(eax);
__ pdep(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x55667400u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ pdep(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x55667400u)); // expected result
__ j(not_equal, &exit);
// pext
__ mov(edx, Immediate(0xfffffff0u));
__ inc(eax);
__ pext(ebx, edx, ecx);
__ cmp(ebx, Immediate(0x0000fffeu)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ pext(ebx, edx, Operand(esp, 0));
__ cmp(ebx, Immediate(0x0000fffeu)); // expected result
__ j(not_equal, &exit);
// sarx
__ mov(edx, Immediate(4));
__ inc(eax);
__ sarx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ sarx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
// shlx
__ mov(edx, Immediate(4));
__ inc(eax);
__ shlx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x56677880u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ shlx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x56677880u)); // expected result
__ j(not_equal, &exit);
// shrx
__ mov(edx, Immediate(4));
__ inc(eax);
__ shrx(ebx, ecx, edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ shrx(ebx, Operand(esp, 0), edx);
__ cmp(ebx, Immediate(0x05566778u)); // expected result
__ j(not_equal, &exit);
// rorx
__ inc(eax);
__ rorx(ebx, ecx, 0x4);
__ cmp(ebx, Immediate(0x85566778u)); // expected result
__ j(not_equal, &exit);
__ inc(eax);
__ rorx(ebx, Operand(esp, 0), 0x4);
__ cmp(ebx, Immediate(0x85566778u)); // expected result
__ j(not_equal, &exit);
__ xor_(eax, eax);
__ bind(&exit);
__ pop(ecx);
__ pop(esi);
__ pop(ebx);
__ ret(0);
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
OFStream os(stdout);
code->Print(os);
#endif
F0 f = FUNCTION_CAST<F0>(code->entry());
CHECK_EQ(0, f());
}
TEST(AssemblerIa32JumpTables1) {
// Test jump tables with forward jumps.
CcTest::InitializeVM();
......
......@@ -590,6 +590,66 @@ TEST(DisasmIa320) {
}
}
// BMI1 instructions
{
if (CpuFeatures::IsSupported(BMI1)) {
CpuFeatureScope scope(&assm, BMI1);
__ andn(eax, ebx, ecx);
__ andn(eax, ebx, Operand(ebx, ecx, times_4, 10000));
__ bextr(eax, ebx, ecx);
__ bextr(eax, Operand(ebx, ecx, times_4, 10000), ebx);
__ blsi(eax, ebx);
__ blsi(eax, Operand(ebx, ecx, times_4, 10000));
__ blsmsk(eax, ebx);
__ blsmsk(eax, Operand(ebx, ecx, times_4, 10000));
__ blsr(eax, ebx);
__ blsr(eax, Operand(ebx, ecx, times_4, 10000));
__ tzcnt(eax, ebx);
__ tzcnt(eax, Operand(ebx, ecx, times_4, 10000));
}
}
// LZCNT instructions
{
if (CpuFeatures::IsSupported(LZCNT)) {
CpuFeatureScope scope(&assm, LZCNT);
__ lzcnt(eax, ebx);
__ lzcnt(eax, Operand(ebx, ecx, times_4, 10000));
}
}
// POPCNT instructions
{
if (CpuFeatures::IsSupported(POPCNT)) {
CpuFeatureScope scope(&assm, POPCNT);
__ popcnt(eax, ebx);
__ popcnt(eax, Operand(ebx, ecx, times_4, 10000));
}
}
// BMI2 instructions
{
if (CpuFeatures::IsSupported(BMI2)) {
CpuFeatureScope scope(&assm, BMI2);
__ bzhi(eax, ebx, ecx);
__ bzhi(eax, Operand(ebx, ecx, times_4, 10000), ebx);
__ mulx(eax, ebx, ecx);
__ mulx(eax, ebx, Operand(ebx, ecx, times_4, 10000));
__ pdep(eax, ebx, ecx);
__ pdep(eax, ebx, Operand(ebx, ecx, times_4, 10000));
__ pext(eax, ebx, ecx);
__ pext(eax, ebx, Operand(ebx, ecx, times_4, 10000));
__ sarx(eax, ebx, ecx);
__ sarx(eax, Operand(ebx, ecx, times_4, 10000), ebx);
__ shlx(eax, ebx, ecx);
__ shlx(eax, Operand(ebx, ecx, times_4, 10000), ebx);
__ shrx(eax, ebx, ecx);
__ shrx(eax, Operand(ebx, ecx, times_4, 10000), ebx);
__ rorx(eax, ebx, 31);
__ rorx(eax, Operand(ebx, ecx, times_4, 10000), 31);
}
}
// xchg.
{
__ xchg(eax, eax);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment