Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 80fc868e7373b04d6c0456a974af2c8ea89ace5f
      
https://github.com/WebKit/WebKit/commit/80fc868e7373b04d6c0456a974af2c8ea89ace5f
  Author: Andrew Gaul <[email protected]>
  Date:   2026-08-26 (Wed, 26 Aug 2026)

  Changed paths:
    M Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
    M Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
    M Source/JavaScriptCore/assembler/testmasm.cpp

  Log Message:
  -----------
  [JSC] add/sub of a zero immediate should be a mov
https://bugs.webkit.org/show_bug.cgi?id=322504

Reviewed by Keith Miller.

The immediate forms of add32/add64/sub32/sub64 wrote a register-to-register
copy the expensive way when the immediate was zero: add xD, xS, #0 or
sub wD, wS, #0 on arm64, and leaq 0(%src), %dest or a dead addq $0, %reg on
x86_64, where the TrustedImm64 pair also burned a movabsq and the scratch
register. A mov is eliminated at rename where add-with-zero and lea are not,
and the 64-bit forms drop the instruction entirely when source and destination
coincide. The 32-bit forms go through zeroExtend32ToWord() instead, since they
must still zero the destination's upper half.

None of these entry points promise flags -- arm64 already uses the
non-flag-setting add and sub, and flag-consuming callers use
branchAdd64/branchSub64 -- so dropping x86_64's flag write is invisible.

x86_64 needed more entry points than arm64: only the add32/sub32 three-operand
forms had the check, and its two-operand forms emit their own instruction
rather than forwarding to the three-operand ones. Its 32-bit two-operand forms
are left alone, where the substitution would be movl %eax, %eax: a byte shorter
than addl $0, %eax but the same single uop.

The dominant source is JIT::emit_op_new_array(), which passes the address of
the literal's first element with

    addPtr(TrustedImm32(valuesStart.offset() * sizeof(Register)),
        callFrameRegister, argumentGPR2);

and that offset is zero for an empty [] literal.

Scanning everything the JITs emit while running JetStream 3, armlint reports
4563 sites on arm64, 3081 of them exactly add x2, x29, #0 (3335 Baseline, 1068
DFG) and the remaining 699 sub wD, wS, #0. The same scan on x86_64 -- 111654
code blobs and 240 MB captured through LinkBuffer's perf JITDump -- has x86lint
reporting 3989 sites:

    3091  lea rD, [rS]      zero displacement, 3090 Baseline and 1 DFG
     680  add/sub rD, 0     64-bit, 676 DFG, 3 Baseline, 1 WasmBBQ
     216  add/sub eD, 0     32-bit, deliberately unchanged
       2  lea rD, [rS+rI]   two-register, unrelated to this change

All 3091 zero-displacement LEAs are exactly leaq 0(%rbp), %rdx, which is
callFrameRegister into argumentGPR2. After this change an empty array literal
compiles to mov x2, fp or movq %rbp, %rdx; no zero-immediate add or sub is left
on arm64, and on x86_64 both targeted rows are empty, 3771 sites in total. The
32-bit row's drift to 219 is JIT nondeterminism between runs.

testmasm covered none of these entry points on x86_64: the six sub tests sat in
the #if CPU(ARM64) block and there were no add tests at all. Move them to
#if CPU(X86_64) || CPU(ARM64) and add testAdd32Imm, testAdd32ArgImm,
testAdd64Imm32, testAdd64ArgImm32, testAdd64Imm64 and testAdd64ArgImm64, one
per immediate form. int32Operands() and int64Operands() both start at 0, so all
of them exercise the zero-immediate path. testmasm goes from 382 to 394 tests
on x86_64, all passing.

Found with armlint and x86lint.

* Source/JavaScriptCore/assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::add32):
(JSC::MacroAssemblerARM64::add64):
(JSC::MacroAssemblerARM64::sub32):
(JSC::MacroAssemblerARM64::sub64):
* Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::add64):
(JSC::MacroAssemblerX86_64::sub64):
* Source/JavaScriptCore/assembler/testmasm.cpp:
(JSC::testAdd32Imm):
(JSC::testAdd32ArgImm):
(JSC::testAdd64Imm32):
(JSC::testAdd64ArgImm32):
(JSC::testAdd64Imm64):
(JSC::testAdd64ArgImm64):
(JSC::run):

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Canonical link: https://commits.webkit.org/319908@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to