Skip to content

Commit 0ad30fa

Browse files
aartbikcommit-bot@chromium.org
authored andcommitted
[vm/assembler] Added cpufeatures, added LZCNT (IA32/X64)
Rationale: We are adding library support for bit operations: lowZeroBitCount/highZeroBitCount/nonZeroBitCount The added features will enable very efficient direct native implementations of these operations in the DartVM codegen. #38346 Change-Id: Id734a7590666c6abdc2a683a240094c6bf6cd46a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117768 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Aart Bik <[email protected]>
1 parent 4d97926 commit 0ad30fa

File tree

12 files changed

+138
-22
lines changed

12 files changed

+138
-22
lines changed

runtime/vm/compiler/assembler/assembler_ia32.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,13 +1514,23 @@ void Assembler::bsrl(Register dst, Register src) {
15141514
}
15151515

15161516
void Assembler::popcntl(Register dst, Register src) {
1517+
ASSERT(TargetCPUFeatures::popcnt_supported());
15171518
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
15181519
EmitUint8(0xF3);
15191520
EmitUint8(0x0F);
15201521
EmitUint8(0xB8);
15211522
EmitRegisterOperand(dst, src);
15221523
}
15231524

1525+
void Assembler::lzcntl(Register dst, Register src) {
1526+
ASSERT(TargetCPUFeatures::abm_supported());
1527+
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1528+
EmitUint8(0xF3);
1529+
EmitUint8(0x0F);
1530+
EmitUint8(0xBD);
1531+
EmitRegisterOperand(dst, src);
1532+
}
1533+
15241534
void Assembler::bt(Register base, Register offset) {
15251535
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
15261536
EmitUint8(0x0F);

runtime/vm/compiler/assembler/assembler_ia32.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ class Assembler : public AssemblerBase {
530530
void bsfl(Register dst, Register src);
531531
void bsrl(Register dst, Register src);
532532
void popcntl(Register dst, Register src);
533+
void lzcntl(Register dst, Register src);
533534

534535
void bt(Register base, Register offset);
535536
void bt(Register base, int bit);

runtime/vm/compiler/assembler/assembler_ia32_test.cc

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,15 +359,42 @@ ASSEMBLER_TEST_RUN(Bsr, test) {
359359
ASSEMBLER_TEST_GENERATE(Popcnt, assembler) {
360360
__ movl(ECX, Immediate(-1));
361361
__ popcntl(EAX, ECX);
362+
__ movl(ECX, Immediate(0xf));
363+
__ popcntl(ECX, ECX);
364+
__ addl(EAX, ECX);
362365
__ ret();
363366
}
364367

365368
ASSEMBLER_TEST_RUN(Popcnt, test) {
366369
typedef int (*PopcntCode)();
367-
EXPECT_EQ(32, reinterpret_cast<PopcntCode>(test->entry())());
370+
EXPECT_EQ(36, reinterpret_cast<PopcntCode>(test->entry())());
368371
EXPECT_DISASSEMBLY(
369372
"mov ecx,0x........\n"
370373
"popcnt eax,ecx\n"
374+
"mov ecx,0xf\n"
375+
"popcnt ecx,ecx\n"
376+
"add eax,ecx\n"
377+
"ret\n");
378+
}
379+
380+
ASSEMBLER_TEST_GENERATE(Lzcnt, assembler) {
381+
__ movl(ECX, Immediate(0x0f00));
382+
__ lzcntl(EAX, ECX);
383+
__ movl(ECX, Immediate(0x00f0));
384+
__ lzcntl(ECX, ECX);
385+
__ addl(EAX, ECX);
386+
__ ret();
387+
}
388+
389+
ASSEMBLER_TEST_RUN(Lzcnt, test) {
390+
typedef int (*LzcntCode)();
391+
EXPECT_EQ(44, reinterpret_cast<LzcntCode>(test->entry())());
392+
EXPECT_DISASSEMBLY(
393+
"mov ecx,0x...\n"
394+
"lzcnt eax,ecx\n"
395+
"mov ecx,0xf0\n"
396+
"lzcnt ecx,ecx\n"
397+
"add eax,ecx\n"
371398
"ret\n");
372399
}
373400

runtime/vm/compiler/assembler/assembler_x64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ class Assembler : public AssemblerBase {
337337
REGULAR_INSTRUCTION(bsf, 0xBC, 0x0F)
338338
REGULAR_INSTRUCTION(bsr, 0xBD, 0x0F)
339339
REGULAR_INSTRUCTION(popcnt, 0xB8, 0x0F, 0xF3)
340+
REGULAR_INSTRUCTION(lzcnt, 0xBD, 0x0F, 0xF3)
340341
#undef REGULAR_INSTRUCTION
341342
RA(Q, movsxd, 0x63)
342343
RR(Q, movsxd, 0x63)

runtime/vm/compiler/assembler/assembler_x64_test.cc

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ ASSEMBLER_TEST_RUN(Testb, test) {
552552
}
553553

554554
ASSEMBLER_TEST_GENERATE(Testb2, assembler) {
555-
Label done, ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8;
555+
Label done, ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8, ok9, ok10;
556556

557557
__ movq(RAX, Immediate(0xffffefff));
558558
__ bsrq(RCX, RAX);
@@ -607,6 +607,20 @@ ASSEMBLER_TEST_GENERATE(Testb2, assembler) {
607607
__ int3();
608608
__ Bind(&ok8);
609609

610+
__ movq(RAX, Immediate(0xf));
611+
__ popcntq(RCX, RAX);
612+
__ cmpq(RCX, Immediate(4));
613+
__ j(EQUAL, &ok9);
614+
__ int3();
615+
__ Bind(&ok9);
616+
617+
__ movq(RAX, Immediate(0x7fffeff0));
618+
__ lzcntq(RCX, RAX);
619+
__ cmpq(RCX, Immediate(33));
620+
__ j(EQUAL, &ok10);
621+
__ int3();
622+
__ Bind(&ok10);
623+
610624
__ movq(RAX, Immediate(42));
611625
__ ret();
612626
}
@@ -660,6 +674,18 @@ ASSEMBLER_TEST_RUN(Testb2, test) {
660674
"jz 0x................\n"
661675
"int3\n"
662676

677+
"movl rax,0xf\n"
678+
"popcntq rcx,rax\n"
679+
"cmpq rcx,4\n"
680+
"jz 0x................\n"
681+
"int3\n"
682+
683+
"movl rax,0x........\n"
684+
"lzcntq rcx,rax\n"
685+
"cmpq rcx,0x21\n"
686+
"jz 0x................\n"
687+
"int3\n"
688+
663689
"movl rax,0x2a\n"
664690
"ret\n");
665691
}

runtime/vm/compiler/assembler/disassembler_x86.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,9 @@ int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
14451445
} else if (opcode == 0xB8) {
14461446
// POPCNT.
14471447
current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1448+
} else if (opcode == 0xBD) {
1449+
// LZCNT (rep BSR encoding).
1450+
current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
14481451
} else {
14491452
UnimplementedInstruction();
14501453
}

runtime/vm/cpu_ia32.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,23 @@ const char* CPU::Id() {
2727
return "ia32";
2828
}
2929

30+
const char* HostCPUFeatures::hardware_ = nullptr;
3031
bool HostCPUFeatures::sse2_supported_ = false;
3132
bool HostCPUFeatures::sse4_1_supported_ = false;
32-
const char* HostCPUFeatures::hardware_ = NULL;
33+
bool HostCPUFeatures::popcnt_supported_ = false;
34+
bool HostCPUFeatures::abm_supported_ = false;
3335
#if defined(DEBUG)
3436
bool HostCPUFeatures::initialized_ = false;
3537
#endif
3638

3739
void HostCPUFeatures::Init() {
3840
CpuInfo::Init();
39-
4041
hardware_ = CpuInfo::GetCpuModel();
4142
sse2_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "sse2");
4243
sse4_1_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "sse4_1") ||
4344
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4.1");
44-
45+
popcnt_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "popcnt");
46+
abm_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "abm");
4547
#if defined(DEBUG)
4648
initialized_ = true;
4749
#endif

runtime/vm/cpu_ia32.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,21 @@ class HostCPUFeatures : public AllStatic {
3232
DEBUG_ASSERT(initialized_);
3333
return sse4_1_supported_ && FLAG_use_sse41;
3434
}
35+
static bool popcnt_supported() {
36+
DEBUG_ASSERT(initialized_);
37+
return popcnt_supported_;
38+
}
39+
static bool abm_supported() {
40+
DEBUG_ASSERT(initialized_);
41+
return abm_supported_;
42+
}
3543

3644
private:
37-
static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
38-
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
3945
static const char* hardware_;
4046
static bool sse2_supported_;
4147
static bool sse4_1_supported_;
48+
static bool popcnt_supported_;
49+
static bool abm_supported_;
4250
#if defined(DEBUG)
4351
static bool initialized_;
4452
#endif
@@ -51,6 +59,8 @@ class TargetCPUFeatures : public AllStatic {
5159
static const char* hardware() { return HostCPUFeatures::hardware(); }
5260
static bool sse2_supported() { return HostCPUFeatures::sse2_supported(); }
5361
static bool sse4_1_supported() { return HostCPUFeatures::sse4_1_supported(); }
62+
static bool popcnt_supported() { return HostCPUFeatures::popcnt_supported(); }
63+
static bool abm_supported() { return HostCPUFeatures::abm_supported(); }
5464
static bool double_truncate_round_supported() { return sse4_1_supported(); }
5565
};
5666

runtime/vm/cpu_x64.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ const char* CPU::Id() {
2727
return "x64";
2828
}
2929

30+
const char* HostCPUFeatures::hardware_ = nullptr;
3031
bool HostCPUFeatures::sse2_supported_ = true;
3132
bool HostCPUFeatures::sse4_1_supported_ = false;
32-
const char* HostCPUFeatures::hardware_ = NULL;
33+
bool HostCPUFeatures::popcnt_supported_ = false;
34+
bool HostCPUFeatures::abm_supported_ = false;
35+
3336
#if defined(DEBUG)
3437
bool HostCPUFeatures::initialized_ = false;
3538
#endif
@@ -39,7 +42,8 @@ void HostCPUFeatures::Init() {
3942
hardware_ = CpuInfo::GetCpuModel();
4043
sse4_1_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "sse4_1") ||
4144
CpuInfo::FieldContains(kCpuInfoFeatures, "sse4.1");
42-
45+
popcnt_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "popcnt");
46+
abm_supported_ = CpuInfo::FieldContains(kCpuInfoFeatures, "abm");
4347
#if defined(DEBUG)
4448
initialized_ = true;
4549
#endif

runtime/vm/cpu_x64.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,21 @@ class HostCPUFeatures : public AllStatic {
3232
DEBUG_ASSERT(initialized_);
3333
return sse4_1_supported_ && FLAG_use_sse41;
3434
}
35+
static bool popcnt_supported() {
36+
DEBUG_ASSERT(initialized_);
37+
return popcnt_supported_;
38+
}
39+
static bool abm_supported() {
40+
DEBUG_ASSERT(initialized_);
41+
return abm_supported_;
42+
}
3543

3644
private:
37-
static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
38-
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
3945
static const char* hardware_;
4046
static bool sse2_supported_;
4147
static bool sse4_1_supported_;
48+
static bool popcnt_supported_;
49+
static bool abm_supported_;
4250
#if defined(DEBUG)
4351
static bool initialized_;
4452
#endif
@@ -51,6 +59,8 @@ class TargetCPUFeatures : public AllStatic {
5159
static const char* hardware() { return HostCPUFeatures::hardware(); }
5260
static bool sse2_supported() { return HostCPUFeatures::sse2_supported(); }
5361
static bool sse4_1_supported() { return HostCPUFeatures::sse4_1_supported(); }
62+
static bool popcnt_supported() { return HostCPUFeatures::popcnt_supported(); }
63+
static bool abm_supported() { return HostCPUFeatures::abm_supported(); }
5464
static bool double_truncate_round_supported() { return false; }
5565
};
5666

0 commit comments

Comments
 (0)