[ia32] Introduce BMI instructions.
BUG=v8:4015 LOG=n Review URL: https://codereview.chromium.org/1069683002 Cr-Commit-Position: refs/heads/master@{#27683}
This commit is contained in:
parent
a0486f1281
commit
dba47f6486
@ -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,10 +136,14 @@ 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",
|
||||
CpuFeatures::IsSupported(SSE3), CpuFeatures::IsSupported(SSE4_1),
|
||||
CpuFeatures::IsSupported(AVX), CpuFeatures::IsSupported(FMA3),
|
||||
CpuFeatures::IsSupported(ATOM));
|
||||
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, ®op, &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, ®op, &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, ®op, &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, ®op, &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, ®op, &rm);
|
||||
data += PrintRightXMMOperand(data);
|
||||
AppendToBuffer(",%s", NameOfXMMRegister(regop));
|
||||
} else if (b2 == 0xB8) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
|
||||
data += PrintRightOperand(data);
|
||||
} else if (b2 == 0xBC) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
|
||||
data += PrintRightOperand(data);
|
||||
} else if (b2 == 0xBD) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &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, ¬_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);
|
||||
|
Loading…
Reference in New Issue
Block a user