Skip to content

Commit 0585f9e

Browse files
committed
[JSC] Add signbit test code generation on ARM64
https://bugs.webkit.org/show_bug.cgi?id=298914 rdar://160658477 Reviewed by Justin Michaud and Dan Hecht. This patch adds code generation via tbnz etc. when the condition is met. Like, v < 0 => checking signbit via tbz v >= 0 => checking signbit via tbnz * Source/JavaScriptCore/assembler/MacroAssemblerARM64.h: (JSC::MacroAssemblerARM64::branch32): (JSC::MacroAssemblerARM64::branch64): (JSC::MacroAssemblerARM64::attemptToFoldToBitTest32): (JSC::MacroAssemblerARM64::attemptToFoldToBitTest64): * Source/JavaScriptCore/assembler/testmasm.cpp: (int32Operands): (int64Operands): (JSC::testBranch32): (JSC::testBranch64): Canonical link: https://commits.webkit.org/300030@main
1 parent f96d509 commit 0585f9e

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed

Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4093,6 +4093,10 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
40934093
Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
40944094
{
40954095
auto immediate = right.m_value;
4096+
4097+
if (auto result = attemptToFoldToBitTest32(cond, left, immediate))
4098+
return result.value();
4099+
40964100
if (!immediate) {
40974101
if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
40984102
return branchTest32(*resultCondition, left, left);
@@ -4166,6 +4170,10 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
41664170
Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm32 right)
41674171
{
41684172
auto immediate = right.m_value;
4173+
4174+
if (auto result = attemptToFoldToBitTest64(cond, left, immediate))
4175+
return result.value();
4176+
41694177
if (!immediate) {
41704178
if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
41714179
return branchTest64(*resultCondition, left, left);
@@ -4187,6 +4195,10 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
41874195
Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
41884196
{
41894197
auto immediate = right.m_value;
4198+
4199+
if (auto result = attemptToFoldToBitTest64(cond, left, immediate))
4200+
return result.value();
4201+
41904202
if (!immediate) {
41914203
if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
41924204
return branchTest64(*resultCondition, left, left);
@@ -6434,6 +6446,107 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
64346446
}
64356447
}
64366448

6449+
std::optional<Jump> attemptToFoldToBitTest32(RelationalCondition cond, RegisterID left, int32_t immediate)
6450+
{
6451+
int32_t signbit = static_cast<int32_t>(1U << (32 - 1));
6452+
switch (cond) {
6453+
case LessThan:
6454+
// left < 0
6455+
if (!immediate)
6456+
return branchTest32(NonZero, left, TrustedImm32(signbit));
6457+
break;
6458+
case LessThanOrEqual:
6459+
// left <= -1
6460+
if (immediate == -1)
6461+
return branchTest32(NonZero, left, TrustedImm32(signbit));
6462+
break;
6463+
case GreaterThan:
6464+
// left > -1
6465+
if (immediate == -1)
6466+
return branchTest32(Zero, left, TrustedImm32(signbit));
6467+
break;
6468+
case GreaterThanOrEqual:
6469+
// left >= 0
6470+
if (!immediate)
6471+
return branchTest32(Zero, left, TrustedImm32(signbit));
6472+
break;
6473+
6474+
case Below:
6475+
// left < signbit
6476+
if (immediate == signbit)
6477+
return branchTest32(Zero, left, TrustedImm32(signbit));
6478+
break;
6479+
case BelowOrEqual:
6480+
// left <= (signbit - 1)
6481+
if (immediate == (signbit - 1))
6482+
return branchTest32(Zero, left, TrustedImm32(signbit));
6483+
break;
6484+
case Above:
6485+
// left > (signbit - 1)
6486+
if (immediate == (signbit - 1))
6487+
return branchTest32(NonZero, left, TrustedImm32(signbit));
6488+
break;
6489+
case AboveOrEqual:
6490+
// left >= signbit
6491+
if (immediate == signbit)
6492+
return branchTest32(NonZero, left, TrustedImm32(signbit));
6493+
break;
6494+
default:
6495+
break;
6496+
}
6497+
return std::nullopt;
6498+
}
6499+
6500+
std::optional<Jump> attemptToFoldToBitTest64(RelationalCondition cond, RegisterID left, int64_t immediate)
6501+
{
6502+
int64_t signbit = static_cast<int64_t>(1ULL << (64 - 1));
6503+
switch (cond) {
6504+
case LessThan:
6505+
// left < 0
6506+
if (!immediate)
6507+
return branchTest64(NonZero, left, TrustedImm64(signbit));
6508+
break;
6509+
case LessThanOrEqual:
6510+
// left <= -1
6511+
if (immediate == -1)
6512+
return branchTest64(NonZero, left, TrustedImm64(signbit));
6513+
break;
6514+
case GreaterThan:
6515+
// left > -1
6516+
if (immediate == -1)
6517+
return branchTest64(Zero, left, TrustedImm64(signbit));
6518+
break;
6519+
case GreaterThanOrEqual:
6520+
// left >= 0
6521+
if (!immediate)
6522+
return branchTest64(Zero, left, TrustedImm64(signbit));
6523+
break;
6524+
case Below:
6525+
// left < signbit
6526+
if (immediate == signbit)
6527+
return branchTest64(Zero, left, TrustedImm64(signbit));
6528+
break;
6529+
case BelowOrEqual:
6530+
// left <= (signbit - 1)
6531+
if (immediate == (signbit - 1))
6532+
return branchTest64(Zero, left, TrustedImm64(signbit));
6533+
break;
6534+
case Above:
6535+
// left > (signbit - 1)
6536+
if (immediate == (signbit - 1))
6537+
return branchTest64(NonZero, left, TrustedImm64(signbit));
6538+
break;
6539+
case AboveOrEqual:
6540+
// left >= signbit
6541+
if (immediate == signbit)
6542+
return branchTest64(NonZero, left, TrustedImm64(signbit));
6543+
break;
6544+
default:
6545+
break;
6546+
}
6547+
return std::nullopt;
6548+
}
6549+
64376550
template<PtrTag resultTag, PtrTag locationTag>
64386551
static CodePtr<resultTag> readCallTarget(CodeLocationCall<locationTag> call)
64396552
{

Source/JavaScriptCore/assembler/testmasm.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static Vector<int32_t> int32Operands()
108108
42,
109109
-42,
110110
64,
111+
static_cast<int32_t>(0x80000000U),
111112
std::numeric_limits<int32_t>::max(),
112113
std::numeric_limits<int32_t>::min(),
113114
};
@@ -155,6 +156,7 @@ static Vector<int64_t> int64Operands()
155156
42,
156157
-42,
157158
64,
159+
static_cast<int64_t>(0x8000000000000000ULL),
158160
std::numeric_limits<int32_t>::max(),
159161
std::numeric_limits<int32_t>::min(),
160162
std::numeric_limits<int64_t>::max(),
@@ -377,6 +379,128 @@ void testBranchTruncateDoubleToInt32(double val, int32_t expected)
377379
}), expected);
378380
}
379381

382+
static void testBranch32()
383+
{
384+
auto compare = [](CCallHelpers::RelationalCondition cond, int32_t v1, int32_t v2) -> int {
385+
switch (cond) {
386+
case CCallHelpers::LessThan:
387+
return !!(static_cast<int32_t>(v1) < static_cast<int32_t>(v2));
388+
case CCallHelpers::LessThanOrEqual:
389+
return !!(static_cast<int32_t>(v1) <= static_cast<int32_t>(v2));
390+
case CCallHelpers::GreaterThan:
391+
return !!(static_cast<int32_t>(v1) > static_cast<int32_t>(v2));
392+
case CCallHelpers::GreaterThanOrEqual:
393+
return !!(static_cast<int32_t>(v1) >= static_cast<int32_t>(v2));
394+
case CCallHelpers::Below:
395+
return !!(static_cast<uint32_t>(v1) < static_cast<uint32_t>(v2));
396+
case CCallHelpers::BelowOrEqual:
397+
return !!(static_cast<uint32_t>(v1) <= static_cast<uint32_t>(v2));
398+
case CCallHelpers::Above:
399+
return !!(static_cast<uint32_t>(v1) > static_cast<uint32_t>(v2));
400+
case CCallHelpers::AboveOrEqual:
401+
return !!(static_cast<uint32_t>(v1) >= static_cast<uint32_t>(v2));
402+
case CCallHelpers::Equal:
403+
return !!(static_cast<uint32_t>(v1) == static_cast<uint32_t>(v2));
404+
case CCallHelpers::NotEqual:
405+
return !!(static_cast<uint32_t>(v1) != static_cast<uint32_t>(v2));
406+
}
407+
return 0;
408+
};
409+
410+
for (auto value : int32Operands()) {
411+
for (auto value2 : int32Operands()) {
412+
auto tryTest = [&](CCallHelpers::RelationalCondition cond) {
413+
auto test = compile([=](CCallHelpers& jit) {
414+
emitFunctionPrologue(jit);
415+
416+
auto branch = jit.branch32(cond, GPRInfo::argumentGPR0, CCallHelpers::TrustedImm32(value2));
417+
jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
418+
auto done = jit.jump();
419+
branch.link(&jit);
420+
jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
421+
done.link(&jit);
422+
423+
emitFunctionEpilogue(jit);
424+
jit.ret();
425+
});
426+
CHECK_EQ(invoke<int>(test, value), compare(cond, value, value2));
427+
};
428+
tryTest(CCallHelpers::LessThan);
429+
tryTest(CCallHelpers::LessThanOrEqual);
430+
tryTest(CCallHelpers::GreaterThan);
431+
tryTest(CCallHelpers::GreaterThanOrEqual);
432+
tryTest(CCallHelpers::Below);
433+
tryTest(CCallHelpers::BelowOrEqual);
434+
tryTest(CCallHelpers::Above);
435+
tryTest(CCallHelpers::AboveOrEqual);
436+
tryTest(CCallHelpers::Equal);
437+
tryTest(CCallHelpers::NotEqual);
438+
}
439+
}
440+
}
441+
442+
#if CPU(X86_64) || CPU(ARM64)
443+
static void testBranch64()
444+
{
445+
auto compare = [](CCallHelpers::RelationalCondition cond, int64_t v1, int64_t v2) -> int {
446+
switch (cond) {
447+
case CCallHelpers::LessThan:
448+
return !!(static_cast<int64_t>(v1) < static_cast<int64_t>(v2));
449+
case CCallHelpers::LessThanOrEqual:
450+
return !!(static_cast<int64_t>(v1) <= static_cast<int64_t>(v2));
451+
case CCallHelpers::GreaterThan:
452+
return !!(static_cast<int64_t>(v1) > static_cast<int64_t>(v2));
453+
case CCallHelpers::GreaterThanOrEqual:
454+
return !!(static_cast<int64_t>(v1) >= static_cast<int64_t>(v2));
455+
case CCallHelpers::Below:
456+
return !!(static_cast<uint64_t>(v1) < static_cast<uint64_t>(v2));
457+
case CCallHelpers::BelowOrEqual:
458+
return !!(static_cast<uint64_t>(v1) <= static_cast<uint64_t>(v2));
459+
case CCallHelpers::Above:
460+
return !!(static_cast<uint64_t>(v1) > static_cast<uint64_t>(v2));
461+
case CCallHelpers::AboveOrEqual:
462+
return !!(static_cast<uint64_t>(v1) >= static_cast<uint64_t>(v2));
463+
case CCallHelpers::Equal:
464+
return !!(static_cast<uint64_t>(v1) == static_cast<uint64_t>(v2));
465+
case CCallHelpers::NotEqual:
466+
return !!(static_cast<uint64_t>(v1) != static_cast<uint64_t>(v2));
467+
}
468+
return 0;
469+
};
470+
471+
for (auto value : int64Operands()) {
472+
for (auto value2 : int64Operands()) {
473+
auto tryTest = [&](CCallHelpers::RelationalCondition cond) {
474+
auto test = compile([=](CCallHelpers& jit) {
475+
emitFunctionPrologue(jit);
476+
477+
auto branch = jit.branch64(cond, GPRInfo::argumentGPR0, CCallHelpers::TrustedImm64(value2));
478+
jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
479+
auto done = jit.jump();
480+
branch.link(&jit);
481+
jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
482+
done.link(&jit);
483+
484+
emitFunctionEpilogue(jit);
485+
jit.ret();
486+
});
487+
CHECK_EQ(invoke<int>(test, value), compare(cond, value, value2));
488+
};
489+
tryTest(CCallHelpers::LessThan);
490+
tryTest(CCallHelpers::LessThanOrEqual);
491+
tryTest(CCallHelpers::GreaterThan);
492+
tryTest(CCallHelpers::GreaterThanOrEqual);
493+
tryTest(CCallHelpers::Below);
494+
tryTest(CCallHelpers::BelowOrEqual);
495+
tryTest(CCallHelpers::Above);
496+
tryTest(CCallHelpers::AboveOrEqual);
497+
tryTest(CCallHelpers::Equal);
498+
tryTest(CCallHelpers::NotEqual);
499+
}
500+
}
501+
}
502+
#endif
503+
380504
void testBranchTest8()
381505
{
382506
for (auto value : int32Operands()) {
@@ -6113,6 +6237,8 @@ void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
61136237
RUN(testLoadStorePair32());
61146238
RUN(testSub32ArgImm());
61156239

6240+
RUN(testBranch32());
6241+
61166242
RUN(testBranchTest8());
61176243
RUN(testBranchTest16());
61186244

@@ -6126,6 +6252,7 @@ void run(const char* filter) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
61266252
#endif
61276253

61286254
#if CPU(X86_64) || CPU(ARM64)
6255+
RUN(testBranch64());
61296256
RUN(testClearBit64());
61306257
RUN(testClearBits64WithMask());
61316258
RUN(testClearBits64WithMaskTernary());

0 commit comments

Comments
 (0)