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/JITArithmetic32_64.cpp

    r58555 r58562  
    315315}
    316316
    317 // RightShift (>>)
    318 
    319 void JIT::emit_op_rshift(Instruction* currentInstruction)
     317// RightShift (>>) and UnsignedRightShift (>>>) helper
     318
     319void JIT::emitRightShift(Instruction* currentInstruction, bool isUnsigned)
    320320{
    321321    unsigned dst = currentInstruction[1].u.operand;
     
    328328        emitLoad(op1, regT1, regT0);
    329329        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
    330         rshift32(Imm32(getConstantOperand(op2).asInt32()), regT0);
     330        int shift = getConstantOperand(op2).asInt32();
     331        if (isUnsigned) {
     332            if (shift)
     333                urshift32(Imm32(shift & 0x1f), regT0);
     334            // unsigned shift < 0 or shift = k*2^32 may result in (essentially)
     335            // a toUint conversion, which can result in a value we can represent
     336            // as an immediate int.
     337            if (shift < 0 || !(shift & 31))
     338                addSlowCase(branch32(LessThan, regT0, Imm32(0)));
     339        } else if (shift) { // signed right shift by zero is simply toInt conversion
     340            rshift32(Imm32(shift & 0x1f), regT0);
     341        }
    331342        emitStoreInt32(dst, regT0, dst == op1);
    332343        return;
     
    337348        addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
    338349    addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
    339     rshift32(regT2, regT0);
     350    if (isUnsigned) {
     351        urshift32(regT2, regT0);
     352        addSlowCase(branch32(LessThan, regT0, Imm32(0)));
     353    } else
     354        rshift32(regT2, regT0);
    340355    emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
    341356}
    342357
    343 void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     358void JIT::emitRightShiftSlowCase(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool isUnsigned)
    344359{
    345360    unsigned dst = currentInstruction[1].u.operand;
     
    347362    unsigned op2 = currentInstruction[3].u.operand;
    348363    if (isOperandConstantImmediateInt(op2)) {
     364        int shift = getConstantOperand(op2).asInt32();
    349365        // op1 = regT1:regT0
    350366        linkSlowCase(iter); // int32 check
    351367        if (supportsFloatingPointTruncate()) {
    352             Jump notDouble = branch32(AboveOrEqual, regT1, Imm32(JSValue::LowestTag));
     368            JumpList failures;
     369            failures.append(branch32(AboveOrEqual, regT1, Imm32(JSValue::LowestTag)));
    353370            emitLoadDouble(op1, fpRegT0);
    354             Jump truncationFailed = branchTruncateDoubleToInt32(fpRegT0, regT0);
    355             rshift32(Imm32(getConstantOperand(op2).asInt32()), regT0);
     371            failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
     372            if (isUnsigned) {
     373                if (shift)
     374                    urshift32(Imm32(shift & 0x1f), regT0);
     375                if (shift < 0 || !(shift & 31))
     376                    failures.append(branch32(LessThan, regT0, Imm32(0)));
     377            } else if (shift)
     378                rshift32(Imm32(shift & 0x1f), regT0);
    356379            emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
    357380            emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
    358             notDouble.link(this);
    359             truncationFailed.link(this);
     381            failures.link(this);
    360382        }
     383        if (isUnsigned && (shift < 0 || !(shift & 31)))
     384            linkSlowCase(iter); // failed to box in hot path
    361385    } else {
    362386        // op1 = regT1:regT0
     
    369393                Jump notInt = branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)); // op2 is not an int
    370394                Jump cantTruncate = branchTruncateDoubleToInt32(fpRegT0, regT0);
    371                 rshift32(regT2, regT0);
     395                if (isUnsigned)
     396                    urshift32(regT2, regT0);
     397                else
     398                    rshift32(regT2, regT0);
    372399                emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
    373400                emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
     
    379406
    380407        linkSlowCase(iter); // int32 check - op2 is not an int
    381     }
    382 
    383     JITStubCall stubCall(this, cti_op_rshift);
    384     stubCall.addArgument(op1);
    385     stubCall.addArgument(op2);
    386     stubCall.call(dst);
     408        if (isUnsigned)
     409            linkSlowCase(iter); // Can't represent unsigned result as an immediate
     410    }
     411
     412    JITStubCall stubCall(this, isUnsigned ? cti_op_urshift : cti_op_rshift);
     413    stubCall.addArgument(op1);
     414    stubCall.addArgument(op2);
     415    stubCall.call(dst);
     416}
     417
     418// RightShift (>>)
     419
     420void JIT::emit_op_rshift(Instruction* currentInstruction)
     421{
     422    emitRightShift(currentInstruction, false);
     423}
     424
     425void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     426{
     427    emitRightShiftSlowCase(currentInstruction, iter, false);
     428}
     429
     430// UnsignedRightShift (>>>)
     431
     432void JIT::emit_op_urshift(Instruction* currentInstruction)
     433{
     434    emitRightShift(currentInstruction, true);
     435}
     436
     437void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     438{
     439    emitRightShiftSlowCase(currentInstruction, iter, true);
    387440}
    388441
Note: See TracChangeset for help on using the changeset viewer.