Improve codegen for MIsNullOrUndefined
Categories
(Core :: JavaScript Engine: JIT, enhancement, P2)
Tracking
()
Tracking | Status | |
---|---|---|
firefox72 | --- | fixed |
People
(Reporter: anba, Assigned: anba)
Details
Attachments
(4 files)
This µ-benchmark completed in ~240ms for me before https://hg.mozilla.org/integration/autoland/rev/ddc6fa7e24f2, but now it needs ~460ms.
function f() {
var xs = [
{a: 0}, {a: 0},
];
var q = 0;
var t = dateNow();
for (var i = 0; i < 100000000; ++i) {
q += xs[i & 1].a ?? 0;
}
return [dateNow() - t, q];
}
By reusing existing performance ideas from MIsObject
, we can easily recover this performance loss.
Details:
For var x = {a: 0};
, 42 + (x.a ?? 0)
currently generates:
[Codegen] # instruction LoadFixedSlotT
[Codegen] movl 0x20(%rax), %edx
[Codegen] # instruction Box:Int32
[Codegen] movabsq $0xfff8800000000000, %rcx
[Codegen] orq %rdx, %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] jne .Lfrom197
[Codegen] movl $0x1, %ecx
[Codegen] jmp .Lfrom207
[Codegen] .set .Llabel207, .
[Codegen] .set .Lfrom197, .Llabel207
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff3, %r11d
[Codegen] sete %cl
[Codegen] movzbl %cl, %ecx
[Codegen] .set .Llabel227, .
[Codegen] .set .Lfrom207, .Llabel227
[Codegen] # instruction TestIAndBranch
[Codegen] testl %ecx, %ecx
[Codegen] je .Lfrom235
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel235, .
[Codegen] # instruction Integer
[Codegen] xorl %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel237, .
[Codegen] .set .Lfrom235, .Llabel237
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl $42, %edx
[Codegen] jo .Lfrom246
Part 1 will add MIsNullOrUndefined::foldsTo
, which improves the codegen to:
[Codegen] # instruction LoadFixedSlotT
[Codegen] movl 0x20(%rax), %edx
[Codegen] # instruction Goto
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel164, .
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl $42, %edx
[Codegen] jo .Lfrom173
When we have either var x = {a: 0};
or var x = {a: null};
, 42 + (x.a ?? 0)
generates:
[Codegen] # instruction LoadFixedSlotV
[Codegen] movq 0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] jne .Lfrom185
[Codegen] movl $0x1, %edx
[Codegen] jmp .Lfrom195
[Codegen] .set .Llabel195, .
[Codegen] .set .Lfrom185, .Llabel195
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff3, %r11d
[Codegen] sete %dl
[Codegen] movzbl %dl, %edx
[Codegen] .set .Llabel215, .
[Codegen] .set .Lfrom195, .Llabel215
[Codegen] # instruction TestIAndBranch
[Codegen] testl %edx, %edx
[Codegen] je .Lfrom223
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel223, .
[Codegen] # instruction Value
[Codegen] movabsq $0xfff8800000000000, %rcx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel233, .
[Codegen] .set .Lfrom223, .Llabel233
[Codegen] # instruction Double
[Codegen] movsd .Lfrom241(%rip), %xmm1
[Codegen] # instruction ValueToDouble
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff0, %r11d
[Codegen] jbe .Lfrom261
[Codegen] cmpl $0x1fff1, %r11d
[Codegen] je .Lfrom274
[Codegen] cmpl $0x1fff2, %r11d
[Codegen] je .Lfrom287
[Codegen] cmpl $0x1fff3, %r11d
[Codegen] je .Lfrom300
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] je .Lfrom313
[Codegen] jmp .Lfrom318
[Codegen] .set .Llabel318, .
[Codegen] .set .Lfrom313, .Llabel318
[Codegen] xorpd %xmm0, %xmm0
[Codegen] jmp .Lfrom327
[Codegen] .set .Llabel327, .
[Codegen] .set .Lfrom300, .Llabel327
[Codegen] movsd .Lfrom335(%rip), %xmm0
[Codegen] jmp .Lfrom340
[Codegen] .set .Llabel340, .
[Codegen] .set .Lfrom287, .Llabel340
[Codegen] xorpd %xmm0, %xmm0
[Codegen] cvtsi2sd %ecx, %xmm0
[Codegen] jmp .Lfrom353
[Codegen] .set .Llabel353, .
[Codegen] .set .Lfrom274, .Llabel353
[Codegen] xorpd %xmm0, %xmm0
[Codegen] cvtsi2sd %ecx, %xmm0
[Codegen] jmp .Lfrom366
[Codegen] .set .Llabel366, .
[Codegen] .set .Lfrom261, .Llabel366
[Codegen] movq %rcx, %xmm0
[Codegen] .set .Llabel371, .
[Codegen] .set .Lfrom366, .Llabel371
[Codegen] .set .Lfrom353, .Llabel371
[Codegen] .set .Lfrom340, .Llabel371
[Codegen] .set .Lfrom327, .Llabel371
[Codegen] # instruction MathD:add
[Codegen] addsd %xmm1, %xmm0
Part 2 removes the undefined
case from LIsNullOrUndefined, resulting in:
[Codegen] # instruction LoadFixedSlotV
[Codegen] movq 0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] sete %dl
[Codegen] movzbl %dl, %edx
[Codegen] # instruction TestIAndBranch
[Codegen] testl %edx, %edx
[Codegen] je .Lfrom193
[Codegen] # block2 /tmp/d.js:25:4:
[Codegen] .set .Llabel193, .
[Codegen] # instruction Value
[Codegen] movabsq $0xfff8800000000000, %rcx
[Codegen] # instruction Goto
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel203, .
[Codegen] .set .Lfrom193, .Llabel203
[Codegen] # instruction Double
[Codegen] movsd .Lfrom211(%rip), %xmm1
[Codegen] # instruction ValueToDouble
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff0, %r11d
[Codegen] jbe .Lfrom231
[Codegen] cmpl $0x1fff1, %r11d
[Codegen] je .Lfrom244
[Codegen] cmpl $0x1fff2, %r11d
[Codegen] je .Lfrom257
[Codegen] cmpl $0x1fff3, %r11d
[Codegen] je .Lfrom270
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] je .Lfrom283
[Codegen] jmp .Lfrom288
[Codegen] .set .Llabel288, .
[Codegen] .set .Lfrom283, .Llabel288
[Codegen] xorpd %xmm0, %xmm0
[Codegen] jmp .Lfrom297
[Codegen] .set .Llabel297, .
[Codegen] .set .Lfrom270, .Llabel297
[Codegen] movsd .Lfrom305(%rip), %xmm0
[Codegen] jmp .Lfrom310
[Codegen] .set .Llabel310, .
[Codegen] .set .Lfrom257, .Llabel310
[Codegen] xorpd %xmm0, %xmm0
[Codegen] cvtsi2sd %ecx, %xmm0
[Codegen] jmp .Lfrom323
[Codegen] .set .Llabel323, .
[Codegen] .set .Lfrom244, .Llabel323
[Codegen] xorpd %xmm0, %xmm0
[Codegen] cvtsi2sd %ecx, %xmm0
[Codegen] jmp .Lfrom336
[Codegen] .set .Llabel336, .
[Codegen] .set .Lfrom231, .Llabel336
[Codegen] movq %rcx, %xmm0
[Codegen] .set .Llabel341, .
[Codegen] .set .Lfrom336, .Llabel341
[Codegen] .set .Lfrom323, .Llabel341
[Codegen] .set .Lfrom310, .Llabel341
[Codegen] .set .Lfrom297, .Llabel341
[Codegen] # instruction MathD:add
[Codegen] addsd %xmm1, %xmm0
Part 3 improves the typeset for MTest:
[Codegen] # instruction LoadFixedSlotV
[Codegen] movq 0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefined
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] sete %dl
[Codegen] movzbl %dl, %edx
[Codegen] # instruction TestIAndBranch
[Codegen] testl %edx, %edx
[Codegen] jne .Lfrom193
[Codegen] # block1 /tmp/d.js:25:4:
[Codegen] .set .Llabel193, .
[Codegen] # instruction Unbox:Int32
[Codegen] movl %ecx, %edx
[Codegen] # instruction Goto
[Codegen] jmp .Lfrom200
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel200, .
[Codegen] .set .Lfrom193, .Llabel200
[Codegen] # instruction Integer
[Codegen] xorl %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block4 /tmp/d.js:25:4:
[Codegen] .set .Llabel202, .
[Codegen] .set .Lfrom200, .Llabel202
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl $42, %edx
[Codegen] jo .Lfrom211
And finally part 4 adds IsNullOrUndefinedAndBranch:
[Codegen] # instruction LoadFixedSlotV
[Codegen] movq 0x20(%rax), %rcx
[Codegen] # instruction IsNullOrUndefinedAndBranch
[Codegen] movq %rcx, %r11
[Codegen] shrq $47, %r11
[Codegen] cmpl $0x1fff4, %r11d
[Codegen] je .Lfrom185
[Codegen] # block1 /tmp/d.js:25:4:
[Codegen] .set .Llabel185, .
[Codegen] # instruction Unbox:Int32
[Codegen] movl %ecx, %edx
[Codegen] # instruction Goto
[Codegen] jmp .Lfrom192
[Codegen] # block3 /tmp/d.js:25:4:
[Codegen] .set .Llabel192, .
[Codegen] .set .Lfrom185, .Llabel192
[Codegen] # instruction Integer
[Codegen] xorl %edx, %edx
[Codegen] # instruction Goto
[Codegen] # block4 /tmp/d.js:25:4:
[Codegen] .set .Llabel194, .
[Codegen] .set .Lfrom192, .Llabel194
[Codegen] # instruction AddI:OverflowCheck
[Codegen] addl $42, %edx
[Codegen] jo .Lfrom203
Assignee | ||
Comment 1•5 years ago
|
||
Fold away MIsNullOrUndefined when the input is definitely null/undefined resp.
never null/undefined.
Assignee | ||
Comment 2•5 years ago
|
||
We don't need to test for null/undefined if that type was never observed.
Depends on D53172
Assignee | ||
Comment 3•5 years ago
|
||
Remove resp. add null/undefined to the typeset in improveTypesAtTest for
MIsNullOrUndefined. That way operations on the coalesce expression can be
further optimised. For example a += obj.prop ?? 0
where obj.prop
is either
an Int32 or null/undefined can now be optimised to use Int32 addition, because
both possible right-hand side values are now typed as Int32.
Depends on D53173
Assignee | ||
Comment 4•5 years ago
|
||
Depends on D53174
Comment 5•5 years ago
|
||
Great, I was considering doing some of this too :)
I might hold off on reviews until bug 1595476 is fixed, just to be sure, although our changes probably don't actually conflict.
Assignee | ||
Comment 6•5 years ago
|
||
Cool. Waiting for bug 1595476 seems reasonable to ensure there won't be any unexpected side-effects between these changes.
Updated•5 years ago
|
Pushed by aciure@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/b449f05b6755 Part 1: Add MIsNullOrUndefined::foldsTo to omit unreachable tests. r=jandem https://hg.mozilla.org/integration/autoland/rev/3cb7dba63a75 Part 2: Don't emit unreachable tests in CodeGenerator::visitIsNullOrUndefined. r=jandem https://hg.mozilla.org/integration/autoland/rev/412b06699b96 Part 3: Handle MIsNullOrUndefined in improveTypesAtTest to remove null/undefined from the typeset. r=jandem https://hg.mozilla.org/integration/autoland/rev/3bd3398c2f0c Part 4: Add LIsNullOrUndefinedAndBranch to fuse LIsNullOrUndefined and LTestIAndBranch. r=jandem
Comment 8•5 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/b449f05b6755
https://hg.mozilla.org/mozilla-central/rev/3cb7dba63a75
https://hg.mozilla.org/mozilla-central/rev/412b06699b96
https://hg.mozilla.org/mozilla-central/rev/3bd3398c2f0c
Description
•