| 2644 | } |
| 2645 | |
| 2646 | void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType) |
| 2647 | { |
| 2648 | // stack: shift_amount value_to_shift |
| 2649 | |
| 2650 | bool c_valueSigned = false; |
| 2651 | if (auto valueType = dynamic_cast<IntegerType const*>(&_valueType)) |
| 2652 | c_valueSigned = valueType->isSigned(); |
| 2653 | else |
| 2654 | solAssert(dynamic_cast<FixedBytesType const*>(&_valueType), "Only integer and fixed bytes type supported for shifts."); |
| 2655 | |
| 2656 | // The amount can be a RationalNumberType too. |
| 2657 | if (auto amountType = dynamic_cast<RationalNumberType const*>(&_shiftAmountType)) |
| 2658 | { |
| 2659 | // This should be handled by the type checker. |
| 2660 | solAssert(amountType->integerType(), ""); |
| 2661 | solAssert(!amountType->integerType()->isSigned(), ""); |
| 2662 | } |
| 2663 | else if (auto amountType = dynamic_cast<IntegerType const*>(&_shiftAmountType)) |
| 2664 | solAssert(!amountType->isSigned(), ""); |
| 2665 | else |
| 2666 | solAssert(false, "Invalid shift amount type."); |
| 2667 | |
| 2668 | m_context << Instruction::SWAP1; |
| 2669 | // stack: value_to_shift shift_amount |
| 2670 | |
| 2671 | switch (_operator) |
| 2672 | { |
| 2673 | case Token::SHL: |
| 2674 | if (m_context.evmVersion().hasBitwiseShifting()) |
| 2675 | m_context << Instruction::SHL; |
| 2676 | else |
| 2677 | m_context << u256(2) << Instruction::EXP << Instruction::MUL; |
| 2678 | break; |
| 2679 | case Token::SAR: |
| 2680 | if (m_context.evmVersion().hasBitwiseShifting()) |
| 2681 | m_context << (c_valueSigned ? Instruction::SAR : Instruction::SHR); |
| 2682 | else |
| 2683 | { |
| 2684 | if (c_valueSigned) |
| 2685 | // In the following assembly snippet, xor_mask will be zero, if value_to_shift is positive. |
| 2686 | // Therefore xor'ing with xor_mask is the identity and the computation reduces to |
| 2687 | // div(value_to_shift, exp(2, shift_amount)), which is correct, since for positive values |
| 2688 | // arithmetic right shift is dividing by a power of two (which, as a bitwise operation, results |
| 2689 | // in discarding bits on the right and filling with zeros from the left). |
| 2690 | // For negative values arithmetic right shift, viewed as a bitwise operation, discards bits to the |
| 2691 | // right and fills in ones from the left. This is achieved as follows: |
| 2692 | // If value_to_shift is negative, then xor_mask will have all bits set, so xor'ing with xor_mask |
| 2693 | // will flip all bits. First all bits in value_to_shift are flipped. As for the positive case, |
| 2694 | // dividing by a power of two using integer arithmetic results in discarding bits to the right |
| 2695 | // and filling with zeros from the left. Flipping all bits in the result again, turns all zeros |
| 2696 | // on the left to ones and restores the non-discarded, shifted bits to their original value (they |
| 2697 | // have now been flipped twice). In summary we now have discarded bits to the right and filled with |
| 2698 | // ones from the left, i.e. we have performed an arithmetic right shift. |
| 2699 | m_context.appendInlineAssembly(R"({ |
| 2700 | let xor_mask := sub(0, slt(value_to_shift, 0)) |
| 2701 | value_to_shift := xor(div(xor(value_to_shift, xor_mask), exp(2, shift_amount)), xor_mask) |
| 2702 | })", {"value_to_shift", "shift_amount"}); |
| 2703 | else |
nothing calls this directly
no test coverage detected