⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 242569 in webkit


Ignore:
Timestamp:
Mar 6, 2019, 2:57:08 PM (7 years ago)
Author:
sbarati@apple.com
Message:

Air::reportUsedRegisters must padInterference
https://bugs.webkit.org/show_bug.cgi?id=195303
<rdar://problem/48270343>

Reviewed by Keith Miller.

JSTests:

  • stress/optional-def-arg-width-should-be-both-early-and-late-use.js: Added.

Source/JavaScriptCore:

reportUsedRegisters uses reg liveness to eliminate loads/moves into dead
registers. However, liveness can report incorrect results in certain
scenarios when considering liveness at instruction boundaries. For example,
it can go wrong when an Inst has a LateUse of a register and the following
Inst has an EarlyDef of that same register. Such a scenario could lead us
to incorrectly say the register is not live-in to the first Inst. Pad
interference inserts Nops between such instruction boundaries that cause
this issue.

The test with this patch fixes the issue in reportUsedRegisters. This patch
also conservatively makes it so that lowerAfterRegAlloc calls padInterference
since it also reasons about liveness.

  • b3/air/AirLowerAfterRegAlloc.cpp:

(JSC::B3::Air::lowerAfterRegAlloc):

  • b3/air/AirPadInterference.h:
  • b3/air/AirReportUsedRegisters.cpp:

(JSC::B3::Air::reportUsedRegisters):

  • b3/testb3.cpp:

(JSC::B3::testReportUsedRegistersLateUseNotDead):
(JSC::B3::run):

Location:
trunk
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r242568 r242569  
     12019-03-06  Saam Barati  <sbarati@apple.com>
     2
     3        Air::reportUsedRegisters must padInterference
     4        https://bugs.webkit.org/show_bug.cgi?id=195303
     5        <rdar://problem/48270343>
     6
     7        Reviewed by Keith Miller.
     8
     9        * stress/optional-def-arg-width-should-be-both-early-and-late-use.js: Added.
     10
    1112019-03-06  Yusuke Suzuki  <ysuzuki@apple.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r242568 r242569  
     12019-03-06  Saam Barati  <sbarati@apple.com>
     2
     3        Air::reportUsedRegisters must padInterference
     4        https://bugs.webkit.org/show_bug.cgi?id=195303
     5        <rdar://problem/48270343>
     6
     7        Reviewed by Keith Miller.
     8
     9        reportUsedRegisters uses reg liveness to eliminate loads/moves into dead
     10        registers. However, liveness can report incorrect results in certain
     11        scenarios when considering liveness at instruction boundaries. For example,
     12        it can go wrong when an Inst has a LateUse of a register and the following
     13        Inst has an EarlyDef of that same register. Such a scenario could lead us
     14        to incorrectly say the register is not live-in to the first Inst. Pad
     15        interference inserts Nops between such instruction boundaries that cause
     16        this issue.
     17       
     18        The test with this patch fixes the issue in reportUsedRegisters. This patch
     19        also conservatively makes it so that lowerAfterRegAlloc calls padInterference
     20        since it also reasons about liveness.
     21
     22        * b3/air/AirLowerAfterRegAlloc.cpp:
     23        (JSC::B3::Air::lowerAfterRegAlloc):
     24        * b3/air/AirPadInterference.h:
     25        * b3/air/AirReportUsedRegisters.cpp:
     26        (JSC::B3::Air::reportUsedRegisters):
     27        * b3/testb3.cpp:
     28        (JSC::B3::testReportUsedRegistersLateUseNotDead):
     29        (JSC::B3::run):
     30
    1312019-03-06  Yusuke Suzuki  <ysuzuki@apple.com>
    232
  • trunk/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.cpp

    r221954 r242569  
    3535#include "AirInsertionSet.h"
    3636#include "AirInstInlines.h"
     37#include "AirPadInterference.h"
    3738#include "AirRegLiveness.h"
    3839#include "AirPhaseScope.h"
     
    7778    if (!haveAnyRelevant)
    7879        return;
     80
     81    padInterference(code);
    7982
    8083    HashMap<Inst*, RegisterSet> usedRegisters;
  • trunk/Source/JavaScriptCore/b3/air/AirPadInterference.h

    r207434 r242569  
    3333
    3434// This isn't a phase - it's meant to be a utility that other phases use. Air reasons about liveness by
    35 // reasoning about interference at boundaries between instructions. This can go wrong - for example, a
     35// reasoning about interference at boundaries between instructions. This is convenient because it works
     36// great in the most common case: early uses and late defs. However, this can go wrong - for example, a
    3637// late use in one instruction doesn't actually interfere with an early def of the next instruction, but
    37 // Air thinks that it does. This is convenient because it works great in the most common case: early uses
    38 // and late defs. In practice, only the register allocators need to use this, since only they need to be
    39 // able to color the interference graph using a bounded number of colors.
     38// Air thinks that it does. It can also go wrong by having liveness incorrectly report that something is
     39// dead when it isn't.
    4040//
    4141// See https://bugs.webkit.org/show_bug.cgi?id=163548#c2 for more info.
  • trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp

    r225893 r242569  
    3232#include "AirCode.h"
    3333#include "AirInstInlines.h"
     34#include "AirPadInterference.h"
    3435#include "AirRegLiveness.h"
    3536#include "AirPhaseScope.h"
     
    4243   
    4344    static constexpr bool verbose = false;
     45
     46    padInterference(code);
    4447   
    4548    if (verbose)
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r242100 r242569  
    1672216722    demoteValues(proc, valuesToDemote);
    1672316723    validate(proc);
     16724}
     16725
     16726void testReportUsedRegistersLateUseFollowedByEarlyDefDoesNotMarkUseAsDead()
     16727{
     16728    Procedure proc;
     16729    if (proc.optLevel() < 2)
     16730        return;
     16731    BasicBlock* root = proc.addBlock();
     16732
     16733    RegisterSet allRegs = RegisterSet::allGPRs();
     16734    allRegs.exclude(RegisterSet::stackRegisters());
     16735    allRegs.exclude(RegisterSet::reservedHardwareRegisters());
     16736
     16737    {
     16738        // Make every reg 42 (just needs to be a value other than 10).
     16739        PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
     16740        Value* const42 = root->appendNew<Const32Value>(proc, Origin(), 42);
     16741        for (Reg reg : allRegs)
     16742            patchpoint->append(const42, ValueRep::reg(reg));
     16743        patchpoint->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     16744    }
     16745
     16746    {
     16747        PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Void, Origin());
     16748        Value* const10 = root->appendNew<Const32Value>(proc, Origin(), 10);
     16749        for (Reg reg : allRegs)
     16750            patchpoint->append(const10, ValueRep::lateReg(reg));
     16751        patchpoint->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) {
     16752            for (Reg reg : allRegs) {
     16753                auto done = jit.branch32(CCallHelpers::Equal, reg.gpr(), CCallHelpers::TrustedImm32(10));
     16754                jit.breakpoint();
     16755                done.link(&jit);
     16756            }
     16757        });
     16758    }
     16759
     16760    {
     16761        PatchpointValue* patchpoint = root->appendNew<PatchpointValue>(proc, Int32, Origin());
     16762        patchpoint->resultConstraint = ValueRep::SomeEarlyRegister;
     16763        patchpoint->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams& params) {
     16764            RELEASE_ASSERT(allRegs.contains(params[0].gpr()));
     16765        });
     16766    }
     16767
     16768    root->appendNewControlValue(proc, Return, Origin());
     16769
     16770    compileAndRun<void>(proc);
    1672416771}
    1672516772
     
    1835018397    }
    1835118398
     18399    RUN(testReportUsedRegistersLateUseFollowedByEarlyDefDoesNotMarkUseAsDead());
     18400
    1835218401    if (tasks.isEmpty())
    1835318402        usage();
Note: See TracChangeset for help on using the changeset viewer.