Revert "Reland "[vm] Recognize int.trailingZeroBitCount/oneBitCount as graph-inlinable""

This reverts commit 415b040d6f.

Reason for revert: breaks riscv https://github.com/dart-lang/sdk/issues/63479

Original change's description:
> Reland "[vm] Recognize int.trailingZeroBitCount/oneBitCount as graph-inlinable"
>
> The previous attempt was reverted because it broke unoptimized JIT
> on ARM 32. This reland force-optimizes the two getters.
>
> Stacks on top of the int.{trailingZeroBitCount,oneBitCount} API CL
> (commit 754239b077). Both getters route through OTHER_RECOGNIZED_LIST
> when a hardware fast path is available; otherwise the newly added
> Dart bodies inline at call sites via vm:prefer-inline. The C++
> natives are removed.
>
> Backend codegen
> ---------------
> ARM64:     NEON CNT + UADDLV (popcount); RBIT + CLZ (ctz).
> ARM:       NEON CNT + VPADDL chain (popcount); RBIT + CLZ on the
>            register pair (ctz).
> x64:       popcntq when TargetCPUFeatures::popcnt_supported();
>            LoadImmediate(64) + rep_bsfq for ctz (decodes as tzcnt
>            on BMI1+, preserves dest on zero otherwise).
> RISC-V 64: cpop / ctz when RV_baseline includes Zbb.
>
> Per-arch availability is encapsulated in
> UnaryInt64OpInstr::IsSupported(Token::Kind).
>
> Apple M-series ARM64, AOT (us/iter, lower is better):
>   cardinality.swar              371
>   cardinality.accelerated       154    (2.4x)
>   forEachSetBit.swar          19031
>   forEachSetBit.accelerated    4988    (3.8x)
>   select.swar                   199
>   select.accelerated             77    (2.6x)
>   complementCardinality.swar    399
>   complementCardinality.accel   152    (2.6x)
>
> Work towards https://github.com/dart-lang/sdk/issues/6486 (popcount
> and ctz intrinsification).
>
> Work towards https://github.com/dart-lang/sdk/issues/1053 (efficient
> BitSet implementation).
>
> Fixes https://github.com/dart-lang/sdk/issues/52673
> Fixes https://github.com/dart-lang/sdk/issues/38346
> Fixes https://github.com/dart-lang/sdk/issues/63436
> Issue https://github.com/dart-lang/sdk/issues/10212
> Issue https://github.com/dart-lang/sdk/issues/5798
> TEST=tests/corelib/int_bit_count_test
>
> Cq-Include-Trybots: luci.dart.try:vm-linux-release-simarm-try,vm-ffi-qemu-linux-release-arm-try,vm-aot-linux-release-simarm_x64-try,vm-aot-linux-debug-simarm_x64-try,dart-sdk-linux-riscv64-try
> Change-Id: Ib812cbaec6e371b9720df7a543411f78e524cac1
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506060
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Auto-Submit: Modestas Valauskas <valauskasmodestas@gmail.com>
> Reviewed-by: Slava Egorov <vegorov@google.com>
> Commit-Queue: Martin Kustermann <kustermann@google.com>

Cq-Include-Trybots: luci.dart.try:vm-linux-release-simarm-try,vm-ffi-qemu-linux-release-arm-try,vm-aot-linux-release-simarm_x64-try,vm-aot-linux-debug-simarm_x64-try,dart-sdk-linux-riscv64-try
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Change-Id: Iaf11d03d394fa615098bed8fcdea38ba40c7e45f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/507520
Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Kevin Moore <kevmoo@google.com>
This commit is contained in:
Alexander Aprelev
2026-05-29 10:29:33 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 8d41c9b677
commit 5b0285866d
26 changed files with 29 additions and 424 deletions
+20
View File
@@ -267,6 +267,26 @@ DEFINE_NATIVE_ENTRY(Smi_bitLength, 0, 1) {
return Smi::New(result);
}
// Unified bit-count natives. Receiver is _IntegerImplementation, so the
// operand can be either Smi or Mint at runtime.
DEFINE_NATIVE_ENTRY(Integer_trailingZeroBitCount, 0, 1) {
const Integer& operand =
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
intptr_t result =
Utils::CountTrailingZeros64(static_cast<uint64_t>(operand.Value()));
ASSERT(Smi::IsValid(result));
return Smi::New(result);
}
DEFINE_NATIVE_ENTRY(Integer_oneBitCount, 0, 1) {
const Integer& operand =
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
intptr_t result =
Utils::CountOneBits64(static_cast<uint64_t>(operand.Value()));
ASSERT(Smi::IsValid(result));
return Smi::New(result);
}
// Should be kept in sync with il_*.cc EmitHashIntegerCodeSequence
uint32_t Multiply64Hash(int64_t ivalue) {
const uint64_t magic_constant = /*0x1b873593cc9e*/ 0x2d51;
+2
View File
@@ -65,6 +65,8 @@ namespace dart {
V(SendPort_sendInternal_, 2) \
V(Smi_bitNegate, 1) \
V(Smi_bitLength, 1) \
V(Integer_trailingZeroBitCount, 1) \
V(Integer_oneBitCount, 1) \
V(SuspendState_instantiateClosureWithFutureTypeArgument, 2) \
V(Mint_bitNegate, 1) \
V(Mint_bitLength, 1) \
@@ -1391,28 +1391,6 @@ void Assembler::vmvnq(QRegister qd, QRegister qm) {
EmitSIMDqqq(B25 | B24 | B23 | B10 | B8 | B7, kWordPair, qd, Q0, qm);
}
void Assembler::vcnt(DRegister dd, DRegister dm) {
EmitSIMDddd(B24 | B23 | B21 | B20 | B10 | B8, kByte, dd, D0, dm);
}
void Assembler::vpaddlu(OperandSize sz, DRegister dd, DRegister dm) {
int32_t size_bits = 0;
switch (sz) {
case kByte:
size_bits = 0;
break;
case kTwoBytes:
size_bits = B18;
break;
case kFourBytes:
size_bits = B19;
break;
default:
UNREACHABLE();
}
EmitSIMDddd(B24 | B23 | B21 | B20 | size_bits | B9 | B7, kByte, dd, D0, dm);
}
void Assembler::vminqs(QRegister qd, QRegister qn, QRegister qm) {
EmitSIMDqqq(B21 | B11 | B10 | B9 | B8, kSWord, qd, qn, qm);
}
@@ -725,9 +725,6 @@ class Assembler : public AssemblerBase {
void vandq(QRegister qd, QRegister qn, QRegister qm);
void vmvnq(QRegister qd, QRegister qm);
void vcnt(DRegister dd, DRegister dm);
void vpaddlu(OperandSize sz, DRegister dd, DRegister dm);
void vceqqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
void vceqqs(QRegister qd, QRegister qn, QRegister qm);
void vcgeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
@@ -1476,21 +1476,6 @@ class Assembler : public AssemblerBase {
void vrsqrtes(VRegister vd, VRegister vn) {
EmitSIMDTwoRegOp(VRSQRTES, vd, vn);
}
// CNT Vd.8B, Vn.8B: byte-wise population count.
void vcnt(VRegister vd, VRegister vn) {
const int32_t encoding = 0x0E205800 |
(static_cast<int32_t>(vn) << kVnShift) |
(static_cast<int32_t>(vd) << kVdShift);
Emit(encoding);
}
// UADDLV Hd, Vn.8B: sum across the 8 unsigned byte lanes of Vn into the
// 16-bit scalar in the low bits of Vd.
void vuaddlv(VRegister vd, VRegister vn) {
const int32_t encoding = 0x2E303800 |
(static_cast<int32_t>(vn) << kVnShift) |
(static_cast<int32_t>(vd) << kVdShift);
Emit(encoding);
}
void vdupw(VRegister vd, Register rn) {
const VRegister vn = static_cast<VRegister>(rn);
EmitSIMDCopyOp(VDUPI, vd, vn, kFourBytes, 0, 0);
@@ -2250,49 +2250,6 @@ ASSEMBLER_TEST_RUN(Rbit, test) {
"ret\n");
}
ASSEMBLER_TEST_GENERATE(Vcnt8B, assembler) {
// 0x0F has popcount 4 in the low byte; all other bytes are zero.
__ LoadImmediate(R1, 0xF);
__ fmovdr(V0, R1);
__ vcnt(V0, V0);
__ vmovrd(R0, V0, 0);
__ ret();
}
ASSEMBLER_TEST_RUN(Vcnt8B, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(4, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
EXPECT_DISASSEMBLY(
"movz r1, #0xf\n"
"fmovdr v0, r1\n"
"vcnt v0, v0\n"
"vmovrd r0, v0[0]\n"
"ret\n");
}
ASSEMBLER_TEST_GENERATE(VcntUaddlv8B, assembler) {
// Low 16 bits set: bytes {0xFF, 0xFF, 0, 0, 0, 0, 0, 0}.
// vcnt -> {8, 8, 0, ...}; vuaddlv -> 16 in H[0].
__ LoadImmediate(R1, 0xFFFF);
__ fmovdr(V0, R1);
__ vcnt(V0, V0);
__ vuaddlv(V0, V0);
__ fmovrs(R0, V0);
__ ret();
}
ASSEMBLER_TEST_RUN(VcntUaddlv8B, test) {
typedef int64_t (*Int64Return)() DART_UNUSED;
EXPECT_EQ(16, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
EXPECT_DISASSEMBLY(
"mov r1, 0xffff\n"
"fmovdr v0, r1\n"
"vcnt v0, v0\n"
"vuaddlv v0, v0\n"
"fmovrsw r0, v0\n"
"ret\n");
}
// Comparisons, branching.
ASSEMBLER_TEST_GENERATE(BranchALForward, assembler) {
Label l;
@@ -3015,47 +3015,6 @@ ASSEMBLER_TEST_RUN(Vmvnq, test) {
}
}
ASSEMBLER_TEST_GENERATE(Vcnt8B, assembler) {
if (TargetCPUFeatures::neon_supported()) {
__ LoadImmediate(R1, 0xF);
__ LoadImmediate(R2, 0);
__ vmovdrr(D0, R1, R2);
__ vcnt(D0, D0);
__ vmovrs(R0, S0);
}
__ Ret();
}
ASSEMBLER_TEST_RUN(Vcnt8B, test) {
EXPECT(test != nullptr);
if (TargetCPUFeatures::neon_supported()) {
typedef int (*Tst)() DART_UNUSED;
EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
}
ASSEMBLER_TEST_GENERATE(VcntVpaddlu8B, assembler) {
if (TargetCPUFeatures::neon_supported()) {
__ LoadImmediate(R1, 0xFFFF);
__ LoadImmediate(R2, 0);
__ vmovdrr(D0, R1, R2);
__ vcnt(D0, D0);
__ vpaddlu(kByte, D0, D0);
__ vpaddlu(kTwoBytes, D0, D0);
__ vpaddlu(kFourBytes, D0, D0);
__ vmovrs(R0, S0);
}
__ Ret();
}
ASSEMBLER_TEST_RUN(VcntVpaddlu8B, test) {
EXPECT(test != nullptr);
if (TargetCPUFeatures::neon_supported()) {
typedef int (*Tst)() DART_UNUSED;
EXPECT_EQ(16, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
}
ASSEMBLER_TEST_GENERATE(Vdupb, assembler) {
if (TargetCPUFeatures::neon_supported()) {
__ LoadImmediate(R0, 0x00000000);
@@ -359,7 +359,6 @@ class Assembler : public AssemblerBase {
REGULAR_INSTRUCTION(imul, 0xAF, 0x0F)
REGULAR_INSTRUCTION(bsf, 0xBC, 0x0F)
REGULAR_INSTRUCTION(bsr, 0xBD, 0x0F)
REGULAR_INSTRUCTION(rep_bsf, 0xBC, 0x0F, 0xF3)
REGULAR_INSTRUCTION(popcnt, 0xB8, 0x0F, 0xF3)
REGULAR_INSTRUCTION(lzcnt, 0xBD, 0x0F, 0xF3)
#undef REGULAR_INSTRUCTION
@@ -735,31 +735,6 @@ ASSEMBLER_TEST_RUN(Lzcnt, test) {
"ret\n");
}
ASSEMBLER_TEST_GENERATE(RepBsf, assembler) {
__ movq(RCX, Immediate(0));
__ LoadImmediate(RAX, Immediate(64));
__ rep_bsfq(RAX, RCX);
__ movq(RCX, Immediate(0xFF00));
__ LoadImmediate(RDX, Immediate(64));
__ rep_bsfq(RDX, RCX);
__ addq(RAX, RDX);
__ ret();
}
ASSEMBLER_TEST_RUN(RepBsf, test) {
typedef int64_t (*RepBsfCode)();
EXPECT_EQ(72, reinterpret_cast<RepBsfCode>(test->entry())());
EXPECT_DISASSEMBLY(
"movl rcx,0\n"
"movl rax,0x40\n"
"tzcntq rax,rcx\n"
"movl rcx,0xff00\n"
"movl rdx,0x40\n"
"tzcntq rdx,rcx\n"
"addq rax,rdx\n"
"ret\n");
}
struct JumpAddress {
uword filler1;
uword filler2;
@@ -1356,16 +1356,6 @@ void ARMDecoder::DecodeSIMDDataProcessing(Instr* instr) {
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) &&
(instr->Bits(16, 4) == 0)) {
Format(instr, "vmvnq 'qd, 'qm");
} else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
(instr->Bit(6) == 0) && (instr->Bit(7) == 0) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bits(16, 4) == 0)) {
Format(instr, "vcnt 'dd, 'dm");
} else if ((instr->Bits(8, 4) == 2) && (instr->Bit(4) == 0) &&
(instr->Bit(6) == 0) && (instr->Bit(7) == 1) &&
(instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
(instr->Bits(16, 2) == 0)) {
Format(instr, "vpaddlu 'dd, 'dm");
} else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
(instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
Format(instr, "vminqs 'qd, 'qn, 'qm");
@@ -1492,16 +1492,6 @@ void ARM64Decoder::DecodeSIMDTwoReg(Instr* instr) {
}
void ARM64Decoder::DecodeDPSimd1(Instr* instr) {
// CNT Vd.8B, Vn.8B (Q=0, U=0, size=00, opcode=00101).
if ((instr->InstructionBits() & 0xFFFFFC00) == 0x0E205800) {
Format(instr, "vcnt 'vd, 'vn");
return;
}
// UADDLV Hd, Vn.8B (Q=0, U=1, size=00, across-lanes ADDLV form).
if ((instr->InstructionBits() & 0xFFFFFC00) == 0x2E303800) {
Format(instr, "vuaddlv 'vd, 'vn");
return;
}
if (instr->IsSIMDCopyOp()) {
DecodeSIMDCopy(instr);
} else if (instr->IsSIMDThreeSameOp()) {
@@ -1478,9 +1478,6 @@ int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
} else if (opcode == 0xB8) {
// POPCNT.
current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
} else if (opcode == 0xBC) {
// TZCNT (rep BSF encoding).
current += PrintOperands("tzcnt", REG_OPER_OP_ORDER, current);
} else if (opcode == 0xBD) {
// LZCNT (rep BSR encoding).
current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
-12
View File
@@ -60,18 +60,6 @@ static IntegerPtr UnaryIntegerEvaluateRaw(const Integer& value,
return Integer::New(~value.Value(), Heap::kOld);
}
break;
case Token::kPOPCNT:
if (value.IsInteger()) {
return Integer::New(Utils::CountOneBits64(value.Value()), Heap::kOld);
}
break;
case Token::kCTZ:
if (value.IsInteger()) {
const int64_t v = value.Value();
return Integer::New(v == 0 ? 64 : Utils::CountTrailingZeros64(v),
Heap::kOld);
}
break;
default:
UNREACHABLE();
}
-28
View File
@@ -2263,34 +2263,6 @@ Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) {
return HasUses() ? this : nullptr;
}
bool UnaryInt64OpInstr::IsSupported(Token::Kind op_kind) {
switch (op_kind) {
case Token::kPOPCNT:
#if defined(TARGET_ARCH_ARM64)
return true;
#elif defined(TARGET_ARCH_ARM)
return TargetCPUFeatures::neon_supported();
#elif defined(TARGET_ARCH_X64)
return TargetCPUFeatures::popcnt_supported();
#elif defined(TARGET_ARCH_RISCV64)
return RV_baseline.Includes(RV_Zbb);
#else
return false;
#endif
case Token::kCTZ:
#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_X64) || \
defined(TARGET_ARCH_ARM)
return true;
#elif defined(TARGET_ARCH_RISCV64)
return RV_baseline.Includes(RV_Zbb);
#else
return false;
#endif
default:
return false;
}
}
UnaryIntegerOpInstr* UnaryIntegerOpInstr::Make(Representation representation,
Token::Kind op_kind,
Value* value,
+2 -6
View File
@@ -9200,8 +9200,7 @@ class UnaryIntegerOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
public:
UnaryIntegerOpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
: TemplateDefinition(deopt_id), op_kind_(op_kind) {
ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT) ||
(op_kind == Token::kPOPCNT) || (op_kind == Token::kCTZ));
ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT));
SetInputAt(0, value);
}
@@ -9295,12 +9294,9 @@ class UnaryInt64OpInstr : public UnaryIntegerOpInstr {
public:
UnaryInt64OpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
: UnaryIntegerOpInstr(op_kind, value, deopt_id) {
ASSERT(op_kind == Token::kBIT_NOT || op_kind == Token::kNEGATE ||
op_kind == Token::kPOPCNT || op_kind == Token::kCTZ);
ASSERT(op_kind == Token::kBIT_NOT || op_kind == Token::kNEGATE);
}
static bool IsSupported(Token::Kind op_kind);
virtual bool ComputeCanDeoptimize() const { return false; }
virtual Representation representation() const { return kUnboxedInt64; }
-25
View File
@@ -6742,31 +6742,6 @@ void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ sbc(out_hi, out_hi, compiler::Operand(out_hi));
__ sub(out_hi, out_hi, compiler::Operand(left_hi));
break;
case Token::kPOPCNT: {
__ vmovdrr(DTMP, left_lo, left_hi);
__ vcnt(DTMP, DTMP);
__ vpaddlu(compiler::kByte, DTMP, DTMP);
__ vpaddlu(compiler::kTwoBytes, DTMP, DTMP);
__ vpaddlu(compiler::kFourBytes, DTMP, DTMP);
__ vmovrs(out_lo, EvenSRegisterOf(DTMP));
__ mov(out_hi, compiler::Operand(0));
break;
}
case Token::kCTZ: {
compiler::Label hi_path, done;
__ cmp(left_lo, compiler::Operand(0));
__ b(&hi_path, EQ);
__ rbit(out_lo, left_lo);
__ clz(out_lo, out_lo);
__ b(&done);
__ Bind(&hi_path);
__ rbit(out_lo, left_hi);
__ clz(out_lo, out_lo);
__ add(out_lo, out_lo, compiler::Operand(32));
__ Bind(&done);
__ mov(out_hi, compiler::Operand(0));
break;
}
default:
UNREACHABLE();
}
-13
View File
@@ -5822,19 +5822,6 @@ void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case Token::kNEGATE:
__ sub(out, ZR, compiler::Operand(left));
break;
case Token::kPOPCNT: {
__ fmovdr(VTMP, left);
__ vcnt(VTMP, VTMP);
__ vuaddlv(VTMP, VTMP);
__ fmovrs(out, VTMP);
break;
}
case Token::kCTZ:
// RBIT(0) = 0 and CLZ(0) = 64, so the zero-input case naturally
// returns the platform width (matching the Dart API contract).
__ rbit(out, left);
__ clz(out, out);
break;
default:
UNREACHABLE();
}
-6
View File
@@ -6302,12 +6302,6 @@ void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case Token::kNEGATE:
__ neg(out, left);
break;
case Token::kPOPCNT:
__ cpop(out, left);
break;
case Token::kCTZ:
__ ctz(out, left);
break;
default:
UNREACHABLE();
}
+1 -26
View File
@@ -5976,14 +5976,11 @@ void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LocationSummary* UnaryInt64OpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = (op_kind() == Token::kCTZ) ? 1 : 0;
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_out(0, Location::SameAsFirstInput());
if (op_kind() == Token::kCTZ) {
summary->set_temp(0, Location::RequiresRegister());
}
return summary;
}
@@ -5998,28 +5995,6 @@ void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case Token::kNEGATE:
__ negq(left);
break;
case Token::kPOPCNT:
__ popcntq(out, left);
break;
case Token::kCTZ: {
// Intel Software Development Manual documents BSF behavior with zero
// input as undefined. However in reality all modern CPUs instead leave
// out unmodified - and compilers like LLVM rely on this behavior, so
// it makes sense for us to rely on it as well. This has an additional
// benefit of breaking false-data dependency on output register which
// can cause performance issues on some microarchitectures.
//
// |out| aliases |left| (SameAsFirstInput), so we stage through |tmp|
// to keep |left| readable as the BSF source.
const Register tmp = locs()->temp(0).reg();
__ LoadImmediate(tmp, compiler::Immediate(64));
// On CPUs supporting BMI2 extensions `rep bsf` will be interpreted as
// tzcnt, which is a faster instruction. On older CPUs rep-prefix will
// be ignored.
__ rep_bsfq(tmp, left);
__ movq(out, tmp);
break;
}
default:
UNREACHABLE();
}
@@ -1119,10 +1119,6 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
STORE_NATIVE_FIELD_NO_BARRIER(CASE)
#undef CASE
return true;
case MethodRecognizer::kInteger_trailingZeroBitCount:
return UnaryInt64OpInstr::IsSupported(Token::kCTZ);
case MethodRecognizer::kInteger_oneBitCount:
return UnaryInt64OpInstr::IsSupported(Token::kPOPCNT);
case MethodRecognizer::kDoubleToInteger:
case MethodRecognizer::kDoubleMod:
case MethodRecognizer::kDoubleRem:
@@ -1775,24 +1771,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
body += BuildDoubleHashCode();
body += Box(kUnboxedInt64);
} break;
case MethodRecognizer::kInteger_trailingZeroBitCount:
case MethodRecognizer::kInteger_oneBitCount: {
const auto op_kind =
kind == MethodRecognizer::kInteger_trailingZeroBitCount
? Token::kCTZ
: Token::kPOPCNT;
if (UnaryInt64OpInstr::IsSupported(op_kind)) {
ASSERT_EQUAL(function.NumParameters(), 1);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += UnboxTruncate(kUnboxedInt64);
Value* value = Pop();
UnaryInt64OpInstr* op =
new (Z) UnaryInt64OpInstr(op_kind, value, DeoptId::kNone);
Push(op);
body <<= op;
body += Box(kUnboxedInt64);
}
} break;
case MethodRecognizer::kFfiAsExternalTypedDataInt8:
case MethodRecognizer::kFfiAsExternalTypedDataInt16:
case MethodRecognizer::kFfiAsExternalTypedDataInt32:
@@ -76,10 +76,6 @@ namespace dart {
V(CoreLibrary, _WeakReference, set:_target, WeakReference_setTarget, \
0xc70c51ba) \
V(CoreLibrary, _Smi, get:hashCode, Smi_hashCode, 0x75c3b512) \
V(CoreLibrary, _IntegerImplementation, get:trailingZeroBitCount, \
Integer_trailingZeroBitCount, 0xea8b2826) \
V(CoreLibrary, _IntegerImplementation, get:oneBitCount, \
Integer_oneBitCount, 0x60c41821) \
V(CoreLibrary, _Mint, get:hashCode, Mint_hashCode, 0x75c3b512) \
V(CoreLibrary, _Double, get:hashCode, Double_hashCode, 0x75c3b8d3) \
V(CompactHashLibrary, _LinkedHashBase, get:_index, LinkedHashBase_getIndex, \
-2
View File
@@ -9383,8 +9383,6 @@ bool Function::RecognizedKindForceOptimize() const {
case MethodRecognizer::kStringBaseCodeUnitAt:
case MethodRecognizer::kUtf8DecoderScan:
case MethodRecognizer::kDouble_hashCode:
case MethodRecognizer::kInteger_trailingZeroBitCount:
case MethodRecognizer::kInteger_oneBitCount:
case MethodRecognizer::kTypedList_GetInt8:
case MethodRecognizer::kTypedList_SetInt8:
case MethodRecognizer::kTypedList_GetUint8:
-47
View File
@@ -3409,53 +3409,6 @@ void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
}
set_dregister_bits(dd, result);
} else if ((instr->Bits(8, 4) == 5) && (instr->Bit(7) == 0) &&
(instr->Bit(5) == 0) && (instr->Bit(4) == 0) &&
(instr->Bits(16, 4) == 0) && (instr->Bits(20, 2) == 3) &&
(instr->Bits(23, 5) == 7)) {
// Format(instr, "vcnt.8 'dd, 'dm");
DRegister dd = instr->DdField();
DRegister dm = instr->DmField();
uint64_t dm_value = static_cast<uint64_t>(get_dregister_bits(dm));
uint64_t result = 0;
uint8_t* in = reinterpret_cast<uint8_t*>(&dm_value);
uint8_t* out = reinterpret_cast<uint8_t*>(&result);
for (int i = 0; i < 8; i++) {
out[i] = Utils::CountOneBits32(in[i]);
}
set_dregister_bits(dd, static_cast<int64_t>(result));
} else if ((instr->Bits(8, 4) == 2) && (instr->Bit(7) == 1) &&
(instr->Bit(5) == 0) && (instr->Bit(4) == 0) &&
(instr->Bits(16, 2) == 0) && (instr->Bits(20, 2) == 3) &&
(instr->Bits(23, 5) == 7)) {
// Format(instr, "vpaddl.u<sz> 'dd, 'dm");
DRegister dd = instr->DdField();
DRegister dm = instr->DmField();
const int size = instr->Bits(18, 2);
uint64_t dm_value = static_cast<uint64_t>(get_dregister_bits(dm));
uint64_t result = 0;
if (size == 0) {
uint8_t* in = reinterpret_cast<uint8_t*>(&dm_value);
uint16_t* out = reinterpret_cast<uint16_t*>(&result);
for (int i = 0; i < 4; i++) {
out[i] = static_cast<uint16_t>(in[2 * i]) +
static_cast<uint16_t>(in[2 * i + 1]);
}
} else if (size == 1) {
uint16_t* in = reinterpret_cast<uint16_t*>(&dm_value);
uint32_t* out = reinterpret_cast<uint32_t*>(&result);
for (int i = 0; i < 2; i++) {
out[i] = static_cast<uint32_t>(in[2 * i]) +
static_cast<uint32_t>(in[2 * i + 1]);
}
} else if (size == 2) {
uint32_t* in = reinterpret_cast<uint32_t*>(&dm_value);
result = static_cast<uint64_t>(in[0]) + static_cast<uint64_t>(in[1]);
} else {
UnimplementedInstruction(instr);
return;
}
set_dregister_bits(dd, static_cast<int64_t>(result));
} else {
UnimplementedInstruction(instr);
}
-41
View File
@@ -3560,21 +3560,6 @@ void Simulator::DecodeSIMDTwoReg(Instr* instr) {
const VRegister vd = instr->VdField();
const VRegister vn = instr->VnField();
if ((U == 0) && (op == 5) && (sz == 0)) {
// Format(instr, "vcnt 'vd.{8,16}B, 'vn.{8,16}B");
const int lanes = (Q == 1) ? 16 : 8;
int64_t vn_bits[2] = {get_vregisterd(vn, 0), get_vregisterd(vn, 1)};
int64_t result[2] = {0, 0};
uint8_t* in = reinterpret_cast<uint8_t*>(&vn_bits[0]);
uint8_t* out = reinterpret_cast<uint8_t*>(&result[0]);
for (int i = 0; i < lanes; i++) {
out[i] = Utils::CountOneBits32(in[i]);
}
set_vregisterd(vd, 0, result[0]);
set_vregisterd(vd, 1, result[1]);
return;
}
if (Q != 1) {
UnimplementedInstruction(instr);
return;
@@ -3669,32 +3654,6 @@ void Simulator::DecodeSIMDTwoReg(Instr* instr) {
}
void Simulator::DecodeDPSimd1(Instr* instr) {
// UADDLV Hd, Vn.<T> — Advanced SIMD across-vector unsigned add long.
// Encoding: 0 Q 1 01110 sz 11000 00011 10 Vn Vd.
if ((instr->Bits(24, 5) == 0xE) && (instr->Bit(29) == 1) &&
(instr->Bits(17, 5) == 0x18) && (instr->Bits(12, 5) == 0x3) &&
(instr->Bits(10, 2) == 0x2)) {
const int32_t Q = instr->Bit(30);
const int32_t sz = instr->Bits(22, 2);
const VRegister vd = instr->VdField();
const VRegister vn = instr->VnField();
if (sz == 0) {
// Format(instr, "vuaddlv 'hd, 'vn.{8,16}B");
int64_t vn_bits[2] = {get_vregisterd(vn, 0), get_vregisterd(vn, 1)};
uint8_t* in = reinterpret_cast<uint8_t*>(&vn_bits[0]);
const int lanes = (Q == 1) ? 16 : 8;
uint32_t sum = 0;
for (int i = 0; i < lanes; i++) {
sum += in[i];
}
set_vregisterd(vd, 0, static_cast<int64_t>(sum));
set_vregisterd(vd, 1, 0);
return;
}
UnimplementedInstruction(instr);
return;
}
if (instr->IsSIMDCopyOp()) {
DecodeSIMDCopy(instr);
} else if (instr->IsSIMDThreeSameOp()) {
-4
View File
@@ -60,10 +60,6 @@ namespace dart {
TOK(kBIT_AND, "&", 11, kNoAttribute) \
TOK(kBIT_NOT, "~", 0, kNoAttribute) \
\
/* Bit-counting. */ \
TOK(kPOPCNT, "@popcnt", 0, kNoAttribute) \
TOK(kCTZ, "@ctz", 0, kNoAttribute) \
\
/* Shift operators. */ \
TOK(kSHL, "<<", 12, kNoAttribute) \
TOK(kSHR, ">>", 12, kNoAttribute) \