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

Changeset 194331 in webkit


Ignore:
Timestamp:
Dec 21, 2015, 8:16:01 AM (11 years ago)
Author:
fpizlo@apple.com
Message:

B3->Air lowering incorrectly copy-propagates over ZExt32's
​https://bugs.webkit.org/show_bug.cgi?id=152365

Reviewed by Benjamin Poulain.

The instruction selector thinks that Value's that return Int32's are going to always be lowered
to instructions that zero-extend the destination. But this isn't actually true. If you have an
Add32 with a destination on the stack (i.e. spilled) then it only writes 4 bytes. Then, the
filler will load 8 bytes from the stack at the point of use. So, the use of the Add32 will see
garbage in the high bits.

The fact that the spiller chose to use 8 bytes for a Tmp that gets defined by an Add32 is a
pretty sad bug, but:

  • It's entirely up to the spiller to decide how many bytes to use for a Tmp, since we do not ascribe a type to Tmps. We could ascribe types to Tmps, but then coalescing would become harder. Our goal is to fix the bug while still enabling coalescing in cases like "a[i]" where "i" is a 32-bit integer that is computed using operations that already do zero-extension.
  • More broadly, it's strange that the instruction selector decides whether a Value will be lowered to something that zero-extends. That's too constraining, since the most optimal instruction selection might involve something that doesn't zero-extend in cases of spilling, so the zero-extension should only happen if it's actually needed. This means that we need to understand which Air instructions cause zero-extensions.
  • If we know which Air instructions cause zero-extensions, then we don't need the instruction selector to copy-propagate ZExt32's. We have copy-propagation in Air thanks to the register allocator.

In fact, the register allocator is exactly where all of the pieces come together. It's there that
we want to know which operations zero-extend and which don't. It also wants to know how many bits
of a Tmp each instruction reads. Armed with that information, the register allocator can emit
more optimal spill code, use less stack space for spill slots, and coalesce Move32's. As a bonus,
on X86, it replaces Move's with Move32's whenever it can. On X86, Move32 is cheaper.

This fixes a crash bug in V8/encrypt. After fixing this, I only needed two minor fixes to get
V8/encrypt to run. We're about 10% behind LLVM on steady state throughput on this test. It
appears to be mostly due to excessive spilling caused by CCall slow paths. That's fixable: we
could make CCalls on slow paths use a variant of CCallSpecial that promises not to clobber any
registers, and then have it emit spill code around the call itself. LLVM probably gets this
optimization from its live range splitting.

I tried writing a regression test. The problem is that you need garbage on the stack for this to
work, and I didn't feel like writing a flaky test. It appears that running V8/encrypt will cover
this, so we do have coverage.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/AbstractMacroAssembler.h:

(JSC::isX86):
(JSC::isX86_64):
(JSC::optimizeForARMv7IDIVSupported):
(JSC::optimizeForX86):
(JSC::optimizeForX86_64):

  • b3/B3LowerToAir.cpp:

(JSC::B3::Air::LowerToAir::highBitsAreZero):
(JSC::B3::Air::LowerToAir::shouldCopyPropagate):
(JSC::B3::Air::LowerToAir::lower):

  • b3/B3PatchpointSpecial.cpp:

(JSC::B3::PatchpointSpecial::forEachArg):

  • b3/B3StackmapSpecial.cpp:

(JSC::B3::StackmapSpecial::forEachArgImpl):

  • b3/B3Value.h:
  • b3/air/AirAllocateStack.cpp:

(JSC::B3::Air::allocateStack):

  • b3/air/AirArg.cpp:

(WTF::printInternal):

  • b3/air/AirArg.h:

(JSC::B3::Air::Arg::pointerWidth):
(JSC::B3::Air::Arg::isAnyUse):
(JSC::B3::Air::Arg::isColdUse):
(JSC::B3::Air::Arg::isEarlyUse):
(JSC::B3::Air::Arg::isDef):
(JSC::B3::Air::Arg::isZDef):
(JSC::B3::Air::Arg::widthForB3Type):
(JSC::B3::Air::Arg::conservativeWidth):
(JSC::B3::Air::Arg::minimumWidth):
(JSC::B3::Air::Arg::bytes):
(JSC::B3::Air::Arg::widthForBytes):
(JSC::B3::Air::Arg::Arg):
(JSC::B3::Air::Arg::forEachTmp):

  • b3/air/AirCCallSpecial.cpp:

(JSC::B3::Air::CCallSpecial::forEachArg):

  • b3/air/AirEliminateDeadCode.cpp:

(JSC::B3::Air::eliminateDeadCode):

  • b3/air/AirFixPartialRegisterStalls.cpp:

(JSC::B3::Air::fixPartialRegisterStalls):

  • b3/air/AirInst.cpp:

(JSC::B3::Air::Inst::hasArgEffects):

  • b3/air/AirInst.h:

(JSC::B3::Air::Inst::forEachTmpFast):
(JSC::B3::Air::Inst::forEachTmp):

  • b3/air/AirInstInlines.h:

(JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs):

  • b3/air/AirIteratedRegisterCoalescing.cpp:
  • b3/air/AirLiveness.h:

(JSC::B3::Air::AbstractLiveness::AbstractLiveness):
(JSC::B3::Air::AbstractLiveness::LocalCalc::execute):

  • b3/air/AirOpcode.opcodes:
  • b3/air/AirSpillEverything.cpp:

(JSC::B3::Air::spillEverything):

  • b3/air/AirTmpWidth.cpp: Added.

(JSC::B3::Air::TmpWidth::TmpWidth):
(JSC::B3::Air::TmpWidth::~TmpWidth):

  • b3/air/AirTmpWidth.h: Added.

(JSC::B3::Air::TmpWidth::width):
(JSC::B3::Air::TmpWidth::defWidth):
(JSC::B3::Air::TmpWidth::useWidth):
(JSC::B3::Air::TmpWidth::Widths::Widths):

  • b3/air/AirUseCounts.h:

(JSC::B3::Air::UseCounts::UseCounts):

  • b3/air/opcode_generator.rb:
  • b3/testb3.cpp:

(JSC::B3::testCheckMegaCombo):
(JSC::B3::testCheckTrickyMegaCombo):
(JSC::B3::testCheckTwoMegaCombos):
(JSC::B3::run):

Location:
trunk/Source/JavaScriptCore
Files:
2 added
27 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r194328 r194331  
    9191    b3/air/AirStackSlot.cpp
    9292    b3/air/AirTmp.cpp
     93    b3/air/AirTmpWidth.cpp
    9394    b3/air/AirValidate.cpp
    9495
  • trunk/Source/JavaScriptCore/ChangeLog

    r194328 r194331  
     12015-12-21  Filip Pizlo  <fpizlo@apple.com>
     2
     3        B3->Air lowering incorrectly copy-propagates over ZExt32's
     4        https://bugs.webkit.org/show_bug.cgi?id=152365
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        The instruction selector thinks that Value's that return Int32's are going to always be lowered
     9        to instructions that zero-extend the destination. But this isn't actually true. If you have an
     10        Add32 with a destination on the stack (i.e. spilled) then it only writes 4 bytes. Then, the
     11        filler will load 8 bytes from the stack at the point of use. So, the use of the Add32 will see
     12        garbage in the high bits.
     13
     14        The fact that the spiller chose to use 8 bytes for a Tmp that gets defined by an Add32 is a
     15        pretty sad bug, but:
     16
     17        - It's entirely up to the spiller to decide how many bytes to use for a Tmp, since we do not
     18          ascribe a type to Tmps. We could ascribe types to Tmps, but then coalescing would become
     19          harder. Our goal is to fix the bug while still enabling coalescing in cases like "a[i]" where
     20          "i" is a 32-bit integer that is computed using operations that already do zero-extension.
     21
     22        - More broadly, it's strange that the instruction selector decides whether a Value will be
     23          lowered to something that zero-extends. That's too constraining, since the most optimal
     24          instruction selection might involve something that doesn't zero-extend in cases of spilling, so
     25          the zero-extension should only happen if it's actually needed. This means that we need to
     26          understand which Air instructions cause zero-extensions.
     27
     28        - If we know which Air instructions cause zero-extensions, then we don't need the instruction
     29          selector to copy-propagate ZExt32's. We have copy-propagation in Air thanks to the register
     30          allocator.
     31
     32        In fact, the register allocator is exactly where all of the pieces come together. It's there that
     33        we want to know which operations zero-extend and which don't. It also wants to know how many bits
     34        of a Tmp each instruction reads. Armed with that information, the register allocator can emit
     35        more optimal spill code, use less stack space for spill slots, and coalesce Move32's. As a bonus,
     36        on X86, it replaces Move's with Move32's whenever it can. On X86, Move32 is cheaper.
     37
     38        This fixes a crash bug in V8/encrypt. After fixing this, I only needed two minor fixes to get
     39        V8/encrypt to run. We're about 10% behind LLVM on steady state throughput on this test. It
     40        appears to be mostly due to excessive spilling caused by CCall slow paths. That's fixable: we
     41        could make CCalls on slow paths use a variant of CCallSpecial that promises not to clobber any
     42        registers, and then have it emit spill code around the call itself. LLVM probably gets this
     43        optimization from its live range splitting.
     44
     45        I tried writing a regression test. The problem is that you need garbage on the stack for this to
     46        work, and I didn't feel like writing a flaky test. It appears that running V8/encrypt will cover
     47        this, so we do have coverage.
     48
     49        * CMakeLists.txt:
     50        * JavaScriptCore.xcodeproj/project.pbxproj:
     51        * assembler/AbstractMacroAssembler.h:
     52        (JSC::isX86):
     53        (JSC::isX86_64):
     54        (JSC::optimizeForARMv7IDIVSupported):
     55        (JSC::optimizeForX86):
     56        (JSC::optimizeForX86_64):
     57        * b3/B3LowerToAir.cpp:
     58        (JSC::B3::Air::LowerToAir::highBitsAreZero):
     59        (JSC::B3::Air::LowerToAir::shouldCopyPropagate):
     60        (JSC::B3::Air::LowerToAir::lower):
     61        * b3/B3PatchpointSpecial.cpp:
     62        (JSC::B3::PatchpointSpecial::forEachArg):
     63        * b3/B3StackmapSpecial.cpp:
     64        (JSC::B3::StackmapSpecial::forEachArgImpl):
     65        * b3/B3Value.h:
     66        * b3/air/AirAllocateStack.cpp:
     67        (JSC::B3::Air::allocateStack):
     68        * b3/air/AirArg.cpp:
     69        (WTF::printInternal):
     70        * b3/air/AirArg.h:
     71        (JSC::B3::Air::Arg::pointerWidth):
     72        (JSC::B3::Air::Arg::isAnyUse):
     73        (JSC::B3::Air::Arg::isColdUse):
     74        (JSC::B3::Air::Arg::isEarlyUse):
     75        (JSC::B3::Air::Arg::isDef):
     76        (JSC::B3::Air::Arg::isZDef):
     77        (JSC::B3::Air::Arg::widthForB3Type):
     78        (JSC::B3::Air::Arg::conservativeWidth):
     79        (JSC::B3::Air::Arg::minimumWidth):
     80        (JSC::B3::Air::Arg::bytes):
     81        (JSC::B3::Air::Arg::widthForBytes):
     82        (JSC::B3::Air::Arg::Arg):
     83        (JSC::B3::Air::Arg::forEachTmp):
     84        * b3/air/AirCCallSpecial.cpp:
     85        (JSC::B3::Air::CCallSpecial::forEachArg):
     86        * b3/air/AirEliminateDeadCode.cpp:
     87        (JSC::B3::Air::eliminateDeadCode):
     88        * b3/air/AirFixPartialRegisterStalls.cpp:
     89        (JSC::B3::Air::fixPartialRegisterStalls):
     90        * b3/air/AirInst.cpp:
     91        (JSC::B3::Air::Inst::hasArgEffects):
     92        * b3/air/AirInst.h:
     93        (JSC::B3::Air::Inst::forEachTmpFast):
     94        (JSC::B3::Air::Inst::forEachTmp):
     95        * b3/air/AirInstInlines.h:
     96        (JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs):
     97        * b3/air/AirIteratedRegisterCoalescing.cpp:
     98        * b3/air/AirLiveness.h:
     99        (JSC::B3::Air::AbstractLiveness::AbstractLiveness):
     100        (JSC::B3::Air::AbstractLiveness::LocalCalc::execute):
     101        * b3/air/AirOpcode.opcodes:
     102        * b3/air/AirSpillEverything.cpp:
     103        (JSC::B3::Air::spillEverything):
     104        * b3/air/AirTmpWidth.cpp: Added.
     105        (JSC::B3::Air::TmpWidth::TmpWidth):
     106        (JSC::B3::Air::TmpWidth::~TmpWidth):
     107        * b3/air/AirTmpWidth.h: Added.
     108        (JSC::B3::Air::TmpWidth::width):
     109        (JSC::B3::Air::TmpWidth::defWidth):
     110        (JSC::B3::Air::TmpWidth::useWidth):
     111        (JSC::B3::Air::TmpWidth::Widths::Widths):
     112        * b3/air/AirUseCounts.h:
     113        (JSC::B3::Air::UseCounts::UseCounts):
     114        * b3/air/opcode_generator.rb:
     115        * b3/testb3.cpp:
     116        (JSC::B3::testCheckMegaCombo):
     117        (JSC::B3::testCheckTrickyMegaCombo):
     118        (JSC::B3::testCheckTwoMegaCombos):
     119        (JSC::B3::run):
     120
    11212015-12-21  Andy VanWagoner  <thetalecrafter@gmail.com>
    2122
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r194328 r194331  
    696696                0FE0502D1AA9095600D33B33 /* VarOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050241AA9095600D33B33 /* VarOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
    697697                0FE0502F1AAA806900D33B33 /* ScopedArgumentsTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */; };
     698                0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */; };
     699                0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */; };
    698700                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
    699701                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
    … …  
    28362838                0FE050241AA9095600D33B33 /* VarOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VarOffset.h; sourceTree = "<group>"; };
    28372839                0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedArgumentsTable.cpp; sourceTree = "<group>"; };
     2840                0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirTmpWidth.cpp; path = b3/air/AirTmpWidth.cpp; sourceTree = "<group>"; };
     2841                0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirTmpWidth.h; path = b3/air/AirTmpWidth.h; sourceTree = "<group>"; };
    28382842                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
    28392843                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
    … …  
    48014805                                0FEC85691BDACDC70080FF74 /* AirTmp.h */,
    48024806                                0FEC856A1BDACDC70080FF74 /* AirTmpInlines.h */,
     4807                                0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */,
     4808                                0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */,
    48034809                                0F3730921C0D67EE00052BFA /* AirUseCounts.h */,
    48044810                                0FEC856B1BDACDC70080FF74 /* AirValidate.cpp */,
    … …  
    72977303                                0F2B9CF719D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h in Headers */,
    72987304                                0F235BDB17178E1C00690C7F /* FTLExitValue.h in Headers */,
     7305                                0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */,
    72997306                                A7F2996C17A0BB670010417A /* FTLFail.h in Headers */,
    73007307                                0FEA0A2C170B661900BB722C /* FTLFormattedValue.h in Headers */,
    … …  
    92309237                                BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */,
    92319238                                705B41AB1A6E501E00716757 /* Symbol.cpp in Sources */,
     9239                                0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */,
    92329240                                705B41AD1A6E501E00716757 /* SymbolConstructor.cpp in Sources */,
    92339241                                705B41AF1A6E501E00716757 /* SymbolObject.cpp in Sources */,
  • trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h

    r193640 r194331  
    6868}
    6969
     70inline bool isX86_64()
     71{
     72#if CPU(X86_64)
     73    return true;
     74#else
     75    return false;
     76#endif
     77}
     78
    7079inline bool optimizeForARMv7IDIVSupported()
    7180{
    … …  
    8190{
    8291    return isX86() && Options::useArchitectureSpecificOptimizations();
     92}
     93
     94inline bool optimizeForX86_64()
     95{
     96    return isX86_64() && Options::useArchitectureSpecificOptimizations();
    8397}
    8498
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r194320 r194331  
    159159    }
    160160
    161     // NOTE: This entire mechanism could be done over Air, if we felt that this would be fast enough.
    162     // For now we're assuming that it's faster to do this here, since analyzing B3 is so cheap.
    163161    bool shouldCopyPropagate(Value* value)
    164162    {
    … …  
    167165        case Identity:
    168166            return true;
    169         case ZExt32:
    170             return highBitsAreZero(value->child(0));
    171167        default:
    172168            return false;
    … …  
    17761772
    17771773        case ZExt32: {
    1778             if (highBitsAreZero(m_value->child(0))) {
    1779                 ASSERT(tmp(m_value->child(0)) == tmp(m_value));
    1780                 return;
    1781             }
    1782 
    17831774            appendUnOp<Move32, Air::Oops>(m_value->child(0));
    17841775            return;
  • trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp

    r193640 r194331  
    5555    }
    5656
    57     callback(inst.args[1], Arg::Def, inst.origin->airType());
     57    callback(inst.args[1], Arg::Def, inst.origin->airType(), inst.origin->airWidth());
    5858    forEachArgImpl(0, 2, inst, SameAsRep, callback);
    5959}
  • trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp

    r193631 r194331  
    112112            break;
    113113        }
    114        
    115         callback(arg, role, Arg::typeForB3Type(child.value()->type()));
     114
     115        Type type = child.value()->type();
     116        callback(arg, role, Arg::typeForB3Type(type), Arg::widthForB3Type(type));
    116117    }
    117118}
  • trunk/Source/JavaScriptCore/b3/B3Value.h

    r194314 r194331  
    7777    // This is useful when lowering. Note that this is only valid for non-void values.
    7878    Air::Arg::Type airType() const { return Air::Arg::typeForB3Type(type()); }
     79    Air::Arg::Width airWidth() const { return Air::Arg::widthForB3Type(type()); }
    7980
    8081    AdjacencyList& children() { return m_children; }
  • trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp

    r192851 r194331  
    105105        for (Inst& inst : *block) {
    106106            inst.forEachArg(
    107                 [&] (Arg& arg, Arg::Role role, Arg::Type) {
     107                [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
    108108                    if (role == Arg::UseAddr && arg.isStack())
    109109                        escapingStackSlots.add(arg.stackSlot());
    … …  
    149149
    150150            inst.forEachArg(
    151                 [&] (Arg& arg, Arg::Role role, Arg::Type) {
     151                [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
    152152                    if (!Arg::isDef(role))
    153153                        return;
  • trunk/Source/JavaScriptCore/b3/air/AirArg.cpp

    r192863 r194331  
    179179        out.print("UseDef");
    180180        return;
     181    case Arg::ZDef:
     182        out.print("ZDef");
     183        return;
     184    case Arg::UseZDef:
     185        out.print("UseZDef");
     186        return;
    181187    case Arg::UseAddr:
    182188        out.print("UseAddr");
  • trunk/Source/JavaScriptCore/b3/air/AirArg.h

    r193683 r194331  
    102102        Def,
    103103
     104        // This is a special variant of Def that implies that the upper bits of the target register are
     105        // zero-filled. Specifically, if the Width of a ZDef is less than the largest possible width of
     106        // the argument (for example, we're on a 64-bit machine and we have a Width32 ZDef of a GPR) then
     107        // this has different implications for the upper bits (i.e. the top 32 bits in our example)
     108        // depending on the kind of the argument:
     109        //
     110        // For register: the upper bits are zero-filled.
     111        // For address: the upper bits are not touched (i.e. we do a 32-bit store in our example).
     112        // For tmp: either the upper bits are not touched or they are zero-filled, and we won't know
     113        // which until we lower the tmp to either a StackSlot or a Reg.
     114        //
     115        // The behavior of ZDef is consistent with what happens when you perform 32-bit operations on a
     116        // 64-bit GPR. It's not consistent with what happens with 8-bit or 16-bit Defs on x86 GPRs, or
     117        // what happens with float Defs in ARM NEON or X86 SSE. Hence why we have both Def and ZDef.
     118        ZDef,
     119
    104120        // This is a combined Use and Def. It means that both things happen.
    105121        UseDef,
     122
     123        // This is a combined Use and ZDef. It means that both things happen.
     124        UseZDef,
    106125
    107126        // This is a special kind of use that is only valid for addresses. It means that the
    … …  
    127146    };
    128147
     148    static Width pointerWidth()
     149    {
     150        if (sizeof(void*) == 8)
     151            return Width64;
     152        return Width32;
     153    }
     154
    129155    enum Signedness : int8_t {
    130156        Signed,
    … …  
    140166        case ColdUse:
    141167        case UseDef:
     168        case UseZDef:
    142169        case LateUse:
    143170            return true;
    144171        case Def:
     172        case ZDef:
    145173        case UseAddr:
    146174            return false;
    … …  
    156184        case Use:
    157185        case UseDef:
     186        case UseZDef:
    158187        case Def:
     188        case ZDef:
    159189        case UseAddr:
    160190            return false;
    … …  
    174204        case ColdUse:
    175205        case UseDef:
     206        case UseZDef:
    176207            return true;
    177208        case Def:
     209        case ZDef:
    178210        case UseAddr:
    179211        case LateUse:
    … …  
    199231        case Def:
    200232        case UseDef:
     233        case ZDef:
     234        case UseZDef:
     235            return true;
     236        }
     237    }
     238
     239    // Returns true if the Role implies that the Inst will ZDef the Arg.
     240    static bool isZDef(Role role)
     241    {
     242        switch (role) {
     243        case Use:
     244        case ColdUse:
     245        case UseAddr:
     246        case LateUse:
     247        case Def:
     248        case UseDef:
     249            return false;
     250        case ZDef:
     251        case UseZDef:
    201252            return true;
    202253        }
    … …  
    231282        case Int64:
    232283        case Double:
     284            return Width64;
     285        }
     286    }
     287
     288    static Width conservativeWidth(Type type)
     289    {
     290        return type == GP ? pointerWidth() : Width64;
     291    }
     292
     293    static Width minimumWidth(Type type)
     294    {
     295        return type == GP ? Width8 : Width32;
     296    }
     297
     298    static unsigned bytes(Width width)
     299    {
     300        return 1 << width;
     301    }
     302
     303    static Width widthForBytes(unsigned bytes)
     304    {
     305        switch (bytes) {
     306        case 0:
     307        case 1:
     308            return Width8;
     309        case 2:
     310            return Width16;
     311        case 3:
     312        case 4:
     313            return Width32;
     314        default:
    233315            return Width64;
    234316        }
    … …  
    718800    // This defs (%rcx) but uses %rcx.
    719801    template<typename Functor>
    720     void forEachTmp(Role argRole, Type argType, const Functor& functor)
     802    void forEachTmp(Role argRole, Type argType, Width argWidth, const Functor& functor)
    721803    {
    722804        switch (m_kind) {
    723805        case Tmp:
    724806            ASSERT(isAnyUse(argRole) || isDef(argRole));
    725             functor(m_base, argRole, argType);
     807            functor(m_base, argRole, argType, argWidth);
    726808            break;
    727809        case Addr:
    728             functor(m_base, Use, GP);
     810            functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
    729811            break;
    730812        case Index:
    731             functor(m_base, Use, GP);
    732             functor(m_index, Use, GP);
     813            functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
     814            functor(m_index, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
    733815            break;
    734816        default:
  • trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp

    r192841 r194331  
    4646{
    4747    for (unsigned i = 0; i < numCalleeArgs; ++i)
    48         callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP);
     48        callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP, Arg::pointerWidth());
    4949    for (unsigned i = 0; i < numReturnGPArgs; ++i)
    50         callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP);
     50        callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP, Arg::pointerWidth());
    5151    for (unsigned i = 0; i < numReturnFPArgs; ++i)
    52         callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP);
     52        callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP, Arg::Width64);
    5353   
    5454    for (unsigned i = argArgOffset; i < inst.args.size(); ++i) {
    5555        // For the type, we can just query the arg's type. The arg will have a type, because we
    5656        // require these args to be argument registers.
    57         callback(inst.args[i], Arg::Use, inst.args[i].type());
     57        Arg::Type type = inst.args[i].type();
     58        callback(inst.args[i], Arg::Use, type, Arg::conservativeWidth(type));
    5859    }
    5960}
  • trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp

    r192826 r194331  
    8181        bool storesToLive = false;
    8282        inst.forEachArg(
    83             [&] (Arg& arg, Arg::Role role, Arg::Type) {
     83            [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
    8484                if (!Arg::isDef(role))
    8585                    return;
  • trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp

    r193683 r194331  
    114114    }
    115115
    116     inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type) {
     116    inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
    117117        ASSERT_WITH_MESSAGE(tmp.isReg(), "This phase must be run after register allocation.");
    118118
    … …  
    204204                RegisterSet defs;
    205205                RegisterSet uses;
    206                 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type) {
     206                inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
    207207                    if (tmp.isFPR()) {
    208208                        if (Arg::isDef(role))
  • trunk/Source/JavaScriptCore/b3/air/AirInst.cpp

    r192121 r194331  
    3939    bool result = false;
    4040    forEachArg(
    41         [&] (Arg&, Arg::Role role, Arg::Type) {
     41        [&] (Arg&, Arg::Role role, Arg::Type, Arg::Width) {
    4242            if (Arg::isDef(role))
    4343                result = true;
  • trunk/Source/JavaScriptCore/b3/air/AirInst.h

    r192841 r194331  
    9999    }
    100100
    101     typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type);
     101    typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type, Arg::Width);
    102102   
    103     // Calls the functor with (arg, role, type). This function is auto-generated by
     103    // Calls the functor with (arg, role, type, width). This function is auto-generated by
    104104    // opcode_generator.rb.
    105105    template<typename Functor>
    106106    void forEachArg(const Functor&);
    107107
    108     // Calls the functor with (tmp, role, type).
     108    // Calls the functor with (tmp, role, type, width).
    109109    template<typename Functor>
    110110    void forEachTmp(const Functor& functor)
    111111    {
    112112        forEachArg(
    113             [&] (Arg& arg, Arg::Role role, Arg::Type type) {
    114                 arg.forEachTmp(role, type, functor);
     113            [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
     114                arg.forEachTmp(role, type, width, functor);
    115115            });
    116116    }
  • trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h

    r192841 r194331  
    5656    {
    5757        inst.forEachArg(
    58             [&] (Arg& arg, Arg::Role role, Arg::Type type) {
     58            [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
    5959                if (!arg.isStack())
    6060                    return;
    … …  
    6767                // https://bugs.webkit.org/show_bug.cgi?id=151128
    6868               
    69                 functor(stackSlot, role, type);
     69                functor(stackSlot, role, type, width);
    7070                arg = Arg::stack(stackSlot, arg.offset());
    7171            });
    … …  
    100100{
    101101    forEachTmp(
    102         [&] (Tmp& tmpArg, Arg::Role role, Arg::Type argType) {
    103             functor(tmpArg, role, argType);
     102        [&] (Tmp& tmpArg, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
     103            functor(tmpArg, role, argType, argWidth);
    104104        });
    105105
    106106    auto reportReg = [&] (Reg reg) {
    107         functor(Tmp(reg), Arg::Def, reg.isGPR() ? Arg::GP : Arg::FP);
     107        Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP;
     108        functor(Tmp(reg), Arg::Def, type, Arg::conservativeWidth(type));
    108109    };
    109110
  • trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp

    r194316 r194331  
    3636#include "AirRegisterPriority.h"
    3737#include "AirTmpInlines.h"
     38#include "AirTmpWidth.h"
    3839#include "AirUseCounts.h"
    3940#include <wtf/ListDump.h>
    … …  
    631632class ColoringAllocator : public AbstractColoringAllocator<unsigned> {
    632633public:
    633     ColoringAllocator(Code& code, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp)
     634    ColoringAllocator(Code& code, TmpWidth& tmpWidth, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp)
    634635        : AbstractColoringAllocator<unsigned>(regsInPriorityOrder(type), AbsoluteTmpMapper<type>::lastMachineRegisterIndex(), tmpArraySize(code))
    635636        , m_code(code)
     637        , m_tmpWidth(tmpWidth)
    636638        , m_useCounts(useCounts)
    637639        , m_unspillableTmps(unspillableTmp)
    … …  
    647649    }
    648650
     651    // This tells you if a Move will be coalescable if the src and dst end up matching. This method
     652    // relies on an analysis that is invalidated by register allocation, so you it's only meaningful to
     653    // call this *before* replacing the Tmp's in this Inst with registers or spill slots.
     654    bool mayBeCoalescable(const Inst& inst) const
     655    {
     656        return mayBeCoalescableImpl(inst, &m_tmpWidth);
     657    }
     658
    649659    bool isUselessMove(const Inst& inst) const
    650660    {
    651         return mayBeCoalescable(inst) && inst.args[0].tmp() == inst.args[1].tmp();
     661        return mayBeCoalescableImpl(inst, nullptr) && inst.args[0].tmp() == inst.args[1].tmp();
    652662    }
    653663
    … …  
    771781        inst.forEachTmpWithExtraClobberedRegs(
    772782            nextInst,
    773             [&] (const Tmp& arg, Arg::Role role, Arg::Type argType) {
     783            [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) {
    774784                if (!Arg::isDef(role) || argType != type)
    775785                    return;
    … …  
    778788                // We should not use forEachDefAndExtraClobberedTmp() here since colored Tmps
    779789                // do not need interference edges in our implementation.
    780                 inst.forEachTmp([&] (Tmp& otherArg, Arg::Role role, Arg::Type argType) {
     790                inst.forEachTmp([&] (Tmp& otherArg, Arg::Role role, Arg::Type argType, Arg::Width) {
    781791                    if (!Arg::isDef(role) || argType != type)
    782792                        return;
    … …  
    792802            Tmp defTmp;
    793803            Tmp useTmp;
    794             inst.forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type) {
     804            inst.forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type, Arg::Width) {
    795805                if (Arg::isDef(role))
    796806                    defTmp = argTmp;
    … …  
    840850        inst.forEachTmpWithExtraClobberedRegs(
    841851            nextInst,
    842             [&] (const Tmp& arg, Arg::Role role, Arg::Type argType) {
     852            [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) {
    843853                if (!Arg::isDef(role) || argType != type)
    844854                    return;
    … …  
    858868    }
    859869
    860     bool mayBeCoalescable(const Inst& inst) const
     870    // Calling this without a tmpWidth will perform a more conservative coalescing analysis that assumes
     871    // that Move32's are not coalescable.
     872    static bool mayBeCoalescableImpl(const Inst& inst, TmpWidth* tmpWidth)
    861873    {
    862874        switch (type) {
    … …  
    864876            switch (inst.opcode) {
    865877            case Move:
     878            case Move32:
    866879                break;
    867880            default:
    … …  
    888901        ASSERT(inst.args[1].type() == type);
    889902
     903        // We can coalesce a Move32 so long as either of the following holds:
     904        // - The input is already zero-filled.
     905        // - The output only cares about the low 32 bits.
     906        //
     907        // Note that the input property requires an analysis over ZDef's, so it's only valid so long
     908        // as the input gets a register. We don't know if the input gets a register, but we do know
     909        // that if it doesn't get a register then we will still emit this Move32.
     910        if (inst.opcode == Move32) {
     911            if (!tmpWidth)
     912                return false;
     913
     914            if (tmpWidth->defWidth(inst.args[0].tmp()) > Arg::Width32
     915                && tmpWidth->useWidth(inst.args[1].tmp()) > Arg::Width32)
     916                return false;
     917        }
     918       
    890919        return true;
    891920    }
    … …  
    10251054
    10261055    Code& m_code;
     1056    TmpWidth& m_tmpWidth;
    10271057    // FIXME: spilling should not type specific. It is only a side effect of using UseCounts.
    10281058    const UseCounts<Tmp>& m_useCounts;
    … …  
    10541084        while (true) {
    10551085            ++m_numIterations;
    1056             ColoringAllocator<type> allocator(m_code, m_useCounts, unspillableTmps);
     1086
     1087            // FIXME: One way to optimize this code is to remove the recomputation inside the fixpoint.
     1088            // We need to recompute because spilling adds tmps, but we could just update tmpWidth when we
     1089            // add those tmps. Note that one easy way to remove the recomputation is to make any newly
     1090            // added Tmps get the same use/def widths that the original Tmp got. But, this may hurt the
     1091            // spill code we emit. Since we currently recompute TmpWidth after spilling, the newly
     1092            // created Tmps may get narrower use/def widths. On the other hand, the spiller already
     1093            // selects which move instruction to use based on the original Tmp's widths, so it may not
     1094            // matter than a subsequent iteration sees a coservative width for the new Tmps. Also, the
     1095            // recomputation may not actually be a performance problem; it's likely that a better way to
     1096            // improve performance of TmpWidth is to replace its HashMap with something else. It's
     1097            // possible that most of the TmpWidth overhead is from queries of TmpWidth rather than the
     1098            // recomputation, in which case speeding up the lookup would be a bigger win.
     1099            // https://bugs.webkit.org/show_bug.cgi?id=152478
     1100            m_tmpWidth.recompute(m_code);
     1101           
     1102            ColoringAllocator<type> allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps);
    10571103            if (!allocator.requiresSpilling()) {
    10581104                assignRegistersToTmp(allocator);
    … …  
    10701116            for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
    10711117                Inst& inst = block->at(instIndex);
     1118
     1119                // The mayBeCoalescable() method will change its mind for some operations after we
     1120                // complete register allocation. So, we record this before starting.
     1121                bool mayBeCoalescable = allocator.mayBeCoalescable(inst);
     1122
     1123                // On X86_64, Move32 is cheaper if we know that it's equivalent to a Move. It's
     1124                // equivalent if the destination's high bits are not observable or if the source's high
     1125                // bits are all zero. Note that we don't have the opposite optimization for other
     1126                // architectures, which may prefer Move over Move32, because Move is canonical already.
     1127                if (type == Arg::GP && optimizeForX86_64() && inst.opcode == Move
     1128                    && inst.args[0].isTmp() && inst.args[1].isTmp()) {
     1129                    if (m_tmpWidth.useWidth(inst.args[1].tmp()) <= Arg::Width32
     1130                        || m_tmpWidth.defWidth(inst.args[0].tmp()) <= Arg::Width32)
     1131                        inst.opcode = Move32;
     1132                }
     1133
    10721134                inst.forEachTmpFast([&] (Tmp& tmp) {
    10731135                    if (tmp.isReg() || tmp.isGP() == (type != Arg::GP))
    … …  
    10861148                    tmp = assignedTmp;
    10871149                });
     1150
     1151                if (mayBeCoalescable && inst.args[0].isTmp() && inst.args[1].isTmp()
     1152                    && inst.args[0].tmp() == inst.args[1].tmp())
     1153                    inst = Inst();
    10881154            }
    10891155
    10901156            // Remove all the useless moves we created in this block.
    10911157            block->insts().removeAllMatching([&] (const Inst& inst) {
    1092                 return allocator.isUselessMove(inst);
     1158                return !inst;
    10931159            });
    10941160        }
    … …  
    11041170
    11051171            // Allocate stack slot for each spilled value.
    1106             bool isNewTmp = stackSlots.add(tmp, m_code.addStackSlot(8, StackSlotKind::Anonymous)).isNewEntry;
     1172            StackSlot* stackSlot = m_code.addStackSlot(
     1173                m_tmpWidth.width(tmp) <= Arg::Width32 ? 4 : 8, StackSlotKind::Anonymous);
     1174            bool isNewTmp = stackSlots.add(tmp, stackSlot).isNewEntry;
    11071175            ASSERT_UNUSED(isNewTmp, isNewTmp);
    11081176        }
    … …  
    11151183            for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
    11161184                Inst& inst = block->at(instIndex);
     1185
     1186                // The TmpWidth analysis will say that a Move only stores 32 bits into the destination,
     1187                // if the source only had 32 bits worth of non-zero bits. Same for the source: it will
     1188                // only claim to read 32 bits from the source if only 32 bits of the destination are
     1189                // read. Note that we only apply this logic if this turns into a load or store, since
     1190                // Move is the canonical way to move data between GPRs.
     1191                bool forceMove32IfDidSpill = false;
     1192                bool didSpill = false;
     1193                if (type == Arg::GP && inst.opcode == Move) {
     1194                    if (m_tmpWidth.defWidth(inst.args[0].tmp()) <= Arg::Width32
     1195                        || m_tmpWidth.useWidth(inst.args[1].tmp()) <= Arg::Width32)
     1196                        forceMove32IfDidSpill = true;
     1197                }
    11171198
    11181199                // Try to replace the register use by memory use when possible.
    … …  
    11211202                    if (arg.isTmp() && arg.type() == type && !arg.isReg()) {
    11221203                        auto stackSlotEntry = stackSlots.find(arg.tmp());
    1123                         if (stackSlotEntry != stackSlots.end() && inst.admitsStack(i))
     1204                        if (stackSlotEntry != stackSlots.end() && inst.admitsStack(i)) {
    11241205                            arg = Arg::stack(stackSlotEntry->value);
     1206                            didSpill = true;
     1207                        }
    11251208                    }
    11261209                }
    11271210
     1211                if (didSpill && forceMove32IfDidSpill)
     1212                    inst.opcode = Move32;
     1213
    11281214                // For every other case, add Load/Store as needed.
    1129                 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type argType) {
     1215                inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type argType, Arg::Width) {
    11301216                    if (tmp.isReg() || argType != type)
    11311217                        return;
    … …  
    11421228
    11431229                    Arg arg = Arg::stack(stackSlotEntry->value);
    1144                     Opcode move = type == Arg::GP ? Move : MoveDouble;
     1230                    Opcode move = Oops;
     1231                    switch (stackSlotEntry->value->byteSize()) {
     1232                    case 4:
     1233                        move = type == Arg::GP ? Move32 : MoveFloat;
     1234                        break;
     1235                    case 8:
     1236                        move = type == Arg::GP ? Move : MoveDouble;
     1237                        break;
     1238                    default:
     1239                        RELEASE_ASSERT_NOT_REACHED();
     1240                        break;
     1241                    }
    11451242
    11461243                    if (Arg::isAnyUse(role)) {
    … …  
    11671264
    11681265    Code& m_code;
     1266    TmpWidth m_tmpWidth;
    11691267    UseCounts<Tmp> m_useCounts;
    11701268    unsigned m_numIterations { 0 };
  • trunk/Source/JavaScriptCore/b3/air/AirLiveness.h

    r192863 r194331  
    9191
    9292            block->last().forEach<typename Adapter::Thing>(
    93                 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type) {
     93                [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
    9494                    if (Arg::isLateUse(role) && Adapter::acceptsType(type))
    9595                        liveAtTail.add(Adapter::valueToIndex(thing));
    … …  
    217217            // First handle def's.
    218218            inst.forEach<typename Adapter::Thing>(
    219                 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type) {
     219                [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
    220220                    if (Arg::isDef(role) && Adapter::acceptsType(type))
    221221                        workset.remove(Adapter::valueToIndex(thing));
    … …  
    224224            // Then handle use's.
    225225            inst.forEach<typename Adapter::Thing>(
    226                 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type) {
     226                [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
    227227                    if (Arg::isEarlyUse(role) && Adapter::acceptsType(type))
    228228                        workset.add(Adapter::valueToIndex(thing));
    … …  
    233233                Inst& prevInst = m_block->at(instIndex - 1);
    234234                prevInst.forEach<typename Adapter::Thing>(
    235                     [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type) {
     235                    [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
    236236                        if (Arg::isLateUse(role) && Adapter::acceptsType(type))
    237237                            workset.add(Adapter::valueToIndex(thing));
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r194320 r194331  
    2424# Syllabus:
    2525#
    26 # Roles and types:
    27 # U:G => use of a general-purpose register or value
    28 # D:G => def of a general-purpose register or value
    29 # UD:G => use and def of a general-purpose register or value
    30 # UA:G => UseAddr (see comment in Arg.h)
    31 # U:F => use of a float register or value
    32 # D:F => def of a float register or value
    33 # UD:F => use and def of a float register or value
     26# Examples of some roles, types, and widths:
     27# U:G:32 => use of the low 32 bits of a general-purpose register or value
     28# D:G:32 => def of the low 32 bits of a general-purpose register or value
     29# UD:G:32 => use and def of the low 32 bits of a general-purpose register or value
     30# U:G:64 => use of the low 64 bits of a general-purpose register or value
     31# ZD:G:32 => def of all bits of a general-purpose register, where all but the low 32 bits are guaranteed to be zeroed.
     32# UA:G:Ptr => UseAddr (see comment in Arg.h)
     33# U:F:32 => use of a float register or value
     34# U:F:64 => use of a double register or value
     35# D:F:32 => def of a float register or value
     36# UD:F:32 => use and def of a float register or value
    3437#
    3538# Argument kinds:
    … …  
    4548# even newlines are meaningful to the parser. For example, you could write:
    4649#
    47 # Foo42 U:G, UD:F Imm, Tmp Addr, Tmp
     50# Foo42 U:G:32, UD:F:32 Imm, Tmp Addr, Tmp
    4851#
    4952# And the parser would know that this is the same as:
    5053#
    51 # Foo42 U:G, UD:F
     54# Foo42 U:G:32, UD:F:32
    5255#     Imm, Tmp
    5356#     Addr, Tmp
    … …  
    5962# opcode only available on x86_64:
    6063#
    61 # x86_64: Fuzz UD:G, D:G
     64# x86_64: Fuzz UD:G:64, D:G:64
    6265#     Tmp, Tmp
    6366#     Tmp, Addr
    … …  
    6568# But this only restricts the two-operand form, the other form is allowed on all architectures:
    6669#
    67 # x86_64: Fuzz UD:G, D:G
     70# x86_64: Fuzz UD:G:64, D:G:64
    6871#     Tmp, Tmp
    6972#     Tmp, Addr
    70 # Fuzz UD:G, D:G, U:F
     73# Fuzz UD:G:Ptr, D:G:Ptr, U:F:Ptr
    7174#     Tmp, Tmp, Tmp
    7275#     Tmp, Addr, Tmp
    … …  
    7477# And you can also restrict individual forms:
    7578#
    76 # Thingy UD:G, D:G
     79# Thingy UD:G:32, D:G:32
    7780#     Tmp, Tmp
    7881#     arm64: Tmp, Addr
    … …  
    8285# versions are available on armv7 or x86_64:
    8386#
    84 # x86_64 armv7: Buzz U:G, UD:F
     87# x86_64 armv7: Buzz U:G:32, UD:F:32
    8588#     Tmp, Tmp
    8689#     Imm, Tmp
    … …  
    104107Nop
    105108
    106 Add32 U:G, UD:G
    107     Tmp, Tmp
    108     x86: Imm, Addr
    109     Imm, Tmp
    110     x86: Addr, Tmp
    111     x86: Tmp, Addr
    112 
    113 Add32 U:G, U:G, D:G
     109Add32 U:G:32, UZD:G:32
     110    Tmp, Tmp
     111    x86: Imm, Addr
     112    Imm, Tmp
     113    x86: Addr, Tmp
     114    x86: Tmp, Addr
     115
     116Add32 U:G:32, U:G:32, ZD:G:32
    114117    Imm, Tmp, Tmp
    115118    Tmp, Tmp, Tmp
    116119
    117 64: Add64 U:G, UD:G
    118     Tmp, Tmp
    119     x86: Imm, Addr
    120     Imm, Tmp
    121     x86: Addr, Tmp
    122     x86: Tmp, Addr
    123 
    124 64: Add64 U:G, U:G, D:G
     12064: Add64 U:G:64, UD:G:64
     121    Tmp, Tmp
     122    x86: Imm, Addr
     123    Imm, Tmp
     124    x86: Addr, Tmp
     125    x86: Tmp, Addr
     126
     12764: Add64 U:G:64, U:G:64, D:G:64
    125128    Imm, Tmp, Tmp
    126129    Tmp, Tmp, Tmp
    127130
    128 AddDouble U:F, UD:F
    129     Tmp, Tmp
    130     x86: Addr, Tmp
    131 
    132 AddFloat U:F, UD:F
    133     Tmp, Tmp
    134     x86: Addr, Tmp
    135 
    136 Sub32 U:G, UD:G
    137     Tmp, Tmp
    138     x86: Imm, Addr
    139     Imm, Tmp
    140     x86: Addr, Tmp
    141     x86: Tmp, Addr
    142 
    143 64: Sub64 U:G, UD:G
    144     Tmp, Tmp
    145     x86: Imm, Addr
    146     Imm, Tmp
    147     x86: Addr, Tmp
    148     x86: Tmp, Addr
    149 
    150 SubDouble U:F, UD:F
    151     Tmp, Tmp
    152     x86: Addr, Tmp
    153 
    154 SubFloat U:F, UD:F
    155     Tmp, Tmp
    156     x86: Addr, Tmp
    157 
    158 Neg32 UD:G
     131AddDouble U:F:64, UD:F:64
     132    Tmp, Tmp
     133    x86: Addr, Tmp
     134
     135AddFloat U:F:32, UD:F:32
     136    Tmp, Tmp
     137    x86: Addr, Tmp
     138
     139Sub32 U:G:32, UZD:G:32
     140    Tmp, Tmp
     141    x86: Imm, Addr
     142    Imm, Tmp
     143    x86: Addr, Tmp
     144    x86: Tmp, Addr
     145
     14664: Sub64 U:G:64, UD:G:64
     147    Tmp, Tmp
     148    x86: Imm, Addr
     149    Imm, Tmp
     150    x86: Addr, Tmp
     151    x86: Tmp, Addr
     152
     153SubDouble U:F:64, UD:F:64
     154    Tmp, Tmp
     155    x86: Addr, Tmp
     156
     157SubFloat U:F:32, UD:F:32
     158    Tmp, Tmp
     159    x86: Addr, Tmp
     160
     161Neg32 UZD:G:32
    159162    Tmp
    160163    Addr
    161164
    162 64: Neg64 UD:G
     16564: Neg64 UD:G:64
    163166    Tmp
    164167
    165 Mul32 U:G, UD:G
    166     Tmp, Tmp
    167     x86: Addr, Tmp
    168 
    169 Mul32 U:G, U:G, D:G
     168Mul32 U:G:32, UZD:G:32
     169    Tmp, Tmp
     170    x86: Addr, Tmp
     171
     172Mul32 U:G:32, U:G:32, ZD:G:32
    170173    Imm, Tmp, Tmp
    171174
    172 64: Mul64 U:G, UD:G
    173     Tmp, Tmp
    174 
    175 MulDouble U:F, UD:F
    176     Tmp, Tmp
    177     x86: Addr, Tmp
    178 
    179 MulFloat U:F, UD:F
    180     Tmp, Tmp
    181     x86: Addr, Tmp
    182 
    183 DivDouble U:F, UD:F
    184     Tmp, Tmp
    185     x86: Addr, Tmp
    186 
    187 DivFloat U:F, UD:F
    188     Tmp, Tmp
    189     x86: Addr, Tmp
    190 
    191 x86: X86ConvertToDoubleWord32 U:G, D:G
     17564: Mul64 U:G:64, UD:G:64
     176    Tmp, Tmp
     177
     178MulDouble U:F:64, UD:F:64
     179    Tmp, Tmp
     180    x86: Addr, Tmp
     181
     182MulFloat U:F:32, UD:F:32
     183    Tmp, Tmp
     184    x86: Addr, Tmp
     185
     186DivDouble U:F:32, UD:F:32
     187    Tmp, Tmp
     188    x86: Addr, Tmp
     189
     190DivFloat U:F:32, UD:F:32
     191    Tmp, Tmp
     192    x86: Addr, Tmp
     193
     194x86: X86ConvertToDoubleWord32 U:G:32, ZD:G:32
    192195    Tmp*, Tmp*
    193196
    194 x86_64: X86ConvertToQuadWord64 U:G, D:G
     197x86_64: X86ConvertToQuadWord64 U:G:64, D:G:64
    195198    Tmp*, Tmp*
    196199
    197 x86: X86Div32 UD:G, UD:G, U:G
     200x86: X86Div32 UZD:G:32, UZD:G:32, U:G:32
    198201    Tmp*, Tmp*, Tmp
    199202
    200 x86_64: X86Div64 UD:G, UD:G, U:G
     203x86_64: X86Div64 UZD:G:64, UZD:G:64, U:G:64
    201204    Tmp*, Tmp*, Tmp
    202205
    203 Lea UA:G, D:G
    204     Addr, Tmp
    205 
    206 And32 U:G, UD:G
    207     Tmp, Tmp
    208     Imm, Tmp
    209     x86: Tmp, Addr
    210     x86: Addr, Tmp
    211     x86: Imm, Addr
    212 
    213 64: And64 U:G, UD:G
    214     Tmp, Tmp
    215     Imm, Tmp
    216 
    217 AndDouble U:F, UD:F
    218     Tmp, Tmp
    219 
    220 AndFloat U:F, UD:F
    221     Tmp, Tmp
    222 
    223 Lshift32 U:G, UD:G
     206Lea UA:G:Ptr, D:G:Ptr
     207    Addr, Tmp
     208
     209And32 U:G:32, UZD:G:32
     210    Tmp, Tmp
     211    Imm, Tmp
     212    x86: Tmp, Addr
     213    x86: Addr, Tmp
     214    x86: Imm, Addr
     215
     21664: And64 U:G:64, UD:G:64
     217    Tmp, Tmp
     218    Imm, Tmp
     219
     220AndDouble U:F:64, UD:F:64
     221    Tmp, Tmp
     222
     223AndFloat U:F:32, UD:F:32
     224    Tmp, Tmp
     225
     226Lshift32 U:G:32, UZD:G:32
    224227    Tmp*, Tmp
    225228    Imm, Tmp
    226229
    227 64: Lshift64 U:G, UD:G
     23064: Lshift64 U:G:64, UD:G:64
    228231    Tmp*, Tmp
    229232    Imm, Tmp
    230233
    231 Rshift32 U:G, UD:G
     234Rshift32 U:G:32, UZD:G:32
    232235    Tmp*, Tmp
    233236    Imm, Tmp
    234237
    235 64: Rshift64 U:G, UD:G
     23864: Rshift64 U:G:64, UD:G:64
    236239    Tmp*, Tmp
    237240    Imm, Tmp
    238241
    239 Urshift32 U:G, UD:G
     242Urshift32 U:G:32, UZD:G:32
    240243    Tmp*, Tmp
    241244    Imm, Tmp
    242245
    243 64: Urshift64 U:G, UD:G
     24664: Urshift64 U:G:64, UD:G:64
    244247    Tmp*, Tmp
    245248    Imm, Tmp
    246249
    247 Or32 U:G, UD:G
    248     Tmp, Tmp
    249     Imm, Tmp
    250     x86: Tmp, Addr
    251     x86: Addr, Tmp
    252     x86: Imm, Addr
    253 
    254 64: Or64 U:G, UD:G
    255     Tmp, Tmp
    256     Imm, Tmp
    257 
    258 Xor32 U:G, UD:G
    259     Tmp, Tmp
    260     Imm, Tmp
    261     x86: Tmp, Addr
    262     x86: Addr, Tmp
    263     x86: Imm, Addr
    264 
    265 64: Xor64 U:G, UD:G
    266     Tmp, Tmp
    267     x86: Tmp, Addr
    268     Imm, Tmp
    269 
    270 Not32 UD:G
     250Or32 U:G:32, UZD:G:32
     251    Tmp, Tmp
     252    Imm, Tmp
     253    x86: Tmp, Addr
     254    x86: Addr, Tmp
     255    x86: Imm, Addr
     256
     25764: Or64 U:G:64, UD:G:64
     258    Tmp, Tmp
     259    Imm, Tmp
     260
     261Xor32 U:G:32, UZD:G:32
     262    Tmp, Tmp
     263    Imm, Tmp
     264    x86: Tmp, Addr
     265    x86: Addr, Tmp
     266    x86: Imm, Addr
     267
     26864: Xor64 U:G:64, UD:G:64
     269    Tmp, Tmp
     270    x86: Tmp, Addr
     271    Imm, Tmp
     272
     273Not32 UZD:G:32
    271274    Tmp
    272275    x86: Addr
    273276
    274 64: Not64 UD:G
     27764: Not64 UD:G:64
    275278    Tmp
    276279    x86: Addr
    277280
    278 CeilDouble U:F, UD:F
    279     Tmp, Tmp
    280     Addr, Tmp
    281 
    282 CeilFloat U:F, UD:F
    283     Tmp, Tmp
    284     Addr, Tmp
    285 
    286 SqrtDouble U:F, UD:F
    287     Tmp, Tmp
    288     x86: Addr, Tmp
    289 
    290 SqrtFloat U:F, UD:F
    291     Tmp, Tmp
    292     x86: Addr, Tmp
    293 
    294 ConvertInt32ToDouble U:G, D:F
    295     Tmp, Tmp
    296     x86: Addr, Tmp
    297 
    298 64: ConvertInt64ToDouble U:G, D:F
    299     Tmp, Tmp
    300 
    301 CountLeadingZeros32 U:G, D:G
    302     Tmp, Tmp
    303     x86: Addr, Tmp
    304 
    305 64: CountLeadingZeros64 U:G, D:G
    306     Tmp, Tmp
    307     x86: Addr, Tmp
    308 
    309 ConvertDoubleToFloat U:F, D:F
    310     Tmp, Tmp
    311     x86: Addr, Tmp
    312 
    313 ConvertFloatToDouble U:F, D:F
     281CeilDouble U:F:64, UD:F:64
     282    Tmp, Tmp
     283    Addr, Tmp
     284
     285CeilFloat U:F:32, UD:F:32
     286    Tmp, Tmp
     287    Addr, Tmp
     288
     289SqrtDouble U:F:64, UD:F:64
     290    Tmp, Tmp
     291    x86: Addr, Tmp
     292
     293SqrtFloat U:F:32, UD:F:32
     294    Tmp, Tmp
     295    x86: Addr, Tmp
     296
     297ConvertInt32ToDouble U:G:32, D:F:64
     298    Tmp, Tmp
     299    x86: Addr, Tmp
     300
     30164: ConvertInt64ToDouble U:G:64, D:F:64
     302    Tmp, Tmp
     303
     304CountLeadingZeros32 U:G:32, ZD:G:32
     305    Tmp, Tmp
     306    x86: Addr, Tmp
     307
     30864: CountLeadingZeros64 U:G:64, D:G:64
     309    Tmp, Tmp
     310    x86: Addr, Tmp
     311
     312ConvertDoubleToFloat U:F:64, D:F:32
     313    Tmp, Tmp
     314    x86: Addr, Tmp
     315
     316ConvertFloatToDouble U:F:32, D:F:64
    314317    Tmp, Tmp
    315318    x86: Addr, Tmp
    … …  
    319322# Move64 instruction. OTOH, our MacroAssemblers already have this notion of "move()" that basically
    320323# means movePtr.
    321 Move U:G, D:G
     324Move U:G:Ptr, D:G:Ptr
    322325    Tmp, Tmp
    323326    Imm, Tmp as signExtend32ToPtr
    … …  
    329332    Imm, Addr as storePtr
    330333
    331 Move32 U:G, D:G
     334Move32 U:G:32, ZD:G:32
    332335    Tmp, Tmp as zeroExtend32ToPtr
    333336    Addr, Tmp as load32
    … …  
    338341    Imm, Index as store32
    339342
    340 SignExtend32ToPtr U:G, D:G
    341     Tmp, Tmp
    342 
    343 ZeroExtend8To32 U:G, D:G
     343SignExtend32ToPtr U:G:32, D:G:Ptr
     344    Tmp, Tmp
     345
     346ZeroExtend8To32 U:G:8, ZD:G:32
    344347    Tmp, Tmp
    345348    Addr, Tmp as load8
    346349    Index, Tmp as load8
    347350
    348 SignExtend8To32 U:G, D:G
     351SignExtend8To32 U:G:8, ZD:G:32
    349352    Tmp, Tmp
    350353    x86: Addr, Tmp as load8SignedExtendTo32
    351354    Index, Tmp as load8SignedExtendTo32
    352355
    353 ZeroExtend16To32 U:G, D:G
     356ZeroExtend16To32 U:G:16, ZD:G:32
    354357    Tmp, Tmp
    355358    Addr, Tmp as load16
    356359    Index, Tmp as load16
    357360
    358 SignExtend16To32 U:G, D:G
     361SignExtend16To32 U:G:16, ZD:G:32
    359362    Tmp, Tmp
    360363    Addr, Tmp as load16SignedExtendTo32
    361364    Index, Tmp as load16SignedExtendTo32
    362365
    363 MoveFloat U:F, D:F
     366MoveFloat U:F:32, D:F:32
    364367    Tmp, Tmp as moveDouble
    365368    Addr, Tmp as loadFloat
    … …  
    368371    Tmp, Index as storeFloat
    369372
    370 MoveDouble U:F, D:F
     373MoveDouble U:F:64, D:F:64
    371374    Tmp, Tmp
    372375    Addr, Tmp as loadDouble
    … …  
    375378    Tmp, Index as storeDouble
    376379
    377 MoveZeroToDouble D:F
     380MoveZeroToDouble D:F:64
    378381    Tmp
    379382
    380 64: Move64ToDouble U:G, D:F
     38364: Move64ToDouble U:G:64, D:F:64
    381384    Tmp, Tmp
    382385    Addr, Tmp as loadDouble
    383386    Index, Tmp as loadDouble
    384387
    385 MoveInt32ToPacked U:G, D:F
     388MoveInt32ToPacked U:G:32, D:F:32
    386389    Tmp, Tmp
    387390    Addr, Tmp as loadFloat
    388391    Index, Tmp as loadFloat
    389392
    390 64: MoveDoubleTo64 U:F, D:G
     39364: MoveDoubleTo64 U:F:64, D:G:64
    391394    Tmp, Tmp
    392395    Addr, Tmp as load64
    393396    Index, Tmp as load64
    394397
    395 MovePackedToInt32 U:F, D:G
     398MovePackedToInt32 U:F:32, D:G:32
    396399    Tmp, Tmp
    397400    Addr, Tmp as load32
    398401    Index, Tmp as load32
    399402
    400 Load8 U:G, D:G
     403Load8 U:G:8, ZD:G:32
    401404    Addr, Tmp
    402405    Index, Tmp
    403406
    404 Store8 U:G, D:G
     407Store8 U:G:8, D:G:8
    405408    Tmp, Index
    406409    Tmp, Addr
    … …  
    408411    Imm, Addr
    409412
    410 Load8SignedExtendTo32 U:G, D:G
     413Load8SignedExtendTo32 U:G:8, ZD:G:32
    411414    Addr, Tmp
    412415    Index, Tmp
    413416
    414 Load16 U:G, D:G
     417Load16 U:G:16, ZD:G:32
    415418    Addr, Tmp
    416419    Index, Tmp
    417420
    418 Load16SignedExtendTo32 U:G, D:G
     421Load16SignedExtendTo32 U:G:16, ZD:G:32
    419422    Addr, Tmp
    420423    Index, Tmp
    421424
    422 Compare32 U:G, U:G, U:G, D:G
     425Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
    423426    RelCond, Tmp, Tmp, Tmp
    424427    RelCond, Tmp, Imm, Tmp
    425428
    426 64: Compare64 U:G, U:G, U:G, D:G
     42964: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32
    427430    RelCond, Tmp, Imm, Tmp
    428431    RelCond, Tmp, Tmp, Tmp
    429432
    430 Test32 U:G, U:G, U:G, D:G
     433Test32 U:G:32, U:G:32, U:G:32, ZD:G:32
    431434    x86: ResCond, Addr, Imm, Tmp
    432435    ResCond, Tmp, Tmp, Tmp
    433436
    434 64: Test64 U:G, U:G, U:G, D:G
     43764: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32
    435438    ResCond, Tmp, Imm, Tmp
    436439    ResCond, Tmp, Tmp, Tmp
    437440
    438 CompareDouble U:G, U:F, U:F, D:G
     441CompareDouble U:G:32, U:F:64, U:F:64, ZD:G:32
    439442    DoubleCond, Tmp, Tmp, Tmp
    440443
    441 CompareFloat U:G, U:F, U:F, D:G
     444CompareFloat U:G:32, U:F:32, U:F:32, ZD:G:32
    442445    DoubleCond, Tmp, Tmp, Tmp
    443446
    … …  
    445448# you opt them into the block order optimizations.
    446449
    447 Branch8 U:G, U:G, U:G /branch
     450Branch8 U:G:32, U:G:8, U:G:8 /branch
    448451    x86: RelCond, Addr, Imm
    449452    x86: RelCond, Index, Imm
    450453
    451 Branch32 U:G, U:G, U:G /branch
     454Branch32 U:G:32, U:G:32, U:G:32 /branch
    452455    x86: RelCond, Addr, Imm
    453456    RelCond, Tmp, Tmp
    … …  
    457460    x86: RelCond, Index, Imm
    458461
    459 64: Branch64 U:G, U:G, U:G /branch
     46264: Branch64 U:G:32, U:G:64, U:G:64 /branch
    460463    RelCond, Tmp, Tmp
    461464    x86: RelCond, Tmp, Addr
    … …  
    463466    x86: RelCond, Index, Tmp
    464467
    465 BranchTest8 U:G, U:G, U:G /branch
     468BranchTest8 U:G:32, U:G:8, U:G:8 /branch
    466469    x86: ResCond, Addr, Imm
    467470    x86: ResCond, Index, Imm
    468471
    469 BranchTest32 U:G, U:G, U:G /branch
     472BranchTest32 U:G:32, U:G:32, U:G:32 /branch
    470473    ResCond, Tmp, Tmp
    471474    ResCond, Tmp, Imm
    … …  
    475478# Warning: forms that take an immediate will sign-extend their immediate. You probably want
    476479# BranchTest32 in most cases where you use an immediate.
    477 64: BranchTest64 U:G, U:G, U:G /branch
     48064: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
    478481    ResCond, Tmp, Tmp
    479482    ResCond, Tmp, Imm
    … …  
    482485    x86: ResCond, Index, Imm
    483486
    484 BranchDouble U:G, U:F, U:F /branch
     487BranchDouble U:G:32, U:F:64, U:F:64 /branch
    485488    DoubleCond, Tmp, Tmp
    486489
    487 BranchFloat U:G, U:F, U:F /branch
     490BranchFloat U:G:32, U:F:32, U:F:32 /branch
    488491    DoubleCond, Tmp, Tmp
    489492
    490 BranchAdd32 U:G, U:G, UD:G /branch
     493BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch
    491494    ResCond, Tmp, Tmp
    492495    ResCond, Imm, Tmp
    … …  
    495498    x86: ResCond, Addr, Tmp
    496499
    497 64: BranchAdd64 U:G, U:G, UD:G /branch
     50064: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch
    498501    ResCond, Imm, Tmp
    499502    ResCond, Tmp, Tmp
    500503
    501 BranchMul32 U:G, U:G, UD:G /branch
     504BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch
    502505    ResCond, Tmp, Tmp
    503506    x86: ResCond, Addr, Tmp
    504507
    505 BranchMul32 U:G, U:G, U:G, D:G /branch
     508BranchMul32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
    506509    ResCond, Tmp, Imm, Tmp
    507510
    508 64: BranchMul64 U:G, U:G, UD:G /branch
    509     ResCond, Tmp, Tmp
    510 
    511 BranchSub32 U:G, U:G, UD:G /branch
     51164: BranchMul64 U:G:32, U:G:64, UZD:G:64 /branch
     512    ResCond, Tmp, Tmp
     513
     514BranchSub32 U:G:32, U:G:32, UZD:G:32 /branch
    512515    ResCond, Tmp, Tmp
    513516    ResCond, Imm, Tmp
    … …  
    516519    x86: ResCond, Addr, Tmp
    517520
    518 64: BranchSub64 U:G, U:G, UD:G /branch
     52164: BranchSub64 U:G:32, U:G:64, UD:G:64 /branch
    519522    ResCond, Imm, Tmp
    520523    ResCond, Tmp, Tmp
    521524
    522 BranchNeg32 U:G, UD:G /branch
     525BranchNeg32 U:G:32, UZD:G:32 /branch
    523526    ResCond, Tmp
    524527
    525 64: BranchNeg64 U:G, UD:G /branch
     52864: BranchNeg64 U:G:32, UZD:G:64 /branch
    526529    ResCond, Tmp
    527530
    528 MoveConditionally32 U:G, U:G, U:G, U:G, UD:G
     531MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
    529532    RelCond, Tmp, Tmp, Tmp, Tmp
    530533
    531 64: MoveConditionally64 U:G, U:G, U:G, U:G, UD:G
     53464: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
    532535    RelCond, Tmp, Tmp, Tmp, Tmp
    533536
    534 MoveConditionallyTest32 U:G, U:G, U:G, U:G, UD:G
     537MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
    535538    ResCond, Tmp, Tmp, Tmp, Tmp
    536539    ResCond, Tmp, Imm, Tmp, Tmp
    537540
    538 64: MoveConditionallyTest64 U:G, U:G, U:G, U:G, UD:G
     54164: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
    539542    ResCond, Tmp, Tmp, Tmp, Tmp
    540543    ResCond, Tmp, Imm, Tmp, Tmp
    541544
    542 MoveConditionallyDouble U:G, U:F, U:F, U:G, UD:G
     545MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr
    543546    DoubleCond, Tmp, Tmp, Tmp, Tmp
    544547
    545 MoveConditionallyFloat U:G, U:F, U:F, U:G, UD:G
     548MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
    546549    DoubleCond, Tmp, Tmp, Tmp, Tmp
    547550
    548 MoveDoubleConditionally32 U:G, U:G, U:G, U:F, UD:F
     551MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
    549552    RelCond, Tmp, Tmp, Tmp, Tmp
    550553
    551 64: MoveDoubleConditionally64 U:G, U:G, U:G, U:F, UD:F
     55464: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
    552555    RelCond, Tmp, Tmp, Tmp, Tmp
    553556
    554 MoveDoubleConditionallyTest32 U:G, U:G, U:G, U:F, UD:F
     557MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
    555558    ResCond, Tmp, Tmp, Tmp, Tmp
    556559    ResCond, Tmp, Imm, Tmp, Tmp
    557560
    558 64: MoveDoubleConditionallyTest64 U:G, U:G, U:G, U:F, UD:F
     56164: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
    559562    ResCond, Tmp, Tmp, Tmp, Tmp
    560563    ResCond, Tmp, Imm, Tmp, Tmp
    561564
    562 MoveDoubleConditionallyDouble U:G, U:F, U:F, U:F, UD:F
     565MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, UD:F:64
    563566    DoubleCond, Tmp, Tmp, Tmp, Tmp
    564567
    565 MoveDoubleConditionallyFloat U:G, U:F, U:F, U:F, UD:F
     568MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, UD:F:64
    566569    DoubleCond, Tmp, Tmp, Tmp, Tmp
    567570
  • trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp

    r192539 r194331  
    149149        case BranchTest32:
    150150        case BranchTest64:
     151        case BranchFloat:
    151152        case BranchDouble:
    152153        case BranchAdd32:
  • trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp

    r192863 r194331  
    6868            inst.forEachTmpWithExtraClobberedRegs(
    6969                index < block->size() ? &block->at(index) : nullptr,
    70                 [&registerSet] (const Tmp& tmp, Arg::Role role, Arg::Type) {
     70                [&registerSet] (const Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
    7171                    if (tmp.isReg() && Arg::isDef(role))
    7272                        registerSet.set(tmp.reg());
    … …  
    120120            // Now fall back on spilling using separate Move's to load/store the tmp.
    121121            inst.forEachTmp(
    122                 [&] (Tmp& tmp, Arg::Role role, Arg::Type type) {
     122                [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width) {
    123123                    if (tmp.isReg())
    124124                        return;
    … …  
    141141                        break;
    142142                    case Arg::Def:
     143                    case Arg::ZDef:
    143144                        for (Reg reg : regsInPriorityOrder(type)) {
    144145                            if (!setAfter.get(reg)) {
    … …  
    150151                        break;
    151152                    case Arg::UseDef:
     153                    case Arg::UseZDef:
    152154                    case Arg::LateUse:
    153155                        for (Reg reg : regsInPriorityOrder(type)) {
  • trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h

    r192863 r194331  
    7878            for (Inst& inst : *block) {
    7979                inst.forEach<Thing>(
    80                     [&] (Thing& arg, Arg::Role role, Arg::Type) {
     80                    [&] (Thing& arg, Arg::Role role, Arg::Type, Arg::Width) {
    8181                        Counts& counts = m_counts.add(arg, Counts()).iterator->value;
    8282
  • trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb

    r194045 r194331  
    4545
    4646class Arg
    47     attr_reader :role, :type
    48 
    49     def initialize(role, type)
     47    attr_reader :role, :type, :width
     48
     49    def initialize(role, type, width)
    5050        @role = role
    5151        @type = type
     52        @width = width
    5253    end
    5354end
    … …  
    174175
    175176def isUD(token)
    176     token =~ /\A((U)|(D)|(UD)|(UA))\Z/
     177    token =~ /\A((U)|(D)|(UD)|(ZD)|(UZD)|(UA))\Z/
    177178end
    178179
    … …  
    189190end
    190191
     192def isWidth(token)
     193    token =~ /\A((8)|(16)|(32)|(64)|(Ptr))\Z/
     194end
     195
    191196def isKeyword(token)
    192     isUD(token) or isGF(token) or isKind(token) or isArch(token) or
     197    isUD(token) or isGF(token) or isKind(token) or isArch(token) or isWidth(token) or
    193198        token == "special" or token == "as"
    194199end
    … …  
    253258        result = token.string
    254259        parseError("Expected kind (Imm, Imm64, Tmp, Addr, Index, RelCond, ResCond, or DoubleCond)") unless isKind(result)
     260        advance
     261        result
     262    end
     263
     264    def consumeWidth
     265        result = token.string
     266        parseError("Expected width (8, 16, 32, or 64)") unless isWidth(result)
    255267        advance
    256268        result
    … …  
    351363                        consume(":")
    352364                        type = consumeType
     365                        consume(":")
     366                        width = consumeWidth
    353367                       
    354                         signature << Arg.new(role, type)
     368                        signature << Arg.new(role, type, width)
    355369                       
    356370                        break unless token == ","
    … …  
    607621        | opcode, overload |
    608622        if opcode.special
    609             outp.puts "functor(args[0], Arg::Use, Arg::GP); // This is basically bogus, but it works f analyses model Special as an immediate."
     623            outp.puts "functor(args[0], Arg::Use, Arg::GP, Arg::pointerWidth()); // This is basically bogus, but it works for analyses that model Special as an immediate."
    610624            outp.puts "args[0].special()->forEachArg(*this, scopedLambda<EachArgCallback>(functor));"
    611625        else
    612626            overload.signature.each_with_index {
    613627                | arg, index |
     628               
    614629                role = nil
    615630                case arg.role
    … …  
    618633                when "D"
    619634                    role = "Def"
     635                when "ZD"
     636                    role = "ZDef"
    620637                when "UD"
    621638                    role = "UseDef"
     639                when "UZD"
     640                    role = "UseZDef"
    622641                when "UA"
    623642                    role = "UseAddr"
    … …  
    625644                    raise
    626645                end
     646
     647                if arg.width == "Ptr"
     648                    width = "Arg::pointerWidth()"
     649                else
     650                    width = "Arg::Width#{arg.width}"
     651                end
    627652               
    628                 outp.puts "functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P);"
     653                outp.puts "functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{width});"
    629654            }
    630655        end
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r194320 r194331  
    63676367    value = -1;
    63686368    CHECK(invoke<int>(*code, &value - 2, 1) == 42);
     6369}
     6370
     6371void testCheckTrickyMegaCombo()
     6372{
     6373    Procedure proc;
     6374    BasicBlock* root = proc.addBlock();
     6375    Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     6376    Value* index = root->appendNew<Value>(
     6377        proc, ZExt32, Origin(),
     6378        root->appendNew<Value>(
     6379            proc, Add, Origin(),
     6380            root->appendNew<Value>(
     6381                proc, Trunc, Origin(),
     6382                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)),
     6383            root->appendNew<Const32Value>(proc, Origin(), 1)));
     6384
     6385    Value* ptr = root->appendNew<Value>(
     6386        proc, Add, Origin(), base,
     6387        root->appendNew<Value>(
     6388            proc, Shl, Origin(), index,
     6389            root->appendNew<Const32Value>(proc, Origin(), 1)));
     6390   
     6391    CheckValue* check = root->appendNew<CheckValue>(
     6392        proc, Check, Origin(),
     6393        root->appendNew<Value>(
     6394            proc, LessThan, Origin(),
     6395            root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr),
     6396            root->appendNew<Const32Value>(proc, Origin(), 42)));
     6397    check->setGenerator(
     6398        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     6399            AllowMacroScratchRegisterUsage allowScratch(jit);
     6400            CHECK(!params.size());
     6401
     6402            // This should always work because a function this simple should never have callee
     6403            // saves.
     6404            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
     6405            jit.emitFunctionEpilogue();
     6406            jit.ret();
     6407        });
     6408    root->appendNew<ControlValue>(
     6409        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
     6410
     6411    auto code = compile(proc);
     6412
     6413    int8_t value;
     6414    value = 42;
     6415    CHECK(invoke<int>(*code, &value - 2, 0) == 0);
     6416    value = 127;
     6417    CHECK(invoke<int>(*code, &value - 2, 0) == 0);
     6418    value = 41;
     6419    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
     6420    value = 0;
     6421    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
     6422    value = -1;
     6423    CHECK(invoke<int>(*code, &value - 2, 0) == 42);
    63696424}
    63706425
    … …  
    94759530    RUN(testCheckLessThan());
    94769531    RUN(testCheckMegaCombo());
     9532    RUN(testCheckTrickyMegaCombo());
    94779533    RUN(testCheckTwoMegaCombos());
    94789534    RUN(testCheckTwoNonRedundantMegaCombos());
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r194314 r194331  
    42194219        for (unsigned i = 1; i < numKids; ++i) {
    42204220            flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
     4221#if FTL_USES_B3
     4222            B3::CheckValue* lengthCheck = m_out.speculateAdd(
     4223                length, m_out.load32(kids[i], m_heaps.JSString_length));
     4224            blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin);
     4225            length = lengthCheck;
     4226#else // FTL_USES_B3           
    42214227            LValue lengthAndOverflow = m_out.addWithOverflow32(
    42224228                length, m_out.load32(kids[i], m_heaps.JSString_length));
    42234229            speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1));
    42244230            length = m_out.extractValue(lengthAndOverflow, 0);
     4231#endif // FTL_USES_B3
    42254232        }
    42264233        m_out.store32(
  • trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp

    r193362 r194331  
    4040    jit.pushToSaveImmediateWithoutTouchingRegisters(CCallHelpers::TrustedImm32(index));
    4141    CCallHelpers::PatchableJump jump = jit.patchableJump();
     42    RefPtr<OSRExitHandle> self = this;
    4243    jit.addLinkTask(
    43         [this, jump] (LinkBuffer& linkBuffer) {
    44             exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump));
     44        [self, jump] (LinkBuffer& linkBuffer) {
     45            self->exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump));
    4546
    4647            linkBuffer.link(
Note: See TracChangeset for help on using the changeset viewer.