MCPcopy Create free account
hub / github.com/argotorg/solidity / appendShiftOperatorCode

Method appendShiftOperatorCode

libsolidity/codegen/ExpressionCompiler.cpp:2646–2715  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2644}
2645
2646void 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

Callers

nothing calls this directly

Calls 5

integerTypeMethod · 0.80
hasBitwiseShiftingMethod · 0.80
appendInlineAssemblyMethod · 0.80
isSignedMethod · 0.45
evmVersionMethod · 0.45

Tested by

no test coverage detected