Ignore:
Timestamp:
Apr 30, 2010, 12:56:38 AM (15 years ago)
Author:
[email protected]
Message:

2010-04-29 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Add codegen support for unsigned right shift
https://bugs.webkit.org/show_bug.cgi?id=38375

Expose unsigned right shift in the macro assembler, and make use of it
from the jit. Currently if the result is outside the range 0..231-1
we simply fall back to the slow case, even in JSVALUE64 and JSVALUE32_64
where technically we could still return an immediate value.

  • assembler/MacroAssemblerARM.h: (JSC::MacroAssemblerARM::urshift32):
  • assembler/MacroAssemblerARMv7.h: (JSC::MacroAssemblerARMv7::urshift32):
  • assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::urshift32):
  • assembler/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::shrl_i8r): (JSC::X86Assembler::shrl_CLr):

Add unsigned right shift to the x86 assembler

  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases):

op_rshift no longer simply get thrown to a stub function

  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::emit_op_urshift): (JSC::JIT::emitSlow_op_urshift): JSVALUE32 and JSVALUE64 implementation. Only supports double lhs in JSVALUE64.
  • jit/JITArithmetic32_64.cpp: (JSC::JIT::emit_op_rshift): (JSC::JIT::emitSlow_op_rshift): (JSC::JIT::emit_op_urshift): (JSC::JIT::emitSlow_op_urshift): Refactor right shift code to have shared implementation between signed and unsigned versions.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/jit/JITArithmetic.cpp

    r58537 r58562  
    186186
    187187    stubCall.call(result);
     188}
     189
     190void JIT::emit_op_urshift(Instruction* currentInstruction)
     191{
     192    unsigned dst = currentInstruction[1].u.operand;
     193    unsigned op1 = currentInstruction[2].u.operand;
     194    unsigned op2 = currentInstruction[3].u.operand;
     195
     196    // Slow case of urshift makes assumptions about what registers hold the
     197    // shift arguments, so any changes must be updated there as well.
     198    if (isOperandConstantImmediateInt(op2)) {
     199        emitGetVirtualRegister(op1, regT0);
     200        emitJumpSlowCaseIfNotImmediateInteger(regT0);
     201        emitFastArithImmToInt(regT0);
     202        int shift = getConstantOperand(op2).asInt32();
     203        if (shift)
     204            urshift32(Imm32(shift & 0x1f), regT0);
     205        // unsigned shift < 0 or shift = k*2^32 may result in (essentially)
     206        // a toUint conversion, which can result in a value we can represent
     207        // as an immediate int.
     208        if (shift < 0 || !(shift & 31))
     209            addSlowCase(branch32(LessThan, regT0, Imm32(0)));
     210#if USE(JSVALUE32)
     211        addSlowCase(branchAdd32(Overflow, regT0, regT0));
     212        signExtend32ToPtr(regT0, regT0);
     213#endif
     214        emitFastArithReTagImmediate(regT0, regT0);
     215        emitPutVirtualRegister(dst, regT0);
     216        return;
     217    }
     218    emitGetVirtualRegisters(op1, regT0, op2, regT1);
     219    if (!isOperandConstantImmediateInt(op1))
     220        emitJumpSlowCaseIfNotImmediateInteger(regT0);
     221    emitJumpSlowCaseIfNotImmediateInteger(regT1);
     222    emitFastArithImmToInt(regT0);
     223    emitFastArithImmToInt(regT1);
     224    urshift32(regT1, regT0);
     225    addSlowCase(branch32(LessThan, regT0, Imm32(0)));
     226#if USE(JSVALUE32)
     227    addSlowCase(branchAdd32(Overflow, regT0, regT0));
     228    signExtend32ToPtr(regT0, regT0);
     229#endif
     230    emitFastArithReTagImmediate(regT0, regT0);
     231    emitPutVirtualRegister(dst, regT0);
     232}
     233
     234void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     235{
     236    unsigned dst = currentInstruction[1].u.operand;
     237    unsigned op1 = currentInstruction[2].u.operand;
     238    unsigned op2 = currentInstruction[3].u.operand;
     239    if (isOperandConstantImmediateInt(op2)) {
     240        int shift = getConstantOperand(op2).asInt32();
     241        // op1 = regT0
     242        linkSlowCase(iter); // int32 check
     243#if USE(JSVALUE64)
     244        if (supportsFloatingPointTruncate()) {
     245            JumpList failures;
     246            failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
     247            addPtr(tagTypeNumberRegister, regT0);
     248            movePtrToDouble(regT0, fpRegT0);
     249            failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
     250            if (shift)
     251                urshift32(Imm32(shift & 0x1f), regT0);
     252            if (shift < 0 || !(shift & 31))
     253                failures.append(branch32(LessThan, regT0, Imm32(0)));
     254            emitFastArithReTagImmediate(regT0, regT0);
     255            emitPutVirtualRegister(dst, regT0);
     256            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
     257            failures.link(this);
     258        }
     259#endif // JSVALUE64
     260        if (shift < 0 || !(shift & 31))
     261            linkSlowCase(iter); // failed to box in hot path
     262#if USE(JSVALUE32)
     263        linkSlowCase(iter); // Couldn't box result
     264#endif
     265    } else {
     266        // op1 = regT0
     267        // op2 = regT1
     268        if (!isOperandConstantImmediateInt(op1)) {
     269            linkSlowCase(iter); // int32 check -- op1 is not an int
     270#if USE(JSVALUE64)
     271            if (supportsFloatingPointTruncate()) {
     272                JumpList failures;
     273                failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
     274                addPtr(tagTypeNumberRegister, regT0);
     275                movePtrToDouble(regT0, fpRegT0);
     276                failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
     277                failures.append(emitJumpIfNotImmediateInteger(regT1)); // op2 is not an int
     278                emitFastArithImmToInt(regT1);
     279                urshift32(regT1, regT0);
     280                failures.append(branch32(LessThan, regT0, Imm32(0)));
     281                emitFastArithReTagImmediate(regT0, regT0);
     282                emitPutVirtualRegister(dst, regT0);
     283                emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
     284                failures.link(this);
     285            }
     286#endif
     287        }
     288       
     289        linkSlowCase(iter); // int32 check - op2 is not an int
     290        linkSlowCase(iter); // Can't represent unsigned result as an immediate
     291#if USE(JSVALUE32)
     292        linkSlowCase(iter); // Couldn't box result
     293#endif
     294    }
     295   
     296    JITStubCall stubCall(this, cti_op_urshift);
     297    stubCall.addArgument(op1, regT0);
     298    stubCall.addArgument(op2, regT1);
     299    stubCall.call(dst);
    188300}
    189301
Note: See TracChangeset for help on using the changeset viewer.