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

Changeset 196513 in webkit


Ignore:
Timestamp:
Feb 12, 2016, 2:32:44 PM (11 years ago)
Author:
benjamin@webkit.org
Message:

[JSC] On x86, improve the selection of which value are selected for the UseDef part of commutative operations
https://bugs.webkit.org/show_bug.cgi?id=154151

Reviewed by Filip Pizlo.

Previously, when an instruction destroy an argument with
a UseDef use, we would try to pick a good target for the UseDef
while doing instruction selection.

For example:

@x = Add(@1, @2)

can be lowered to:

Move @1 Tmp3
Add @2 Tmp3

or

Move @2 Tmp3
Add @1 Tmp3

The choice of which value ends up copied is done by preferRightForResult()
at lowering time.

There are two common problems with the code we generate:
1) It is based on UseCount. If a value is at its last use,

it is a good target for coalescing even with a use-count > 1.

2) When both values are at their last use, the best choice

depends on the register pressure of each. We don't have that information
until we do register allocation.

This patch implements a simple idea to minimize how many of those Moves are needed.
Each commutative operation gets a 3 op variant. The register allocator then attempts
to alias *both* of them to the destination.
Since our aliasing is conservative, it removes as many copy as possible without causing
spilling.

There was an unexpected cool impovement too. If you have:

Move Tmp1, Tmp2
BranchAdd32 Tmp3, Tmp2

we would previously restore Tmp2 by substracting Tmp3 from the result.
We can now just use Tmp1. That removes quite a few Sub from the slow paths.

The problem is that simple idea uncoverred a bunch of issues that had to be fixed too.
I detail them inline below.

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::and64):

  • assembler/MacroAssemblerX86Common.h:

Most addition are adding an Address version of the 3 operands opcodes.
The reason for this is allow the complex addressing forms of instructions
when spilling.

(JSC::MacroAssemblerX86Common::and32):
(JSC::MacroAssemblerX86Common::mul32):
(JSC::MacroAssemblerX86Common::or32):
(JSC::MacroAssemblerX86Common::xor32):
(JSC::MacroAssemblerX86Common::moveDouble):
This was an unexpected discovery: removing tons of Move32 made floating-point heavy
code much slower.

It turns out the MoveDouble we were using has partial register dependencies.

The x86 optimization manual, Chapter 3, section 3.4.1.13 lists the move instructions executed
directly on the frontend. That's what we use now.

(JSC::MacroAssemblerX86Common::addDouble):
(JSC::MacroAssemblerX86Common::addFloat):
(JSC::MacroAssemblerX86Common::mulDouble):
(JSC::MacroAssemblerX86Common::mulFloat):
(JSC::MacroAssemblerX86Common::andDouble):
(JSC::MacroAssemblerX86Common::andFloat):
(JSC::MacroAssemblerX86Common::xorDouble):
(JSC::MacroAssemblerX86Common::xorFloat):
If the destination is not aliased, the version taking an address
use LoadFloat/LoadDouble instead of direct addressing.

That is because this:

Move Tmp1, Tmp2
Op [Tmp3], Tmp2

is slower than

Move [Tmp3] Tmp2
Op Tmp1, Tmp2

(sometimes significantly).

I am not exactly sure why.

(JSC::MacroAssemblerX86Common::branchAdd32):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::and64):

  • assembler/MacroAssemblerARM64.h:

(JSC::MacroAssemblerARM64::and64):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::and32):
(JSC::MacroAssemblerX86Common::mul32):
(JSC::MacroAssemblerX86Common::or32):
(JSC::MacroAssemblerX86Common::xor32):
(JSC::MacroAssemblerX86Common::moveDouble):
(JSC::MacroAssemblerX86Common::addDouble):
(JSC::MacroAssemblerX86Common::addFloat):
(JSC::MacroAssemblerX86Common::mulDouble):
(JSC::MacroAssemblerX86Common::mulFloat):
(JSC::MacroAssemblerX86Common::andDouble):
(JSC::MacroAssemblerX86Common::andFloat):
(JSC::MacroAssemblerX86Common::xorDouble):
(JSC::MacroAssemblerX86Common::xorFloat):
(JSC::MacroAssemblerX86Common::branchAdd32):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::and64):
(JSC::MacroAssemblerX86_64::mul64):
(JSC::MacroAssemblerX86_64::xor64):
(JSC::MacroAssemblerX86_64::branchAdd64):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::movapd_rr):
(JSC::X86Assembler::movaps_rr):

  • b3/B3CheckSpecial.cpp:

(JSC::B3::CheckSpecial::shouldTryAliasingDef):
(JSC::B3::CheckSpecial::generate):

  • b3/B3CheckSpecial.h:
  • b3/B3LowerToAir.cpp:

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

  • b3/air/AirCustom.h:

(JSC::B3::Air::PatchCustom::shouldTryAliasingDef):

  • b3/air/AirInst.h:
  • b3/air/AirInstInlines.h:

(JSC::B3::Air::Inst::shouldTryAliasingDef):

  • b3/air/AirIteratedRegisterCoalescing.cpp:

Aliasing the operands is done the same way as any coalescing.

There were problem with considering all those coalescing
as equivalent for the result.

Moves are mostly generated for Upsilon-Phis. Getting rid of
those tends to give better loops.

Sometimes, blocks have only Phis and a Jump. Coalescing
those moves gets rids of the block entirely.

Where it go interesting was that something like:

Move Tmp1, Tmp2
Op Tmp3, Tmp2

was significantly better than:

Op Tmp1, Tmp3
Move Tmp1, Tmp4

even in the same basic block.

To get back to the same performance when, I had to prioritize
regular Moves operations over argument coalescing.

Another argument for doing this is that the alias has a shorter
life in the hardware because the operation itself gets a new
virtual register from the bank.

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

(JSC::B3::Air::Special::shouldTryAliasingDef):

  • b3/air/AirSpecial.h:
  • b3/testb3.cpp:

(JSC::B3::testCheckAddArgumentAliasing64):
(JSC::B3::testCheckAddArgumentAliasing32):
(JSC::B3::testCheckAddSelfOverflow64):
(JSC::B3::testCheckAddSelfOverflow32):
(JSC::B3::testCheckMulArgumentAliasing64):
(JSC::B3::testCheckMulArgumentAliasing32):
(JSC::B3::run):

  • dfg/DFGOSRExitCompilerCommon.cpp:

(JSC::DFG::reifyInlinedCallFrames):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::emitSaveOrCopyCalleeSavesFor):
This ruined my week.

When regenerating the frame of an inlined function that
was called through a tail call, we were ignoring r13 for some reason.

Since this patch makes it more likely to increase the degree
of each Tmp, the number of register used increased and r13 was more
commonly used.

When getting out of OSRExit, we would have that value trashed :(

The fix is simply to restore it like the other two Baseline callee saved
register.

Location:
trunk/Source/JavaScriptCore
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r196498 r196513  
     12016-02-12  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        [JSC] On x86, improve the selection of which value are selected for the UseDef part of commutative operations
     4        https://bugs.webkit.org/show_bug.cgi?id=154151
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Previously, when an instruction destroy an argument with
     9        a UseDef use, we would try to pick a good target for the UseDef
     10        while doing instruction selection.
     11
     12        For example:
     13            @x = Add(@1, @2)
     14
     15        can be lowered to:
     16            Move @1 Tmp3
     17            Add @2 Tmp3
     18        or
     19            Move @2 Tmp3
     20            Add @1 Tmp3
     21
     22        The choice of which value ends up copied is done by preferRightForResult()
     23        at lowering time.
     24
     25        There are two common problems with the code we generate:
     26        1) It is based on UseCount. If a value is at its last use,
     27           it is a good target for coalescing even with a use-count > 1.
     28        2) When both values are at their last use, the best choice
     29           depends on the register pressure of each. We don't have that information
     30           until we do register allocation.
     31
     32        This patch implements a simple idea to minimize how many of those Moves are needed.
     33        Each commutative operation gets a 3 op variant. The register allocator then attempts
     34        to alias *both* of them to the destination.
     35        Since our aliasing is conservative, it removes as many copy as possible without causing
     36        spilling.
     37
     38        There was an unexpected cool impovement too. If you have:
     39            Move Tmp1, Tmp2
     40            BranchAdd32 Tmp3, Tmp2
     41        we would previously restore Tmp2 by substracting Tmp3 from the result.
     42        We can now just use Tmp1. That removes quite a few Sub from the slow paths.
     43
     44        The problem is that simple idea uncoverred a bunch of issues that had to be fixed too.
     45        I detail them inline below.
     46
     47        * assembler/MacroAssemblerARM64.h:
     48        (JSC::MacroAssemblerARM64::and64):
     49        * assembler/MacroAssemblerX86Common.h:
     50        Most addition are adding an Address version of the 3 operands opcodes.
     51        The reason for this is allow the complex addressing forms of instructions
     52        when spilling.
     53
     54        (JSC::MacroAssemblerX86Common::and32):
     55        (JSC::MacroAssemblerX86Common::mul32):
     56        (JSC::MacroAssemblerX86Common::or32):
     57        (JSC::MacroAssemblerX86Common::xor32):
     58        (JSC::MacroAssemblerX86Common::moveDouble):
     59        This was an unexpected discovery: removing tons of Move32 made floating-point heavy
     60        code much slower.
     61
     62        It turns out the MoveDouble we were using has partial register dependencies.
     63
     64        The x86 optimization manual, Chapter 3, section 3.4.1.13 lists the move instructions executed
     65        directly on the frontend. That's what we use now.
     66
     67        (JSC::MacroAssemblerX86Common::addDouble):
     68        (JSC::MacroAssemblerX86Common::addFloat):
     69        (JSC::MacroAssemblerX86Common::mulDouble):
     70        (JSC::MacroAssemblerX86Common::mulFloat):
     71        (JSC::MacroAssemblerX86Common::andDouble):
     72        (JSC::MacroAssemblerX86Common::andFloat):
     73        (JSC::MacroAssemblerX86Common::xorDouble):
     74        (JSC::MacroAssemblerX86Common::xorFloat):
     75        If the destination is not aliased, the version taking an address
     76        use LoadFloat/LoadDouble instead of direct addressing.
     77
     78        That is because this:
     79            Move Tmp1, Tmp2
     80            Op [Tmp3], Tmp2
     81        is slower than
     82            Move [Tmp3] Tmp2
     83            Op Tmp1, Tmp2
     84        (sometimes significantly).
     85
     86        I am not exactly sure why.
     87
     88        (JSC::MacroAssemblerX86Common::branchAdd32):
     89        * assembler/MacroAssemblerX86_64.h:
     90        (JSC::MacroAssemblerX86_64::and64):
     91        * assembler/MacroAssemblerARM64.h:
     92        (JSC::MacroAssemblerARM64::and64):
     93        * assembler/MacroAssemblerX86Common.h:
     94        (JSC::MacroAssemblerX86Common::and32):
     95        (JSC::MacroAssemblerX86Common::mul32):
     96        (JSC::MacroAssemblerX86Common::or32):
     97        (JSC::MacroAssemblerX86Common::xor32):
     98        (JSC::MacroAssemblerX86Common::moveDouble):
     99        (JSC::MacroAssemblerX86Common::addDouble):
     100        (JSC::MacroAssemblerX86Common::addFloat):
     101        (JSC::MacroAssemblerX86Common::mulDouble):
     102        (JSC::MacroAssemblerX86Common::mulFloat):
     103        (JSC::MacroAssemblerX86Common::andDouble):
     104        (JSC::MacroAssemblerX86Common::andFloat):
     105        (JSC::MacroAssemblerX86Common::xorDouble):
     106        (JSC::MacroAssemblerX86Common::xorFloat):
     107        (JSC::MacroAssemblerX86Common::branchAdd32):
     108        * assembler/MacroAssemblerX86_64.h:
     109        (JSC::MacroAssemblerX86_64::and64):
     110        (JSC::MacroAssemblerX86_64::mul64):
     111        (JSC::MacroAssemblerX86_64::xor64):
     112        (JSC::MacroAssemblerX86_64::branchAdd64):
     113        * assembler/X86Assembler.h:
     114        (JSC::X86Assembler::movapd_rr):
     115        (JSC::X86Assembler::movaps_rr):
     116        * b3/B3CheckSpecial.cpp:
     117        (JSC::B3::CheckSpecial::shouldTryAliasingDef):
     118        (JSC::B3::CheckSpecial::generate):
     119        * b3/B3CheckSpecial.h:
     120        * b3/B3LowerToAir.cpp:
     121        (JSC::B3::Air::LowerToAir::lower):
     122        * b3/air/AirCustom.h:
     123        (JSC::B3::Air::PatchCustom::shouldTryAliasingDef):
     124        * b3/air/AirInst.h:
     125        * b3/air/AirInstInlines.h:
     126        (JSC::B3::Air::Inst::shouldTryAliasingDef):
     127        * b3/air/AirIteratedRegisterCoalescing.cpp:
     128        Aliasing the operands is done the same way as any coalescing.
     129
     130        There were problem with considering all those coalescing
     131        as equivalent for the result.
     132
     133        Moves are mostly generated for Upsilon-Phis. Getting rid of
     134        those tends to give better loops.
     135
     136        Sometimes, blocks have only Phis and a Jump. Coalescing
     137        those moves gets rids of the block entirely.
     138
     139        Where it go interesting was that something like:
     140            Move Tmp1, Tmp2
     141            Op Tmp3, Tmp2
     142        was significantly better than:
     143            Op Tmp1, Tmp3
     144            Move Tmp1, Tmp4
     145        even in the same basic block.
     146
     147        To get back to the same performance when, I had to prioritize
     148        regular Moves operations over argument coalescing.
     149
     150        Another argument for doing this is that the alias has a shorter
     151        life in the hardware because the operation itself gets a new
     152        virtual register from the bank.
     153
     154        * b3/air/AirOpcode.opcodes:
     155        * b3/air/AirSpecial.cpp:
     156        (JSC::B3::Air::Special::shouldTryAliasingDef):
     157        * b3/air/AirSpecial.h:
     158        * b3/testb3.cpp:
     159        (JSC::B3::testCheckAddArgumentAliasing64):
     160        (JSC::B3::testCheckAddArgumentAliasing32):
     161        (JSC::B3::testCheckAddSelfOverflow64):
     162        (JSC::B3::testCheckAddSelfOverflow32):
     163        (JSC::B3::testCheckMulArgumentAliasing64):
     164        (JSC::B3::testCheckMulArgumentAliasing32):
     165        (JSC::B3::run):
     166
     167        * dfg/DFGOSRExitCompilerCommon.cpp:
     168        (JSC::DFG::reifyInlinedCallFrames):
     169        * jit/AssemblyHelpers.h:
     170        (JSC::AssemblyHelpers::emitSaveOrCopyCalleeSavesFor):
     171        This ruined my week.
     172
     173        When regenerating the frame of an inlined function that
     174        was called through a tail call, we were ignoring r13 for some reason.
     175
     176        Since this patch makes it more likely to increase the degree
     177        of each Tmp, the number of register used increased and r13 was more
     178        commonly used.
     179
     180        When getting out of OSRExit, we would have that value trashed :(
     181
     182        The fix is simply to restore it like the other two Baseline callee saved
     183        register.
     184
    11852016-02-12  Yusuke Suzuki  <utatane.tea@gmail.com>
    2186
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

    r196152 r196513  
    363363    }
    364364
     365    void and64(RegisterID src1, RegisterID src2, RegisterID dest)
     366    {
     367        m_assembler.and_<64>(dest, src1, src2);
     368    }
     369
    365370    void and64(RegisterID src, RegisterID dest)
    366371    {
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r196433 r196513  
    268268    }
    269269
     270    void and32(Address op1, RegisterID op2, RegisterID dest)
     271    {
     272        move(op2, dest);
     273        and32(op1, dest);
     274    }
     275
     276    void and32(RegisterID op1, Address op2, RegisterID dest)
     277    {
     278        move(op1, dest);
     279        and32(op2, dest);
     280    }
     281
    270282    void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
    271283    {
     
    335347    }
    336348
     349    void mul32(RegisterID src1, RegisterID src2, RegisterID dest)
     350    {
     351        if (src2 == dest) {
     352            m_assembler.imull_rr(src1, dest);
     353            return;
     354        }
     355        move(src1, dest);
     356        m_assembler.imull_rr(src2, dest);
     357    }
     358
    337359    void mul32(Address src, RegisterID dest)
    338360    {
    339361        m_assembler.imull_mr(src.offset, src.base, dest);
     362    }
     363
     364    void mul32(Address src1, RegisterID src2, RegisterID dest)
     365    {
     366        move(src2, dest);
     367        mul32(src1, dest);
     368    }
     369
     370    void mul32(RegisterID src1, Address src2, RegisterID dest)
     371    {
     372        move(src1, dest);
     373        mul32(src2, dest);
    340374    }
    341375   
     
    414448            or32(op1, dest);
    415449        }
     450    }
     451
     452    void or32(Address op1, RegisterID op2, RegisterID dest)
     453    {
     454        move(op2, dest);
     455        or32(op1, dest);
     456    }
     457
     458    void or32(RegisterID op1, Address op2, RegisterID dest)
     459    {
     460        move(op1, dest);
     461        or32(op2, dest);
    416462    }
    417463
     
    567613    }
    568614
     615    void xor32(Address op1, RegisterID op2, RegisterID dest)
     616    {
     617        move(op2, dest);
     618        xor32(op1, dest);
     619    }
     620
     621    void xor32(RegisterID op1, Address op2, RegisterID dest)
     622    {
     623        move(op1, dest);
     624        xor32(op2, dest);
     625    }
     626
    569627    void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
    570628    {
     
    906964        ASSERT(isSSE2Present());
    907965        if (src != dest)
    908             m_assembler.movsd_rr(src, dest);
     966            m_assembler.movaps_rr(src, dest);
    909967    }
    910968
     
    10151073    }
    10161074
     1075    void addDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
     1076    {
     1077        ASSERT(isSSE2Present());
     1078        if (op2 == dest) {
     1079            addDouble(op1, dest);
     1080            return;
     1081        }
     1082
     1083        loadDouble(op1, dest);
     1084        addDouble(op2, dest);
     1085    }
     1086
     1087    void addDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
     1088    {
     1089        ASSERT(isSSE2Present());
     1090        if (op1 == dest) {
     1091            addDouble(op2, dest);
     1092            return;
     1093        }
     1094
     1095        loadDouble(op2, dest);
     1096        addDouble(op1, dest);
     1097    }
     1098
    10171099    void addFloat(FPRegisterID src, FPRegisterID dest)
    10181100    {
     
    10251107        ASSERT(isSSE2Present());
    10261108        m_assembler.addss_mr(src.offset, src.base, dest);
     1109    }
     1110
     1111    void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
     1112    {
     1113        ASSERT(isSSE2Present());
     1114        if (op1 == dest)
     1115            addFloat(op2, dest);
     1116        else {
     1117            moveDouble(op2, dest);
     1118            addFloat(op1, dest);
     1119        }
     1120    }
     1121
     1122    void addFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
     1123    {
     1124        ASSERT(isSSE2Present());
     1125        if (op2 == dest) {
     1126            addFloat(op1, dest);
     1127            return;
     1128        }
     1129
     1130        loadFloat(op1, dest);
     1131        addFloat(op2, dest);
     1132    }
     1133
     1134    void addFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
     1135    {
     1136        ASSERT(isSSE2Present());
     1137        if (op1 == dest) {
     1138            addFloat(op2, dest);
     1139            return;
     1140        }
     1141
     1142        loadFloat(op2, dest);
     1143        addFloat(op1, dest);
    10271144    }
    10281145
     
    11161233    }
    11171234
     1235    void mulDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
     1236    {
     1237        ASSERT(isSSE2Present());
     1238        if (op2 == dest) {
     1239            mulDouble(op1, dest);
     1240            return;
     1241        }
     1242        loadDouble(op1, dest);
     1243        mulDouble(op2, dest);
     1244    }
     1245
     1246    void mulDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
     1247    {
     1248        ASSERT(isSSE2Present());
     1249        if (op1 == dest) {
     1250            mulDouble(op2, dest);
     1251            return;
     1252        }
     1253        loadDouble(op2, dest);
     1254        mulDouble(op1, dest);
     1255    }
     1256
    11181257    void mulFloat(FPRegisterID src, FPRegisterID dest)
    11191258    {
     
    11261265        ASSERT(isSSE2Present());
    11271266        m_assembler.mulss_mr(src.offset, src.base, dest);
     1267    }
     1268
     1269    void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
     1270    {
     1271        ASSERT(isSSE2Present());
     1272        if (op1 == dest)
     1273            mulFloat(op2, dest);
     1274        else {
     1275            moveDouble(op2, dest);
     1276            mulFloat(op1, dest);
     1277        }
     1278    }
     1279
     1280    void mulFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
     1281    {
     1282        ASSERT(isSSE2Present());
     1283        if (op2 == dest) {
     1284            mulFloat(op1, dest);
     1285            return;
     1286        }
     1287        loadFloat(op1, dest);
     1288        mulFloat(op2, dest);
     1289    }
     1290
     1291    void mulFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
     1292    {
     1293        ASSERT(isSSE2Present());
     1294        if (op1 == dest) {
     1295            mulFloat(op2, dest);
     1296            return;
     1297        }
     1298        loadFloat(op2, dest);
     1299        mulFloat(op1, dest);
    11281300    }
    11291301
     
    11341306    }
    11351307
     1308    void andDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
     1309    {
     1310        if (src1 == dst)
     1311            andDouble(src2, dst);
     1312        else {
     1313            moveDouble(src2, dst);
     1314            andDouble(src1, dst);
     1315        }
     1316    }
     1317
    11361318    void andFloat(FPRegisterID src, FPRegisterID dst)
    11371319    {
     
    11391321    }
    11401322
     1323    void andFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
     1324    {
     1325        if (src1 == dst)
     1326            andFloat(src2, dst);
     1327        else {
     1328            moveDouble(src2, dst);
     1329            andFloat(src1, dst);
     1330        }
     1331    }
     1332
    11411333    void xorDouble(FPRegisterID src, FPRegisterID dst)
    11421334    {
     
    11441336    }
    11451337
     1338    void xorDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
     1339    {
     1340        if (src1 == dst)
     1341            xorDouble(src2, dst);
     1342        else {
     1343            moveDouble(src2, dst);
     1344            xorDouble(src1, dst);
     1345        }
     1346    }
     1347
    11461348    void xorFloat(FPRegisterID src, FPRegisterID dst)
    11471349    {
    11481350        m_assembler.xorps_rr(src, dst);
     1351    }
     1352
     1353    void xorFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
     1354    {
     1355        if (src1 == dst)
     1356            xorFloat(src2, dst);
     1357        else {
     1358            moveDouble(src2, dst);
     1359            xorFloat(src1, dst);
     1360        }
    11491361    }
    11501362
     
    17091921        move(src2, dest);
    17101922        return branchAdd32(cond, src1, dest);
     1923    }
     1924
     1925    Jump branchAdd32(ResultCondition cond, Address src1, RegisterID src2, RegisterID dest)
     1926    {
     1927        move(src2, dest);
     1928        return branchAdd32(cond, src1, dest);
     1929    }
     1930
     1931    Jump branchAdd32(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest)
     1932    {
     1933        move(src1, dest);
     1934        return branchAdd32(cond, src2, dest);
    17111935    }
    17121936
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r196433 r196513  
    350350    }
    351351
     352    void and64(RegisterID op1, RegisterID op2, RegisterID dest)
     353    {
     354        if (op1 == op2 && op1 != dest && op2 != dest)
     355            move(op1, dest);
     356        else if (op1 == dest)
     357            and64(op2, dest);
     358        else {
     359            move(op2, dest);
     360            and64(op1, dest);
     361        }
     362    }
     363
    352364    void countLeadingZeros64(RegisterID src, RegisterID dst)
    353365    {
     
    431443        m_assembler.imulq_rr(src, dest);
    432444    }
     445
     446    void mul64(RegisterID src1, RegisterID src2, RegisterID dest)
     447    {
     448        if (src2 == dest) {
     449            m_assembler.imulq_rr(src1, dest);
     450            return;
     451        }
     452        move(src1, dest);
     453        m_assembler.imulq_rr(src2, dest);
     454    }
    433455   
    434456    void x86ConvertToQuadWord64()
     
    542564        m_assembler.xorq_rr(src, dest);
    543565    }
     566
     567    void xor64(RegisterID op1, RegisterID op2, RegisterID dest)
     568    {
     569        if (op1 == op2)
     570            move(TrustedImm32(0), dest);
     571        else if (op1 == dest)
     572            xor64(op2, dest);
     573        else {
     574            move(op2, dest);
     575            xor64(op1, dest);
     576        }
     577    }
    544578   
    545579    void xor64(RegisterID src, Address dest)
     
    868902    }
    869903
     904    Jump branchAdd64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
     905    {
     906        if (src1 == dest)
     907            return branchAdd64(cond, src2, dest);
     908        move(src2, dest);
     909        return branchAdd64(cond, src1, dest);
     910    }
     911
     912    Jump branchAdd64(ResultCondition cond, Address src1, RegisterID src2, RegisterID dest)
     913    {
     914        move(src2, dest);
     915        return branchAdd64(cond, src1, dest);
     916    }
     917
     918    Jump branchAdd64(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest)
     919    {
     920        move(src1, dest);
     921        return branchAdd64(cond, src2, dest);
     922    }
     923
    870924    Jump branchAdd64(ResultCondition cond, RegisterID src, RegisterID dest)
     925    {
     926        add64(src, dest);
     927        return Jump(m_assembler.jCC(x86Condition(cond)));
     928    }
     929
     930    Jump branchAdd64(ResultCondition cond, Address src, RegisterID dest)
    871931    {
    872932        add64(src, dest);
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r195549 r196513  
    264264        OP2_MOVSS_VsdWsd    = 0x10,
    265265        OP2_MOVSS_WsdVsd    = 0x11,
     266        OP2_MOVAPD_VpdWpd   = 0x28,
     267        OP2_MOVAPS_VpdWpd   = 0x28,
    266268        OP2_CVTSI2SD_VsdEd  = 0x2A,
    267269        OP2_CVTTSD2SI_GdWsd = 0x2C,
     
    22102212#endif
    22112213
     2214    void movapd_rr(XMMRegisterID src, XMMRegisterID dst)
     2215    {
     2216        m_formatter.prefix(PRE_SSE_66);
     2217        m_formatter.twoByteOp(OP2_MOVAPD_VpdWpd, (RegisterID)dst, (RegisterID)src);
     2218    }
     2219
     2220    void movaps_rr(XMMRegisterID src, XMMRegisterID dst)
     2221    {
     2222        m_formatter.twoByteOp(OP2_MOVAPS_VpdWpd, (RegisterID)dst, (RegisterID)src);
     2223    }
     2224
    22122225    void movsd_rr(XMMRegisterID src, XMMRegisterID dst)
    22132226    {
  • trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp

    r195298 r196513  
    131131}
    132132
     133bool CheckSpecial::shouldTryAliasingDef(Inst& inst, unsigned& defIndex)
     134{
     135    if (hiddenBranch(inst).shouldTryAliasingDef(defIndex)) {
     136        defIndex += 1;
     137        return true;
     138    }
     139    return false;
     140}
     141
    133142CCallHelpers::Jump CheckSpecial::generate(Inst& inst, CCallHelpers& jit, GenerationContext& context)
    134143{
     
    155164                switch (m_checkOpcode) {
    156165                case BranchAdd32:
    157                     if (args[1] == args[2]) {
     166                    if ((m_numCheckArgs == 4 && args[1] == args[2] && args[2] == args[3])
     167                        || (m_numCheckArgs == 3 && args[1] == args[2])) {
    158168                        // This is ugly, but that's fine - we won't have to do this very often.
    159169                        ASSERT(args[1].isGPR());
     
    168178                        break;
    169179                    }
    170                     Inst(Sub32, nullptr, args[1], args[2]).generate(jit, context);
     180                    if (m_numCheckArgs == 4) {
     181                        if (args[1] == args[3])
     182                            Inst(Sub32, nullptr, args[2], args[3]).generate(jit, context);
     183                        else if (args[2] == args[3])
     184                            Inst(Sub32, nullptr, args[1], args[3]).generate(jit, context);
     185                    } else if (m_numCheckArgs == 3)
     186                        Inst(Sub32, nullptr, args[1], args[2]).generate(jit, context);
    171187                    break;
    172188                case BranchAdd64:
    173                     if (args[1] == args[2]) {
     189                    if ((m_numCheckArgs == 4 && args[1] == args[2] && args[2] == args[3])
     190                        || (m_numCheckArgs == 3 && args[1] == args[2])) {
    174191                        // This is ugly, but that's fine - we won't have to do this very often.
    175192                        ASSERT(args[1].isGPR());
     
    184201                        break;
    185202                    }
    186                     Inst(Sub64, nullptr, args[1], args[2]).generate(jit, context);
     203                    if (m_numCheckArgs == 4) {
     204                        if (args[1] == args[3])
     205                            Inst(Sub64, nullptr, args[2], args[3]).generate(jit, context);
     206                        else if (args[2] == args[3])
     207                            Inst(Sub64, nullptr, args[1], args[3]).generate(jit, context);
     208                    } else if (m_numCheckArgs == 3)
     209                        Inst(Sub64, nullptr, args[1], args[2]).generate(jit, context);
    187210                    break;
    188211                case BranchSub32:
  • trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h

    r195298 r196513  
    127127    bool isValid(Air::Inst&) override;
    128128    bool admitsStack(Air::Inst&, unsigned argIndex) override;
     129    bool shouldTryAliasingDef(Air::Inst&, unsigned& defIndex) override;
    129130
    130131    // NOTE: the generate method will generate the hidden branch and then register a LatePath that
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r196045 r196513  
    21472147                sources.append(imm(right));
    21482148                append(Move, tmp(left), result);
    2149             } else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp)) {
     2149            } else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp, Arg::Tmp)) {
     2150                sources.append(tmp(left));
     2151                sources.append(tmp(right));
     2152            }  else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp)) {
    21502153                if (commutativity == Commutative && preferRightForResult(left, right)) {
    21512154                    sources.append(tmp(left));
  • trunk/Source/JavaScriptCore/b3/air/AirCustom.h

    r195298 r196513  
    8181    }
    8282
     83    static bool shouldTryAliasingDef(Inst& inst, unsigned& defIndex)
     84    {
     85        return inst.args[0].special()->shouldTryAliasingDef(inst, defIndex);
     86    }
     87
    8388    static bool hasNonArgNonControlEffects(Inst& inst)
    8489    {
  • trunk/Source/JavaScriptCore/b3/air/AirInst.h

    r195298 r196513  
    181181    CCallHelpers::Jump generate(CCallHelpers&, GenerationContext&);
    182182
     183    // Returns true if the register allocator should attempt to alias the arguments with the destination
     184    // for this instruction.
     185    // If the method returns true, defIndex is set to the index of the destination argument. The indices
     186    // (defIndex - 1) and (defIndex - 2) are the one to alias to defIndex.
     187    bool shouldTryAliasingDef(unsigned& defIndex);
     188
    183189    void dump(PrintStream&) const;
    184190
  • trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h

    r196032 r196513  
    165165}
    166166
     167inline bool Inst::shouldTryAliasingDef(unsigned& defIndex)
     168{
     169    if (!isX86())
     170        return false;
     171
     172    switch (opcode) {
     173    case Add32:
     174    case Add64:
     175    case And32:
     176    case And64:
     177    case Mul32:
     178    case Mul64:
     179    case Or32:
     180    case Or64:
     181    case Xor32:
     182    case Xor64:
     183    case AddDouble:
     184    case AddFloat:
     185    case AndFloat:
     186    case AndDouble:
     187    case MulDouble:
     188    case MulFloat:
     189    case XorDouble:
     190    case XorFloat:
     191        if (args.size() == 3) {
     192            defIndex = 2;
     193            return true;
     194        }
     195        break;
     196    case BranchAdd32:
     197    case BranchAdd64:
     198        if (args.size() == 4) {
     199            defIndex = 3;
     200            return true;
     201        }
     202        break;
     203    case Patch:
     204        return PatchCustom::shouldTryAliasingDef(*this, defIndex);
     205    default:
     206        break;
     207    }
     208    return false;
     209}
     210
    167211inline bool isShiftValid(const Inst& inst)
    168212{
  • trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp

    r196032 r196513  
    170170            if (traceDebug)
    171171                dataLog("    Coalesced\n");
    172         } else if (isPrecolored(v) || m_interferenceEdges.contains(InterferenceEdge(u, v))) {
     172        } else if (isPrecolored(v)
     173            || m_interferenceEdges.contains(InterferenceEdge(u, v))
     174            || (u == m_framePointerIndex && m_interferesWithFramePointer.quickGet(v))) {
    173175            addWorkList(u);
    174176            addWorkList(v);
     
    400402        });
    401403
     404        if (m_framePointerIndex && m_interferesWithFramePointer.quickGet(v))
     405            m_interferesWithFramePointer.quickSet(u);
     406
    402407        if (m_degrees[u] >= m_regsInPriorityOrder.size() && m_freezeWorklist.remove(u))
    403408            addToSpill(u);
     
    575580    Vector<IndexType> m_selectStack;
    576581
     582    IndexType m_framePointerIndex { 0 };
     583    BitVector m_interferesWithFramePointer;
     584
    577585    struct OrderedMoveSet {
    578586        unsigned addMove()
    579587        {
    580             unsigned nextIndex = m_moveList.size();
     588            ASSERT(m_lowPriorityMoveList.isEmpty());
     589            ASSERT(!m_firstLowPriorityMoveIndex);
     590
     591            unsigned nextIndex = m_positionInMoveList.size();
     592            unsigned position = m_moveList.size();
    581593            m_moveList.append(nextIndex);
    582             m_positionInMoveList.append(nextIndex);
     594            m_positionInMoveList.append(position);
    583595            return nextIndex;
    584596        }
    585597
     598        void startAddingLowPriorityMoves()
     599        {
     600            ASSERT(m_lowPriorityMoveList.isEmpty());
     601            m_firstLowPriorityMoveIndex = m_moveList.size();
     602        }
     603
     604        unsigned addLowPriorityMove()
     605        {
     606            ASSERT(m_firstLowPriorityMoveIndex == m_moveList.size());
     607
     608            unsigned nextIndex = m_positionInMoveList.size();
     609            unsigned position = m_lowPriorityMoveList.size();
     610            m_lowPriorityMoveList.append(nextIndex);
     611            m_positionInMoveList.append(position);
     612
     613            ASSERT(nextIndex >= m_firstLowPriorityMoveIndex);
     614
     615            return nextIndex;
     616        }
     617
    586618        bool isEmpty() const
    587619        {
    588             return m_moveList.isEmpty();
     620            return m_moveList.isEmpty() && m_lowPriorityMoveList.isEmpty();
    589621        }
    590622
     
    600632                return;
    601633
    602             ASSERT(m_moveList[positionInMoveList] == moveIndex);
    603             unsigned lastIndex = m_moveList.last();
    604             m_positionInMoveList[lastIndex] = positionInMoveList;
    605             m_moveList[positionInMoveList] = lastIndex;
    606             m_moveList.removeLast();
     634            if (moveIndex < m_firstLowPriorityMoveIndex) {
     635                ASSERT(m_moveList[positionInMoveList] == moveIndex);
     636                unsigned lastIndex = m_moveList.last();
     637                m_positionInMoveList[lastIndex] = positionInMoveList;
     638                m_moveList[positionInMoveList] = lastIndex;
     639                m_moveList.removeLast();
     640            } else {
     641                ASSERT(m_lowPriorityMoveList[positionInMoveList] == moveIndex);
     642                unsigned lastIndex = m_lowPriorityMoveList.last();
     643                m_positionInMoveList[lastIndex] = positionInMoveList;
     644                m_lowPriorityMoveList[positionInMoveList] = lastIndex;
     645                m_lowPriorityMoveList.removeLast();
     646            }
    607647
    608648            m_positionInMoveList[moveIndex] = std::numeric_limits<unsigned>::max();
     
    615655            ASSERT(!isEmpty());
    616656
    617             unsigned lastIndex = m_moveList.takeLast();
    618             ASSERT(m_positionInMoveList[lastIndex] == m_moveList.size());
     657            unsigned lastIndex;
     658            if (!m_moveList.isEmpty()) {
     659                lastIndex = m_moveList.takeLast();
     660                ASSERT(m_positionInMoveList[lastIndex] == m_moveList.size());
     661            } else {
     662                lastIndex = m_lowPriorityMoveList.takeLast();
     663                ASSERT(m_positionInMoveList[lastIndex] == m_lowPriorityMoveList.size());
     664            }
    619665            m_positionInMoveList[lastIndex] = std::numeric_limits<unsigned>::max();
    620666
     
    630676            ASSERT(!contains(index));
    631677
    632             unsigned position = m_moveList.size();
    633             m_moveList.append(index);
    634             m_positionInMoveList[index] = position;
     678            if (index < m_firstLowPriorityMoveIndex) {
     679                unsigned position = m_moveList.size();
     680                m_moveList.append(index);
     681                m_positionInMoveList[index] = position;
     682            } else {
     683                unsigned position = m_lowPriorityMoveList.size();
     684                m_lowPriorityMoveList.append(index);
     685                m_positionInMoveList[index] = position;
     686            }
    635687
    636688            ASSERT(contains(index));
     
    641693            m_positionInMoveList.clear();
    642694            m_moveList.clear();
     695            m_lowPriorityMoveList.clear();
    643696        }
    644697
     
    646699        Vector<unsigned, 0, UnsafeVectorOverflow> m_positionInMoveList;
    647700        Vector<unsigned, 0, UnsafeVectorOverflow> m_moveList;
     701        Vector<unsigned, 0, UnsafeVectorOverflow> m_lowPriorityMoveList;
     702        unsigned m_firstLowPriorityMoveIndex { 0 };
    648703    };
    649704
     
    679734        , m_useCounts(useCounts)
    680735    {
     736        if (type == Arg::GP) {
     737            m_framePointerIndex = AbsoluteTmpMapper<type>::absoluteIndex(Tmp(MacroAssembler::framePointerRegister));
     738            m_interferesWithFramePointer.ensureSize(tmpArraySize(code));
     739        }
     740
    681741        initializePrecoloredTmp();
    682742        build();
     
    801861            m_coloredTmp[i] = tmp.reg();
    802862        }
     863    }
     864
     865    bool mayBeCoalesced(Arg left, Arg right)
     866    {
     867        if (!left.isTmp() || !right.isTmp())
     868            return false;
     869
     870        Tmp leftTmp = left.tmp();
     871        Tmp rightTmp = right.tmp();
     872
     873        if (leftTmp == rightTmp)
     874            return false;
     875
     876        if (leftTmp.isGP() != (type == Arg::GP) || rightTmp.isGP() != (type == Arg::GP))
     877            return false;
     878
     879        unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp);
     880        unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp);
     881
     882        return !m_interferenceEdges.contains(InterferenceEdge(leftIndex, rightIndex));
     883    }
     884
     885    void addToLowPriorityCoalescingCandidates(Arg left, Arg right)
     886    {
     887        ASSERT(mayBeCoalesced(left, right));
     888        Tmp leftTmp = left.tmp();
     889        Tmp rightTmp = right.tmp();
     890
     891        unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp);
     892        unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp);
     893
     894        unsigned nextMoveIndex = m_coalescingCandidates.size();
     895        m_coalescingCandidates.append({ leftIndex, rightIndex });
     896
     897        unsigned newIndexInWorklist = m_worklistMoves.addLowPriorityMove();
     898        ASSERT_UNUSED(newIndexInWorklist, newIndexInWorklist == nextMoveIndex);
     899
     900        ASSERT(nextMoveIndex <= m_activeMoves.size());
     901        m_activeMoves.ensureSize(nextMoveIndex + 1);
     902
     903        m_moveList[leftIndex].add(nextMoveIndex);
     904        m_moveList[rightIndex].add(nextMoveIndex);
    803905    }
    804906
     
    816918            build(nullptr, &block->at(0), localCalc);
    817919        }
     920        buildLowPriorityMoveList();
    818921    }
    819922
     
    882985    }
    883986
     987    void buildLowPriorityMoveList()
     988    {
     989        if (!isX86())
     990            return;
     991
     992        m_worklistMoves.startAddingLowPriorityMoves();
     993        for (BasicBlock* block : m_code) {
     994            for (Inst& inst : *block) {
     995                unsigned defArgIndex = 0;
     996                if (inst.shouldTryAliasingDef(defArgIndex)) {
     997                    Arg op1 = inst.args[defArgIndex - 2];
     998                    Arg op2 = inst.args[defArgIndex - 1];
     999                    Arg dest = inst.args[defArgIndex];
     1000
     1001                    if (op1 == dest || op2 == dest)
     1002                        continue;
     1003
     1004                    if (mayBeCoalesced(op1, dest))
     1005                        addToLowPriorityCoalescingCandidates(op1, dest);
     1006                    if (op1 != op2 && mayBeCoalesced(op2, dest))
     1007                        addToLowPriorityCoalescingCandidates(op2, dest);
     1008                }
     1009            }
     1010        }
     1011    }
     1012
    8841013    void addEdges(Inst* prevInst, Inst* nextInst, typename TmpLiveness<type>::LocalCalc::Iterable liveTmps)
    8851014    {
     
    8961025                }
    8971026
    898                 if (type == Arg::GP && !arg.isGPR()) {
    899                     m_interferenceEdges.add(InterferenceEdge(
    900                         AbsoluteTmpMapper<type>::absoluteIndex(Tmp(MacroAssembler::framePointerRegister)),
    901                         AbsoluteTmpMapper<type>::absoluteIndex(arg)));
    902                 }
     1027                if (type == Arg::GP && !arg.isGPR())
     1028                    m_interferesWithFramePointer.quickSet(AbsoluteTmpMapper<type>::absoluteIndex(arg));
    9031029            });
    9041030    }
     
    10331159            dataLog("Interference: ", listDump(m_interferenceEdges), "\n");
    10341160            dumpInterferenceGraphInDot(WTF::dataFile());
     1161            dataLog("Coalescing candidates:\n");
     1162            for (MoveOperands& moveOp : m_coalescingCandidates) {
     1163                dataLog("    ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.srcIndex),
     1164                    " -> ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.dstIndex), "\n");
     1165            }
    10351166            dataLog("Initial work list\n");
    10361167            dumpWorkLists(WTF::dataFile());
     
    11321263    void iteratedRegisterCoalescingOnType()
    11331264    {
    1134         HashSet<unsigned> unspillableTmps;
     1265        HashSet<unsigned> unspillableTmps = computeUnspillableTmps<type>();
    11351266
    11361267        // FIXME: If a Tmp is used only from a Scratch role and that argument is !admitsStack, then
     
    11731304
    11741305    template<Arg::Type type>
     1306    HashSet<unsigned> computeUnspillableTmps()
     1307    {
     1308        HashSet<unsigned> unspillableTmps;
     1309
     1310        struct Range {
     1311            unsigned first { std::numeric_limits<unsigned>::max() };
     1312            unsigned last { 0 };
     1313            unsigned count { 0 };
     1314            unsigned admitStackCount { 0 };
     1315        };
     1316
     1317        unsigned numTmps = m_code.numTmps(type);
     1318        unsigned arraySize = AbsoluteTmpMapper<type>::absoluteIndex(numTmps);
     1319
     1320        Vector<Range, 0, UnsafeVectorOverflow> ranges;
     1321        ranges.fill(Range(), arraySize);
     1322
     1323        unsigned globalIndex = 0;
     1324        for (BasicBlock* block : m_code) {
     1325            for (Inst& inst : *block) {
     1326                inst.forEachArg([&] (Arg& arg, Arg::Role, Arg::Type argType, Arg::Width) {
     1327                    if (arg.isTmp() && inst.admitsStack(arg)) {
     1328                        if (argType != type)
     1329                            return;
     1330
     1331                        Tmp tmp = arg.tmp();
     1332                        Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)];
     1333                        range.count++;
     1334                        range.admitStackCount++;
     1335                        if (globalIndex < range.first) {
     1336                            range.first = globalIndex;
     1337                            range.last = globalIndex;
     1338                        } else
     1339                            range.last = globalIndex;
     1340
     1341                        return;
     1342                    }
     1343
     1344                    arg.forEachTmpFast([&] (Tmp& tmp) {
     1345                        if (tmp.isGP() != (type == Arg::GP))
     1346                            return;
     1347
     1348                        Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)];
     1349                        range.count++;
     1350                        if (globalIndex < range.first) {
     1351                            range.first = globalIndex;
     1352                            range.last = globalIndex;
     1353                        } else
     1354                            range.last = globalIndex;
     1355                    });
     1356                });
     1357
     1358                ++globalIndex;
     1359            }
     1360            ++globalIndex;
     1361        }
     1362        for (unsigned i = AbsoluteTmpMapper<type>::lastMachineRegisterIndex() + 1; i < ranges.size(); ++i) {
     1363            Range& range = ranges[i];
     1364            if (range.last - range.first <= 1 && range.count > range.admitStackCount)
     1365                unspillableTmps.add(i);
     1366        }
     1367
     1368        return unspillableTmps;
     1369    }
     1370
     1371    template<Arg::Type type>
    11751372    void assignRegistersToTmp(const ColoringAllocator<type>& allocator)
    11761373    {
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r196409 r196513  
    108108Nop
    109109
     110Add32 U:G:32, U:G:32, ZD:G:32
     111    Imm, Tmp, Tmp
     112    Tmp, Tmp, Tmp
     113
    110114Add32 U:G:32, UZD:G:32
    111115    Tmp, Tmp
     
    129133    Tmp, Index
    130134
    131 Add32 U:G:32, U:G:32, ZD:G:32
    132     Imm, Tmp, Tmp
    133     Tmp, Tmp, Tmp
    134 
    13513564: Add64 U:G:64, UD:G:64
    136136    Tmp, Tmp
     
    144144    Tmp, Tmp, Tmp
    145145
    146 arm64: AddDouble U:F:64, U:F:64, D:F:64
    147     Tmp, Tmp, Tmp
     146AddDouble U:F:64, U:F:64, D:F:64
     147    Tmp, Tmp, Tmp
     148    x86: Addr, Tmp, Tmp
     149    x86: Tmp, Addr, Tmp
    148150
    149151x86: AddDouble U:F:64, UD:F:64
     
    151153    Addr, Tmp
    152154
    153 arm64: AddFloat U:F:32, U:F:32, D:F:32
    154     Tmp, Tmp, Tmp
     155AddFloat U:F:32, U:F:32, D:F:32
     156    Tmp, Tmp, Tmp
     157    x86: Addr, Tmp, Tmp
     158    x86: Tmp, Addr, Tmp
    155159
    156160x86: AddFloat U:F:32, UD:F:32
     
    201205
    202206Mul32 U:G:32, U:G:32, ZD:G:32
    203     arm64: Tmp, Tmp, Tmp
     207    Tmp, Tmp, Tmp
     208    x86: Addr, Tmp, Tmp
     209    x86: Tmp, Addr, Tmp
    204210    x86: Imm, Tmp, Tmp
    205211
     
    207213    Tmp, Tmp
    208214
    209 arm64: Mul64 U:G:64, U:G:64, D:G:64
     215Mul64 U:G:64, U:G:64, D:G:64
    210216    Tmp, Tmp, Tmp
    211217
     
    216222    Tmp, Tmp, Tmp
    217223
    218 arm64: MulDouble U:F:64, U:F:64, D:F:64
    219     Tmp, Tmp, Tmp
     224MulDouble U:F:64, U:F:64, D:F:64
     225    Tmp, Tmp, Tmp
     226    x86: Addr, Tmp, Tmp
     227    x86: Tmp, Addr, Tmp
    220228
    221229x86: MulDouble U:F:64, UD:F:64
     
    223231    Addr, Tmp
    224232
    225 arm64: MulFloat U:F:32, U:F:32, D:F:32
    226     Tmp, Tmp, Tmp
     233MulFloat U:F:32, U:F:32, D:F:32
     234    Tmp, Tmp, Tmp
     235    x86: Addr, Tmp, Tmp
     236    x86: Tmp, Addr, Tmp
    227237
    228238x86: MulFloat U:F:32, UD:F:32
     
    259269    Addr, Tmp
    260270
     271And32 U:G:32, U:G:32, ZD:G:32
     272    Tmp, Tmp, Tmp
     273    x86: Tmp, Addr, Tmp
     274    x86: Addr, Tmp, Tmp
     275
    261276And32 U:G:32, UZD:G:32
    262277    Tmp, Tmp
     
    266281    x86: Imm, Addr
    267282
    268 64: And64 U:G:64, UD:G:64
     28364: And64 U:G:64, U:G:64, D:G:64
     284    Tmp, Tmp, Tmp
     285
     286x86_64: And64 U:G:64, UD:G:64
    269287    Tmp, Tmp
    270288    x86: Imm, Tmp
    271289
    272 arm64: AndDouble U:F:64, U:F:64, D:F:64
     290AndDouble U:F:64, U:F:64, D:F:64
    273291    Tmp, Tmp, Tmp
    274292
     
    276294    Tmp, Tmp
    277295
    278 arm64: AndFloat U:F:32, U:F:32, D:F:32
     296AndFloat U:F:32, U:F:32, D:F:32
    279297    Tmp, Tmp, Tmp
    280298
     
    282300    Tmp, Tmp
    283301
     302x86: XorDouble U:F:64, U:F:64, D:F:64
     303    Tmp, Tmp, Tmp
     304
    284305x86: XorDouble U:F:64, UD:F:64
    285306    Tmp, Tmp
     307
     308x86: XorFloat U:F:32, U:F:32, D:F:32
     309    Tmp, Tmp, Tmp
    286310
    287311x86: XorFloat U:F:32, UD:F:32
     
    336360    Imm, Tmp
    337361
     362Or32 U:G:32, U:G:32, ZD:G:32
     363    Tmp, Tmp, Tmp
     364    x86: Tmp, Addr, Tmp
     365    x86: Addr, Tmp, Tmp
     366
    338367Or32 U:G:32, UZD:G:32
    339368    Tmp, Tmp
     
    343372    x86: Imm, Addr
    344373
     37464: Or64 U:G:64, U:G:64, D:G:64
     375    Tmp, Tmp, Tmp
     376
    34537764: Or64 U:G:64, UD:G:64
    346378    Tmp, Tmp
    347379    x86: Imm, Tmp
     380
     381Xor32 U:G:32, U:G:32, ZD:G:32
     382    Tmp, Tmp, Tmp
     383    x86: Tmp, Addr, Tmp
     384    x86: Addr, Tmp, Tmp
    348385
    349386Xor32 U:G:32, UZD:G:32
     
    353390    x86: Addr, Tmp
    354391    x86: Imm, Addr
     392
     39364: Xor64 U:G:64, U:G:64, D:G:64
     394    Tmp, Tmp, Tmp
    355395
    35639664: Xor64 U:G:64, UD:G:64
     
    610650    DoubleCond, Tmp, Tmp
    611651
     652BranchAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
     653    ResCond, Tmp, Tmp, Tmp
     654    x86:ResCond, Tmp, Addr, Tmp
     655    x86:ResCond, Addr, Tmp, Tmp
     656
    612657BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch
    613658    ResCond, Tmp, Tmp
     
    617662    x86: ResCond, Addr, Tmp
    618663
     664BranchAdd64 U:G:32, U:G:64, U:G:64, ZD:G:64 /branch
     665    ResCond, Tmp, Tmp, Tmp
     666    x86:ResCond, Tmp, Addr, Tmp
     667    x86:ResCond, Addr, Tmp, Tmp
     668
    61966964: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch
    620670    ResCond, Imm, Tmp
    621671    ResCond, Tmp, Tmp
     672    x86:ResCond, Addr, Tmp
    622673
    623674x86: BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch
  • trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp

    r196032 r196513  
    5151}
    5252
     53bool Special::shouldTryAliasingDef(Inst&, unsigned&)
     54{
     55    return false;
     56}
     57
    5358bool Special::hasNonArgNonControlEffects()
    5459{
  • trunk/Source/JavaScriptCore/b3/air/AirSpecial.h

    r196032 r196513  
    5757    virtual bool isValid(Inst&) = 0;
    5858    virtual bool admitsStack(Inst&, unsigned argIndex) = 0;
     59    virtual bool shouldTryAliasingDef(Inst&, unsigned& defIndex);
    5960
    6061    // This gets called on for each Inst that uses this Special. Note that there is no way to
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r196433 r196513  
    74937493}
    74947494
     7495void testCheckAddArgumentAliasing64()
     7496{
     7497    Procedure proc;
     7498    BasicBlock* root = proc.addBlock();
     7499    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     7500    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     7501    Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
     7502
     7503    // Pretend to use all the args.
     7504    PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7505    useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
     7506    useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     7507    useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
     7508    useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7509
     7510    // Last use of first arg (here, arg1).
     7511    CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
     7512    checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7513
     7514    // Last use of second arg (here, arg2).
     7515    CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg3, arg2);
     7516    checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7517
     7518    // Keep arg3 live.
     7519    PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7520    keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     7521    keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7522
     7523    // Only use of checkAdd1 and checkAdd2.
     7524    CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2);
     7525    checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7526
     7527    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3);
     7528
     7529    CHECK(compileAndRun<int64_t>(proc, 1, 2, 3) == 8);
     7530}
     7531
     7532void testCheckAddArgumentAliasing32()
     7533{
     7534    Procedure proc;
     7535    BasicBlock* root = proc.addBlock();
     7536    Value* arg1 = root->appendNew<Value>(
     7537        proc, Trunc, Origin(),
     7538        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     7539    Value* arg2 = root->appendNew<Value>(
     7540        proc, Trunc, Origin(),
     7541        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     7542    Value* arg3 = root->appendNew<Value>(
     7543        proc, Trunc, Origin(),
     7544        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
     7545
     7546    // Pretend to use all the args.
     7547    PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7548    useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
     7549    useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     7550    useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
     7551    useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7552
     7553    // Last use of first arg (here, arg1).
     7554    CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2);
     7555    checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7556
     7557    // Last use of second arg (here, arg3).
     7558    CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg2, arg3);
     7559    checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7560
     7561    // Keep arg3 live.
     7562    PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7563    keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     7564    keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7565
     7566    // Only use of checkAdd1 and checkAdd2.
     7567    CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2);
     7568    checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     7569
     7570    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3);
     7571
     7572    CHECK(compileAndRun<int32_t>(proc, 1, 2, 3) == 8);
     7573}
     7574
     7575void testCheckAddSelfOverflow64()
     7576{
     7577    Procedure proc;
     7578    BasicBlock* root = proc.addBlock();
     7579    Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     7580    CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg);
     7581    checkAdd->append(arg);
     7582    checkAdd->setGenerator(
     7583        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     7584            AllowMacroScratchRegisterUsage allowScratch(jit);
     7585            jit.move(params[0].gpr(), GPRInfo::returnValueGPR);
     7586            jit.emitFunctionEpilogue();
     7587            jit.ret();
     7588        });
     7589
     7590    // Make sure the arg is not the destination of the operation.
     7591    PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7592    opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister));
     7593    opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7594
     7595    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd);
     7596
     7597    auto code = compile(proc);
     7598
     7599    CHECK(invoke<int64_t>(*code, 0ll) == 0);
     7600    CHECK(invoke<int64_t>(*code, 1ll) == 2);
     7601    CHECK(invoke<int64_t>(*code, std::numeric_limits<int64_t>::max()) == std::numeric_limits<int64_t>::max());
     7602}
     7603
     7604void testCheckAddSelfOverflow32()
     7605{
     7606    Procedure proc;
     7607    BasicBlock* root = proc.addBlock();
     7608    Value* arg = root->appendNew<Value>(
     7609        proc, Trunc, Origin(),
     7610        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     7611    CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg);
     7612    checkAdd->append(arg);
     7613    checkAdd->setGenerator(
     7614        [&] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     7615            AllowMacroScratchRegisterUsage allowScratch(jit);
     7616            jit.move(params[0].gpr(), GPRInfo::returnValueGPR);
     7617            jit.emitFunctionEpilogue();
     7618            jit.ret();
     7619        });
     7620
     7621    // Make sure the arg is not the destination of the operation.
     7622    PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin());
     7623    opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister));
     7624    opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     7625
     7626    root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd);
     7627
     7628    auto code = compile(proc);
     7629
     7630    CHECK(invoke<int32_t>(*code, 0ll) == 0);
     7631    CHECK(invoke<int32_t>(*code, 1ll) == 2);
     7632    CHECK(invoke<int32_t>(*code, std::numeric_limits<int32_t>::max()) == std::numeric_limits<int32_t>::max());
     7633}
     7634
    74957635void testCheckSubImm()
    74967636{
     
    79428082
    79438083    CHECK(invoke<int>(*code) == 42);
     8084}
     8085
     8086void testCheckMulArgumentAliasing64()
     8087{
     8088    Procedure proc;
     8089    BasicBlock* root = proc.addBlock();
     8090    Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     8091    Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
     8092    Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2);
     8093
     8094    // Pretend to use all the args.
     8095    PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin());
     8096    useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
     8097    useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     8098    useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
     8099    useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     8100
     8101    // Last use of first arg (here, arg1).
     8102    CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
     8103    checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8104
     8105    // Last use of second arg (here, arg2).
     8106    CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg3, arg2);
     8107    checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8108
     8109    // Keep arg3 live.
     8110    PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin());
     8111    keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     8112    keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     8113
     8114    // Only use of checkMul1 and checkMul2.
     8115    CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2);
     8116    checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8117
     8118    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3);
     8119
     8120    CHECK(compileAndRun<int64_t>(proc, 2, 3, 4) == 72);
     8121}
     8122
     8123void testCheckMulArgumentAliasing32()
     8124{
     8125    Procedure proc;
     8126    BasicBlock* root = proc.addBlock();
     8127    Value* arg1 = root->appendNew<Value>(
     8128        proc, Trunc, Origin(),
     8129        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     8130    Value* arg2 = root->appendNew<Value>(
     8131        proc, Trunc, Origin(),
     8132        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8133    Value* arg3 = root->appendNew<Value>(
     8134        proc, Trunc, Origin(),
     8135        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
     8136
     8137    // Pretend to use all the args.
     8138    PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin());
     8139    useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister));
     8140    useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     8141    useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
     8142    useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     8143
     8144    // Last use of first arg (here, arg1).
     8145    CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2);
     8146    checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8147
     8148    // Last use of second arg (here, arg3).
     8149    CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg2, arg3);
     8150    checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8151
     8152    // Keep arg3 live.
     8153    PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin());
     8154    keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
     8155    keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
     8156
     8157    // Only use of checkMul1 and checkMul2.
     8158    CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2);
     8159    checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); });
     8160
     8161    root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3);
     8162
     8163    CHECK(compileAndRun<int32_t>(proc, 2, 3, 4) == 72);
    79448164}
    79458165
     
    1106211282    RUN(testCheckAddFold(100, 200));
    1106311283    RUN(testCheckAddFoldFail(2147483647, 100));
     11284    RUN(testCheckAddArgumentAliasing64());
     11285    RUN(testCheckAddArgumentAliasing32());
     11286    RUN(testCheckAddSelfOverflow64());
     11287    RUN(testCheckAddSelfOverflow32());
    1106411288    RUN(testCheckSubImm());
    1106511289    RUN(testCheckSubBadImm());
     
    1107611300    RUN(testCheckMulFold(100, 200));
    1107711301    RUN(testCheckMulFoldFail(2147483647, 100));
     11302    RUN(testCheckMulArgumentAliasing64());
     11303    RUN(testCheckMulArgumentAliasing32());
    1107811304
    1107911305    RUN(testCompare(Equal, 42, 42));
     
    1160511831
    1160611832    RUN(testCheckMul64SShr());
     11833
    1160711834    RUN(testComputeDivisionMagic<int32_t>(2, -2147483647, 0));
    1160811835    RUN(testTrivialInfiniteLoop());
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp

    r195831 r196513  
    214214            baselineCodeBlock,
    215215            static_cast<VirtualRegister>(inlineCallFrame->stackOffset),
    216             trueCaller ? AssemblyHelpers::UseExistingTagRegisterContents : AssemblyHelpers::CopySavedTagRegistersFromBaseFrame,
     216            trueCaller ? AssemblyHelpers::UseExistingTagRegisterContents : AssemblyHelpers::CopyBaselineCalleeSavedRegistersFromBaseFrame,
    217217            GPRInfo::regT2);
    218218
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r195134 r196513  
    214214    }
    215215   
    216     enum RestoreTagRegisterMode { UseExistingTagRegisterContents, CopySavedTagRegistersFromBaseFrame };
     216    enum RestoreTagRegisterMode { UseExistingTagRegisterContents, CopyBaselineCalleeSavedRegistersFromBaseFrame };
    217217
    218218    void emitSaveOrCopyCalleeSavesFor(CodeBlock* codeBlock, VirtualRegister offsetVirtualRegister, RestoreTagRegisterMode tagRegisterMode, GPRReg temp)
     
    223223        RegisterSet dontSaveRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs());
    224224        unsigned registerCount = calleeSaves->size();
     225
     226#if USE(JSVALUE64)
     227        RegisterSet baselineCalleeSaves = RegisterSet::llintBaselineCalleeSaveRegisters();
     228#endif
    225229       
    226230        for (unsigned i = 0; i < registerCount; i++) {
     
    235239            UNUSED_PARAM(temp);
    236240#else
    237             if (tagRegisterMode == CopySavedTagRegistersFromBaseFrame
    238                 && (entry.reg() == GPRInfo::tagTypeNumberRegister || entry.reg() == GPRInfo::tagMaskRegister)) {
     241            if (tagRegisterMode == CopyBaselineCalleeSavedRegistersFromBaseFrame && baselineCalleeSaves.get(entry.reg())) {
    239242                registerToWrite = temp;
    240243                loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, entry.offset()), registerToWrite);
Note: See TracChangeset for help on using the changeset viewer.