Changeset 247889 in webkit


Ignore:
Timestamp:
Jul 27, 2019 12:08:01 AM (5 years ago)
Author:
Justin Michaud
Message:

[X86] Emit BT instruction for shift + mask in B3
https://bugs.webkit.org/show_bug.cgi?id=199891

Reviewed by Keith Miller.

JSTests:

  • microbenchmarks/bit-test-constant.js: Added.

(let.glob.0.doTest):

  • microbenchmarks/bit-test-load.js: Added.

(let.glob.0.let.arr.new.Int32Array.8.doTest):
(i):

  • microbenchmarks/bit-test-nonconstant.js: Added.

(let.glob.0.doTest):

Source/JavaScriptCore:

  • Add a new BranchTestBit air opcode, matching the intel bt instruction
  • Select this instruction for the following patterns: if (a & (1<<b)) if ((a>>b)&1) if ((~a>>b)&1) if (~a & (1<<b))
  • 15% perf progression on the nonconstant microbenchmark, neutral otherwise.
  • Note: we cannot fuse loads when we have bitBase=Load, bitOffset=Tmp, since the X86 instruction has different behaviour in this mode. It will read past the current dword/qword instead of wrapping around.
  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::branchTestBit32):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::branchTestBit64):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::bt_ir):
(JSC::X86Assembler::bt_im):
(JSC::X86Assembler::btw_ir):
(JSC::X86Assembler::btw_im):

  • assembler/testmasm.cpp:

(JSC::int64Operands):
(JSC::testBranchTestBit32RegReg):
(JSC::testBranchTestBit32RegImm):
(JSC::testBranchTestBit32AddrImm):
(JSC::testBranchTestBit64RegReg):
(JSC::testBranchTestBit64RegImm):
(JSC::testBranchTestBit64AddrImm):
(JSC::run):

  • b3/B3LowerToAir.cpp:
  • b3/air/AirOpcode.opcodes:
  • b3/testb3.cpp:

(JSC::B3::testBranchBitTest32TmpImm):
(JSC::B3::testBranchBitTest32AddrImm):
(JSC::B3::testBranchBitTest32TmpTmp):
(JSC::B3::testBranchBitTest64TmpTmp):
(JSC::B3::testBranchBitTest64AddrTmp):
(JSC::B3::run):

Location:
trunk
Files:
3 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r247888 r247889  
     12019-07-27  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [X86] Emit BT instruction for shift + mask in B3
     4        https://bugs.webkit.org/show_bug.cgi?id=199891
     5
     6        Reviewed by Keith Miller.
     7
     8        * microbenchmarks/bit-test-constant.js: Added.
     9        (let.glob.0.doTest):
     10        * microbenchmarks/bit-test-load.js: Added.
     11        (let.glob.0.let.arr.new.Int32Array.8.doTest):
     12        (i):
     13        * microbenchmarks/bit-test-nonconstant.js: Added.
     14        (let.glob.0.doTest):
     15
    1162019-07-26  Yusuke Suzuki  <ysuzuki@apple.com>
    217
  • trunk/Source/JavaScriptCore/ChangeLog

    r247888 r247889  
     12019-07-27  Justin Michaud  <justin_michaud@apple.com>
     2
     3        [X86] Emit BT instruction for shift + mask in B3
     4        https://bugs.webkit.org/show_bug.cgi?id=199891
     5
     6        Reviewed by Keith Miller.
     7
     8        - Add a new BranchTestBit air opcode, matching the intel bt instruction
     9        - Select this instruction for the following patterns:
     10          if (a & (1<<b))
     11          if ((a>>b)&1)
     12          if ((~a>>b)&1)
     13          if (~a & (1<<b))
     14        - 15% perf progression on the nonconstant microbenchmark, neutral otherwise.
     15        - Note: we cannot fuse loads when we have bitBase=Load, bitOffset=Tmp, since the X86 instruction has
     16          different behaviour in this mode. It will read past the current dword/qword instead of wrapping around.
     17
     18        * assembler/MacroAssemblerX86Common.h:
     19        (JSC::MacroAssemblerX86Common::branchTestBit32):
     20        * assembler/MacroAssemblerX86_64.h:
     21        (JSC::MacroAssemblerX86_64::branchTestBit64):
     22        * assembler/X86Assembler.h:
     23        (JSC::X86Assembler::bt_ir):
     24        (JSC::X86Assembler::bt_im):
     25        (JSC::X86Assembler::btw_ir):
     26        (JSC::X86Assembler::btw_im):
     27        * assembler/testmasm.cpp:
     28        (JSC::int64Operands):
     29        (JSC::testBranchTestBit32RegReg):
     30        (JSC::testBranchTestBit32RegImm):
     31        (JSC::testBranchTestBit32AddrImm):
     32        (JSC::testBranchTestBit64RegReg):
     33        (JSC::testBranchTestBit64RegImm):
     34        (JSC::testBranchTestBit64AddrImm):
     35        (JSC::run):
     36        * b3/B3LowerToAir.cpp:
     37        * b3/air/AirOpcode.opcodes:
     38        * b3/testb3.cpp:
     39        (JSC::B3::testBranchBitTest32TmpImm):
     40        (JSC::B3::testBranchBitTest32AddrImm):
     41        (JSC::B3::testBranchBitTest32TmpTmp):
     42        (JSC::B3::testBranchBitTest64TmpTmp):
     43        (JSC::B3::testBranchBitTest64AddrTmp):
     44        (JSC::B3::run):
     45
    1462019-07-26  Yusuke Suzuki  <ysuzuki@apple.com>
    247
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r245127 r247889  
    26432643        m_assembler.testl_rr(reg, mask);
    26442644        return Jump(m_assembler.jCC(x86Condition(cond)));
     2645    }
     2646
     2647    Jump branchTestBit32(ResultCondition cond, RegisterID reg, TrustedImm32 bit)
     2648    {
     2649        m_assembler.bt_ir(static_cast<unsigned>(bit.m_value) % 32, reg);
     2650        if (cond == NonZero)
     2651            return Jump(m_assembler.jb());
     2652        if (cond == Zero)
     2653            return Jump(m_assembler.jae());
     2654        RELEASE_ASSERT_NOT_REACHED();
     2655    }
     2656
     2657    Jump branchTestBit32(ResultCondition cond, Address testValue, TrustedImm32 bit)
     2658    {
     2659        m_assembler.bt_im(static_cast<unsigned>(bit.m_value) % 32, testValue.offset, testValue.base);
     2660        if (cond == NonZero)
     2661            return Jump(m_assembler.jb());
     2662        if (cond == Zero)
     2663            return Jump(m_assembler.jae());
     2664        RELEASE_ASSERT_NOT_REACHED();
     2665    }
     2666
     2667    Jump branchTestBit32(ResultCondition cond, RegisterID reg, RegisterID bit)
     2668    {
     2669        m_assembler.bt_ir(bit, reg);
     2670        if (cond == NonZero)
     2671            return Jump(m_assembler.jb());
     2672        if (cond == Zero)
     2673            return Jump(m_assembler.jae());
     2674        RELEASE_ASSERT_NOT_REACHED();
    26452675    }
    26462676
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r235636 r247889  
    11041104    }
    11051105
     1106    Jump branchTestBit64(ResultCondition cond, RegisterID testValue, TrustedImm32 bit)
     1107    {
     1108        m_assembler.btw_ir(static_cast<unsigned>(bit.m_value) % 64, testValue);
     1109        if (cond == NonZero)
     1110            return Jump(m_assembler.jb());
     1111        if (cond == Zero)
     1112            return Jump(m_assembler.jae());
     1113        RELEASE_ASSERT_NOT_REACHED();
     1114    }
     1115
     1116    Jump branchTestBit64(ResultCondition cond, Address testValue, TrustedImm32 bit)
     1117    {
     1118        m_assembler.btw_im(static_cast<unsigned>(bit.m_value) % 64, testValue.offset, testValue.base);
     1119        if (cond == NonZero)
     1120            return Jump(m_assembler.jb());
     1121        if (cond == Zero)
     1122            return Jump(m_assembler.jae());
     1123        RELEASE_ASSERT_NOT_REACHED();
     1124    }
     1125
     1126    Jump branchTestBit64(ResultCondition cond, RegisterID reg, RegisterID bit)
     1127    {
     1128        m_assembler.btw_ir(bit, reg);
     1129        if (cond == NonZero)
     1130            return Jump(m_assembler.jb());
     1131        if (cond == Zero)
     1132            return Jump(m_assembler.jae());
     1133        RELEASE_ASSERT_NOT_REACHED();
     1134    }
     1135
    11061136    void test64(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
    11071137    {
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r247097 r247889  
    295295        OP2_MOVZX_GvEb      = 0xB6,
    296296        OP2_POPCNT          = 0xB8,
     297        OP2_GROUP_BT_EvIb   = 0xBA,
     298        OP2_BT_EvEv         = 0xA3,
    297299        OP2_BSF             = 0xBC,
    298300        OP2_TZCNT           = 0xBC,
     
    383385        ESCAPE_D9_FSTP_singleReal = 3,
    384386        ESCAPE_DD_FSTP_doubleReal = 3,
     387
     388        GROUP_BT_OP_BT = 4,
    385389    } GroupOpcodeID;
    386390   
     
    21492153        m_formatter.immediate8(imm);
    21502154    }
     2155
     2156    void bt_ir(int bitOffset, RegisterID testValue)
     2157    {
     2158        ASSERT(-128 <= bitOffset && bitOffset < 128);
     2159        m_formatter.twoByteOp(OP2_GROUP_BT_EvIb, GROUP_BT_OP_BT, testValue);
     2160        m_formatter.immediate8(bitOffset);
     2161    }
     2162
     2163    void bt_im(int bitOffset, int offset, RegisterID base)
     2164    {
     2165        ASSERT(-128 <= bitOffset && bitOffset < 128);
     2166        m_formatter.twoByteOp(OP2_GROUP_BT_EvIb, GROUP_BT_OP_BT, base, offset);
     2167        m_formatter.immediate8(bitOffset);
     2168    }
     2169
     2170    void bt_ir(RegisterID bitOffset, RegisterID testValue)
     2171    {
     2172        m_formatter.twoByteOp(OP2_BT_EvEv, bitOffset, testValue);
     2173    }
     2174
     2175    void bt_im(RegisterID bitOffset, int offset, RegisterID base)
     2176    {
     2177        m_formatter.twoByteOp(OP2_BT_EvEv, bitOffset, base, offset);
     2178    }
     2179
     2180#if CPU(X86_64)
     2181    void btw_ir(int bitOffset, RegisterID testValue)
     2182    {
     2183        ASSERT(-128 <= bitOffset && bitOffset < 128);
     2184        m_formatter.twoByteOp64(OP2_GROUP_BT_EvIb, GROUP_BT_OP_BT, testValue);
     2185        m_formatter.immediate8(bitOffset);
     2186    }
     2187
     2188    void btw_im(int bitOffset, int offset, RegisterID base)
     2189    {
     2190        ASSERT(-128 <= bitOffset && bitOffset < 128);
     2191        m_formatter.twoByteOp64(OP2_GROUP_BT_EvIb, GROUP_BT_OP_BT, base, offset);
     2192        m_formatter.immediate8(bitOffset);
     2193    }
     2194
     2195    void btw_ir(RegisterID bitOffset, RegisterID testValue)
     2196    {
     2197        m_formatter.twoByteOp64(OP2_BT_EvEv, bitOffset, testValue);
     2198    }
     2199
     2200    void btw_im(RegisterID bitOffset, int offset, RegisterID base)
     2201    {
     2202        m_formatter.twoByteOp64(OP2_BT_EvEv, bitOffset, base, offset);
     2203    }
     2204#endif
    21512205
    21522206    void setCC_r(Condition cond, RegisterID dst)
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r247363 r247889  
    294294}
    295295
     296#if CPU(X86_64)
     297static Vector<int64_t> int64Operands()
     298{
     299    return Vector<int64_t> {
     300        0,
     301        1,
     302        -1,
     303        2,
     304        -2,
     305        42,
     306        -42,
     307        64,
     308        std::numeric_limits<int32_t>::max(),
     309        std::numeric_limits<int32_t>::min(),
     310        std::numeric_limits<int64_t>::max(),
     311        std::numeric_limits<int64_t>::min(),
     312    };
     313}
     314#endif
     315
     316#if CPU(X86_64)
     317void testBranchTestBit32RegReg()
     318{
     319    for (uint32_t value : int32Operands()) {
     320        auto test = compile([=] (CCallHelpers& jit) {
     321            jit.emitFunctionPrologue();
     322
     323            auto branch = jit.branchTestBit32(MacroAssembler::NonZero, GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
     324            jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
     325            auto done = jit.jump();
     326            branch.link(&jit);
     327            jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
     328            done.link(&jit);
     329
     330            jit.emitFunctionEpilogue();
     331            jit.ret();
     332        });
     333
     334        for (uint32_t value2 : int32Operands())
     335            CHECK_EQ(invoke<int>(test, value, value2), (value>>(value2%32))&1);
     336    }
     337}
     338
     339void testBranchTestBit32RegImm()
     340{
     341    for (uint32_t value : int32Operands()) {
     342        auto test = compile([=] (CCallHelpers& jit) {
     343            jit.emitFunctionPrologue();
     344
     345            auto branch = jit.branchTestBit32(MacroAssembler::NonZero, GPRInfo::argumentGPR0, CCallHelpers::TrustedImm32(value));
     346            jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
     347            auto done = jit.jump();
     348            branch.link(&jit);
     349            jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
     350            done.link(&jit);
     351
     352            jit.emitFunctionEpilogue();
     353            jit.ret();
     354        });
     355
     356        for (uint32_t value2 : int32Operands())
     357            CHECK_EQ(invoke<int>(test, value2), (value2>>(value%32))&1);
     358    }
     359}
     360
     361void testBranchTestBit32AddrImm()
     362{
     363    for (uint32_t value : int32Operands()) {
     364        auto test = compile([=] (CCallHelpers& jit) {
     365            jit.emitFunctionPrologue();
     366
     367            auto branch = jit.branchTestBit32(MacroAssembler::NonZero, MacroAssembler::Address(GPRInfo::argumentGPR0, 0), CCallHelpers::TrustedImm32(value));
     368            jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
     369            auto done = jit.jump();
     370            branch.link(&jit);
     371            jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
     372            done.link(&jit);
     373
     374            jit.emitFunctionEpilogue();
     375            jit.ret();
     376        });
     377
     378        for (uint32_t value2 : int32Operands())
     379            CHECK_EQ(invoke<int>(test, &value2), (value2>>(value%32))&1);
     380    }
     381}
     382
     383void testBranchTestBit64RegReg()
     384{
     385    for (uint64_t value : int64Operands()) {
     386        auto test = compile([=] (CCallHelpers& jit) {
     387            jit.emitFunctionPrologue();
     388
     389            auto branch = jit.branchTestBit64(MacroAssembler::NonZero, GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
     390            jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::returnValueGPR);
     391            auto done = jit.jump();
     392            branch.link(&jit);
     393            jit.move(CCallHelpers::TrustedImm64(1), GPRInfo::returnValueGPR);
     394            done.link(&jit);
     395
     396            jit.emitFunctionEpilogue();
     397            jit.ret();
     398        });
     399
     400        for (uint64_t value2 : int64Operands())
     401            CHECK_EQ(invoke<long int>(test, value, value2), (value>>(value2%64))&1);
     402    }
     403}
     404
     405void testBranchTestBit64RegImm()
     406{
     407    for (uint64_t value : int64Operands()) {
     408        auto test = compile([=] (CCallHelpers& jit) {
     409            jit.emitFunctionPrologue();
     410
     411            auto branch = jit.branchTestBit64(MacroAssembler::NonZero, GPRInfo::argumentGPR0, CCallHelpers::TrustedImm32(value));
     412            jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::returnValueGPR);
     413            auto done = jit.jump();
     414            branch.link(&jit);
     415            jit.move(CCallHelpers::TrustedImm64(1), GPRInfo::returnValueGPR);
     416            done.link(&jit);
     417
     418            jit.emitFunctionEpilogue();
     419            jit.ret();
     420        });
     421
     422        for (uint64_t value2 : int64Operands())
     423            CHECK_EQ(invoke<long int>(test, value2), (value2>>(value%64))&1);
     424    }
     425}
     426
     427void testBranchTestBit64AddrImm()
     428{
     429    for (uint64_t value : int64Operands()) {
     430        auto test = compile([=] (CCallHelpers& jit) {
     431            jit.emitFunctionPrologue();
     432
     433            auto branch = jit.branchTestBit64(MacroAssembler::NonZero, MacroAssembler::Address(GPRInfo::argumentGPR0, 0), CCallHelpers::TrustedImm32(value));
     434            jit.move(CCallHelpers::TrustedImm64(0), GPRInfo::returnValueGPR);
     435            auto done = jit.jump();
     436            branch.link(&jit);
     437            jit.move(CCallHelpers::TrustedImm64(1), GPRInfo::returnValueGPR);
     438            done.link(&jit);
     439
     440            jit.emitFunctionEpilogue();
     441            jit.ret();
     442        });
     443
     444        for (uint64_t value2 : int64Operands())
     445            CHECK_EQ(invoke<long int>(test, &value2), (value2>>(value%64))&1);
     446    }
     447}
     448
     449#endif
     450
    296451void testCompareDouble(MacroAssembler::DoubleCondition condition)
    297452{
     
    11381293    RUN(testMul32WithImmediates());
    11391294
     1295#if CPU(X86_64)
     1296    RUN(testBranchTestBit32RegReg());
     1297    RUN(testBranchTestBit32RegImm());
     1298    RUN(testBranchTestBit32AddrImm());
     1299    RUN(testBranchTestBit64RegReg());
     1300    RUN(testBranchTestBit64RegImm());
     1301    RUN(testBranchTestBit64AddrImm());
     1302#endif
     1303
    11401304#if CPU(ARM64)
    11411305    RUN(testMul32SignExtend());
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r247363 r247889  
    33263326            if (canBeInternal(m_value->child(0))) {
    33273327                Value* branchChild = m_value->child(0);
     3328
    33283329                switch (branchChild->opcode()) {
     3330                case BitAnd: {
     3331                    Value* andValue = branchChild->child(0);
     3332                    Value* andMask = branchChild->child(1);
     3333                    Air::Opcode opcode = opcodeForType(BranchTestBit32, BranchTestBit64, andValue->type());
     3334
     3335                    Value* testValue = nullptr;
     3336                    Value* bitOffset = nullptr;
     3337                    Value* internalNode = nullptr;
     3338                    Value* negationNode = nullptr;
     3339                    bool inverted = false;
     3340
     3341                    // if (~(val >> x)&1)
     3342                    if (andMask->isInt(1)
     3343                        && andValue->opcode() == BitXor && (andValue->child(1)->isInt32(-1) || andValue->child(1)->isInt64(-1l))
     3344                        && (andValue->child(0)->opcode() == SShr || andValue->child(0)->opcode() == ZShr)) {
     3345
     3346                        negationNode = andValue;
     3347                        testValue = andValue->child(0)->child(0);
     3348                        bitOffset = andValue->child(0)->child(1);
     3349                        internalNode = andValue->child(0);
     3350                        inverted = !inverted;
     3351                    }
     3352
     3353                    // Turn if ((val >> x)&1) -> Bt val x
     3354                    if (andMask->isInt(1) && (andValue->opcode() == SShr || andValue->opcode() == ZShr)) {
     3355                        testValue = andValue->child(0);
     3356                        bitOffset = andValue->child(1);
     3357                        internalNode = andValue;
     3358                    }
     3359
     3360                    // Turn if (val & (1<<x)) -> Bt val x
     3361                    if ((andMask->opcode() == Shl) && andMask->child(0)->isInt(1)) {
     3362                        testValue = andValue;
     3363                        bitOffset = andMask->child(1);
     3364                        internalNode = andMask;
     3365                    }
     3366
     3367                    // if (~val & (1<<x)) or if ((~val >> x)&1)
     3368                    if (!negationNode && testValue && testValue->opcode() == BitXor && (testValue->child(1)->isInt32(-1) || testValue->child(1)->isInt64(-1l))) {
     3369                        negationNode = testValue;
     3370                        testValue = testValue->child(0);
     3371                        inverted = !inverted;
     3372                    }
     3373
     3374                    if (testValue && bitOffset) {
     3375                        for (auto& basePromise : Vector<ArgPromise>::from(loadPromise(testValue), tmpPromise(testValue))) {
     3376                            bool hasLoad = basePromise.kind() != Arg::Tmp;
     3377                            bool canMakeInternal = (hasLoad ? canBeInternal(testValue) : !m_locked.contains(testValue))
     3378                                && (!negationNode || canBeInternal(negationNode))
     3379                                && (!internalNode || canBeInternal(internalNode));
     3380
     3381                            if (basePromise && canMakeInternal) {
     3382                                if (bitOffset->hasInt() && isValidForm(opcode, Arg::ResCond, basePromise.kind(), Arg::Imm)) {
     3383                                    commitInternal(branchChild);
     3384                                    commitInternal(internalNode);
     3385                                    if (hasLoad)
     3386                                        commitInternal(testValue);
     3387                                    commitInternal(negationNode);
     3388                                    append(basePromise.inst(opcode, m_value, Arg::resCond(MacroAssembler::NonZero).inverted(inverted), basePromise.consume(*this), Arg::imm(bitOffset->asInt())));
     3389                                    return;
     3390                                }
     3391
     3392                                if (!m_locked.contains(bitOffset) && isValidForm(opcode, Arg::ResCond, basePromise.kind(), Arg::Tmp)) {
     3393                                    commitInternal(branchChild);
     3394                                    commitInternal(internalNode);
     3395                                    if (hasLoad)
     3396                                        commitInternal(testValue);
     3397                                    commitInternal(negationNode);
     3398                                    append(basePromise.inst(opcode, m_value, Arg::resCond(MacroAssembler::NonZero).inverted(inverted), basePromise.consume(*this), tmp(bitOffset)));
     3399                                    return;
     3400                                }
     3401                            }
     3402                        }
     3403                    }
     3404                    break;
     3405                }
    33293406                case AtomicWeakCAS:
    33303407                    commitInternal(branchChild);
  • trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes

    r247363 r247889  
    11621162    x86: ResCond, Index, BitImm
    11631163
     1164x86_64: BranchTestBit64 U:G:32, U:G:64, U:G:8 /branch
     1165    ResCond, Tmp, Imm
     1166    ResCond, Addr, Imm
     1167    ResCond, Tmp, Tmp
     1168
     1169x86: BranchTestBit32 U:G:32, U:G:32, U:G:8 /branch
     1170    ResCond, Tmp, Imm
     1171    ResCond, Addr, Imm
     1172    ResCond, Tmp, Tmp
     1173
    11641174BranchDouble U:G:32, U:F:64, U:F:64 /branch
    11651175    DoubleCond, Tmp, Tmp
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r247390 r247889  
    87538753    MonotonicTime after = MonotonicTime::now();
    87548754    dataLog(toCString("    That took ", (after - before).milliseconds(), " ms.\n"));
     8755}
     8756
     8757void testBranchBitTest32TmpImm(uint32_t value, uint32_t imm)
     8758{
     8759    Procedure proc;
     8760    BasicBlock* root = proc.addBlock();
     8761    BasicBlock* thenCase = proc.addBlock();
     8762    BasicBlock* elseCase = proc.addBlock();
     8763
     8764    Value* testValue = root->appendNew<Value>(
     8765        proc, Trunc, Origin(),
     8766        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     8767    Value* bitOffset = root->appendNew<Const32Value>(proc, Origin(), imm);
     8768
     8769    Value* one = root->appendNew<Const32Value>(proc, Origin(), 1);
     8770    Value* bitTest = root->appendNew<Value>(
     8771        proc, BitAnd, Origin(),
     8772        root->appendNew<Value>(proc, SShr, Origin(), testValue, bitOffset),
     8773        one);
     8774
     8775    root->appendNewControlValue(
     8776        proc, Branch, Origin(),
     8777        bitTest,
     8778        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8779
     8780    thenCase->appendNewControlValue(
     8781        proc, Return, Origin(),
     8782        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
     8783
     8784    elseCase->appendNewControlValue(
     8785        proc, Return, Origin(),
     8786        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
     8787
     8788    auto code = compileProc(proc);
     8789    CHECK_EQ(invoke<uint32_t>(*code, value), (value>>(imm%32))&1);
     8790}
     8791
     8792void testBranchBitTest32AddrImm(uint32_t value, uint32_t imm)
     8793{
     8794    Procedure proc;
     8795    BasicBlock* root = proc.addBlock();
     8796    BasicBlock* thenCase = proc.addBlock();
     8797    BasicBlock* elseCase = proc.addBlock();
     8798
     8799    Value* testValue = root->appendNew<MemoryValue>(
     8800        proc, Load, Int32, Origin(),
     8801        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     8802    Value* bitOffset = root->appendNew<Const32Value>(proc, Origin(), imm);
     8803
     8804    Value* one = root->appendNew<Const32Value>(proc, Origin(), 1);
     8805    Value* bitTest = root->appendNew<Value>(
     8806        proc, BitAnd, Origin(),
     8807        root->appendNew<Value>(proc, SShr, Origin(), testValue, bitOffset),
     8808        one);
     8809
     8810    root->appendNewControlValue(
     8811        proc, Branch, Origin(),
     8812        bitTest,
     8813        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8814
     8815    thenCase->appendNewControlValue(
     8816        proc, Return, Origin(),
     8817        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
     8818
     8819    elseCase->appendNewControlValue(
     8820        proc, Return, Origin(),
     8821        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
     8822
     8823    auto code = compileProc(proc);
     8824    CHECK_EQ(invoke<uint32_t>(*code, &value), (value>>(imm%32))&1);
     8825}
     8826
     8827void testBranchBitTest32TmpTmp(uint32_t value, uint32_t value2)
     8828{
     8829    Procedure proc;
     8830    BasicBlock* root = proc.addBlock();
     8831    BasicBlock* thenCase = proc.addBlock();
     8832    BasicBlock* elseCase = proc.addBlock();
     8833
     8834    Value* testValue = root->appendNew<Value>(
     8835        proc, Trunc, Origin(),
     8836        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     8837    Value* bitOffset = root->appendNew<Value>(
     8838        proc, Trunc, Origin(),
     8839        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8840
     8841    Value* one = root->appendNew<Const32Value>(proc, Origin(), 1);
     8842    Value* bitTest = root->appendNew<Value>(
     8843        proc, BitAnd, Origin(),
     8844        root->appendNew<Value>(proc, SShr, Origin(), testValue, bitOffset),
     8845        one);
     8846
     8847    root->appendNewControlValue(
     8848        proc, Branch, Origin(),
     8849        bitTest,
     8850        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8851
     8852    thenCase->appendNewControlValue(
     8853        proc, Return, Origin(),
     8854        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
     8855
     8856    elseCase->appendNewControlValue(
     8857        proc, Return, Origin(),
     8858        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
     8859
     8860    auto code = compileProc(proc);
     8861    CHECK_EQ(invoke<uint32_t>(*code, value, value2), (value>>(value2%32))&1);
     8862}
     8863
     8864void testBranchBitTest64TmpTmp(uint64_t value, uint64_t value2)
     8865{
     8866    Procedure proc;
     8867    BasicBlock* root = proc.addBlock();
     8868    BasicBlock* thenCase = proc.addBlock();
     8869    BasicBlock* elseCase = proc.addBlock();
     8870
     8871    Value* testValue = root->appendNew<Value>(proc, BitXor, Origin(),
     8872        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
     8873        root->appendNew<Const64Value>(proc, Origin(), -1l));
     8874    Value* bitOffset = root->appendNew<Value>(
     8875        proc, Trunc, Origin(),
     8876        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8877
     8878    Value* one = root->appendNew<Const64Value>(proc, Origin(), 1);
     8879    Value* bitTest = root->appendNew<Value>(
     8880        proc, BitAnd, Origin(),
     8881        testValue,
     8882        root->appendNew<Value>(proc, Shl, Origin(), one, bitOffset));
     8883
     8884    root->appendNewControlValue(
     8885        proc, Branch, Origin(),
     8886        bitTest,
     8887        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8888
     8889    thenCase->appendNewControlValue(
     8890        proc, Return, Origin(),
     8891        thenCase->appendNew<Const64Value>(proc, Origin(), 0));
     8892
     8893    elseCase->appendNewControlValue(
     8894        proc, Return, Origin(),
     8895        elseCase->appendNew<Const64Value>(proc, Origin(), 1));
     8896
     8897    auto code = compileProc(proc);
     8898    CHECK_EQ(invoke<uint64_t>(*code, value, value2), (value>>(value2%64))&1);
     8899}
     8900
     8901void testBranchBitTest64AddrTmp(uint64_t value, uint64_t value2)
     8902{
     8903    Procedure proc;
     8904    BasicBlock* root = proc.addBlock();
     8905    BasicBlock* thenCase = proc.addBlock();
     8906    BasicBlock* elseCase = proc.addBlock();
     8907
     8908    Value* testValue = root->appendNew<MemoryValue>(
     8909        proc, Load, Int64, Origin(),
     8910        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
     8911    Value* bitOffset = root->appendNew<Value>(
     8912        proc, Trunc, Origin(),
     8913        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8914
     8915    Value* one = root->appendNew<Const64Value>(proc, Origin(), 1);
     8916    Value* bitTest = root->appendNew<Value>(
     8917        proc, BitAnd, Origin(),
     8918        testValue,
     8919        root->appendNew<Value>(proc, Shl, Origin(), one, bitOffset));
     8920
     8921    root->appendNewControlValue(
     8922        proc, Branch, Origin(),
     8923        bitTest,
     8924        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8925
     8926    thenCase->appendNewControlValue(
     8927        proc, Return, Origin(),
     8928        thenCase->appendNew<Const64Value>(proc, Origin(), 1));
     8929
     8930    elseCase->appendNewControlValue(
     8931        proc, Return, Origin(),
     8932        elseCase->appendNew<Const64Value>(proc, Origin(), 0));
     8933
     8934    auto code = compileProc(proc);
     8935    CHECK_EQ(invoke<uint64_t>(*code, &value, value2), (value>>(value2%64))&1);
     8936}
     8937
     8938void testBranchBitTestNegation(uint64_t value, uint64_t value2)
     8939{
     8940    Procedure proc;
     8941    BasicBlock* root = proc.addBlock();
     8942    BasicBlock* thenCase = proc.addBlock();
     8943    BasicBlock* elseCase = proc.addBlock();
     8944
     8945    Value* testValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     8946    Value* bitOffset = root->appendNew<Value>(
     8947        proc, Trunc, Origin(),
     8948        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8949    Value* shift = root->appendNew<Value>(proc, SShr, Origin(), testValue, bitOffset);
     8950
     8951    Value* one = root->appendNew<Const64Value>(proc, Origin(), 1);
     8952    Value* bitTest = root->appendNew<Value>(
     8953        proc, BitAnd, Origin(),
     8954        root->appendNew<Value>(proc, BitXor, Origin(), shift, root->appendNew<Const64Value>(proc, Origin(), -1l)),
     8955        one);
     8956
     8957    root->appendNewControlValue(
     8958        proc, Branch, Origin(),
     8959        bitTest,
     8960        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8961
     8962    thenCase->appendNewControlValue(
     8963        proc, Return, Origin(),
     8964        thenCase->appendNew<Const64Value>(proc, Origin(), 0));
     8965
     8966    elseCase->appendNewControlValue(
     8967        proc, Return, Origin(),
     8968        elseCase->appendNew<Const64Value>(proc, Origin(), 1));
     8969
     8970    auto code = compileProc(proc);
     8971    CHECK_EQ(invoke<uint64_t>(*code, value, value2), (value>>(value2%64))&1);
     8972}
     8973
     8974void testBranchBitTestNegation2(uint64_t value, uint64_t value2)
     8975{
     8976    Procedure proc;
     8977    BasicBlock* root = proc.addBlock();
     8978    BasicBlock* thenCase = proc.addBlock();
     8979    BasicBlock* elseCase = proc.addBlock();
     8980
     8981    Value* testValue = root->appendNew<Value>(proc, BitXor, Origin(),
     8982        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
     8983        root->appendNew<Const64Value>(proc, Origin(), -1l));
     8984    Value* bitOffset = root->appendNew<Value>(
     8985        proc, Trunc, Origin(),
     8986        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
     8987    Value* shift = root->appendNew<Value>(proc, SShr, Origin(), testValue, bitOffset);
     8988
     8989    Value* one = root->appendNew<Const64Value>(proc, Origin(), 1);
     8990    Value* bitTest = root->appendNew<Value>(
     8991        proc, BitAnd, Origin(),
     8992        shift,
     8993        one);
     8994
     8995    root->appendNewControlValue(
     8996        proc, Branch, Origin(),
     8997        bitTest,
     8998        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
     8999
     9000    thenCase->appendNewControlValue(
     9001        proc, Return, Origin(),
     9002        thenCase->appendNew<Const64Value>(proc, Origin(), 0));
     9003
     9004    elseCase->appendNewControlValue(
     9005        proc, Return, Origin(),
     9006        elseCase->appendNew<Const64Value>(proc, Origin(), 1));
     9007
     9008    auto code = compileProc(proc);
     9009    CHECK_EQ(invoke<uint64_t>(*code, value, value2), (value>>(value2%64))&1);
    87559010}
    87569011
     
    1811818373    RUN(testComplex(4, 256));
    1811918374    RUN(testComplex(4, 384));
     18375
     18376    RUN_BINARY(testBranchBitTest32TmpImm, int32Operands(), int32Operands());
     18377    RUN_BINARY(testBranchBitTest32AddrImm, int32Operands(), int32Operands());
     18378    RUN_BINARY(testBranchBitTest32TmpTmp, int32Operands(), int32Operands());
     18379    RUN_BINARY(testBranchBitTest64TmpTmp, int64Operands(), int64Operands());
     18380    RUN_BINARY(testBranchBitTest64AddrTmp, int64Operands(), int64Operands());
     18381    RUN_BINARY(testBranchBitTestNegation, int64Operands(), int64Operands());
     18382    RUN_BINARY(testBranchBitTestNegation2, int64Operands(), int64Operands());
    1812018383
    1812118384    RUN(testSimplePatchpoint());
Note: See TracChangeset for help on using the changeset viewer.