diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 540086756..4e0ebb929 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -299,9 +299,6 @@ string YulUtilFunctions::shiftRightFunction(size_t _numBits) string YulUtilFunctions::shiftRightFunctionDynamic() { - // Note that if this is extended with signed shifts, - // the opcodes SAR and SDIV behave differently with regards to rounding! - string const functionName = "shift_right_unsigned_dynamic"; return m_functionCollector.createFunction(functionName, [&]() { return @@ -321,6 +318,86 @@ string YulUtilFunctions::shiftRightFunctionDynamic() }); } +string YulUtilFunctions::shiftRightSignedFunctionDynamic() +{ + string const functionName = "shift_right_signed_dynamic"; + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (bits, value) -> result { + + result := sar(bits, value) + + let divisor := exp(2, bits) + let xor_mask := sub(0, slt(value, 0)) + result := xor(div(xor(value, xor_mask), divisor), xor_mask) + // combined version of + // switch slt(value, 0) + // case 0 { result := div(value, divisor) } + // default { result := not(div(not(value), divisor)) } + + } + )") + ("functionName", functionName) + ("hasShifts", m_evmVersion.hasBitwiseShifting()) + .render(); + }); +} + + +string YulUtilFunctions::typedShiftLeftFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + string const functionName = "shift_left_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, value)) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", shiftLeftFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + +string YulUtilFunctions::typedShiftRightFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + IntegerType const* integerType = dynamic_cast(&_type); + bool valueSigned = integerType && integerType->isSigned(); + + string const functionName = "shift_right_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, (value))) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", valueSigned ? shiftRightSignedFunctionDynamic() : shiftRightFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + string YulUtilFunctions::updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes) { solAssert(_numBytes <= 32, ""); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 9f21a7d39..e72d6d293 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -81,6 +81,14 @@ public: std::string shiftLeftFunctionDynamic(); std::string shiftRightFunction(size_t _numBits); std::string shiftRightFunctionDynamic(); + std::string shiftRightSignedFunctionDynamic(); + + /// @returns the name of a function that performs a left shift and subsequent cleanup + /// and, if needed, prior cleanup. + /// If the amount to shift by is signed, a check for negativeness is performed. + /// signature: (value, amountToShift) -> result + std::string typedShiftLeftFunction(Type const& _type, Type const& _amountType); + std::string typedShiftRightFunction(Type const& _type, Type const& _amountType); /// @returns the name of a function which replaces the /// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d10ec3bd5..6bfe35395 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -254,29 +254,53 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional) bool IRGeneratorForStatements::visit(Assignment const& _assignment) { _assignment.rightHandSide().accept(*this); - Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( - &type(_assignment.leftHandSide()) - ); - IRVariable value = convert(_assignment.rightHandSide(), *intermediateType); + Token assignmentOperator = _assignment.assignmentOperator(); + Token binaryOperator = + assignmentOperator == Token::Assign ? + assignmentOperator : + TokenTraits::AssignmentToBinaryOp(assignmentOperator); + + Type const* rightIntermediateType = + TokenTraits::isShiftOp(binaryOperator) ? + type(_assignment.rightHandSide()).mobileType() : + type(_assignment.rightHandSide()).closestTemporaryType( + &type(_assignment.leftHandSide()) + ); + solAssert(rightIntermediateType, ""); + IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - if (_assignment.assignmentOperator() != Token::Assign) + if (assignmentOperator != Token::Assign) { - solAssert(type(_assignment.leftHandSide()) == *intermediateType, ""); - solAssert(intermediateType->isValueType(), "Compound operators only available for value types."); - + solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types."); + solAssert(rightIntermediateType->isValueType(), "Compound operators only available for value types."); IRVariable leftIntermediate = readFromLValue(*m_currentLValue); - m_code << value.name() << " := " << binaryOperation( - TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()), - *intermediateType, - leftIntermediate.name(), - value.name() - ); + if (TokenTraits::isShiftOp(binaryOperator)) + { + solAssert(type(_assignment) == leftIntermediate.type(), ""); + solAssert(type(_assignment) == type(_assignment.leftHandSide()), ""); + define(_assignment) << shiftOperation(binaryOperator, leftIntermediate, value); + + writeToLValue(*m_currentLValue, IRVariable(_assignment)); + m_currentLValue.reset(); + return false; + } + else + { + solAssert(type(_assignment.leftHandSide()) == *rightIntermediateType, ""); + m_code << value.name() << " := " << binaryOperation( + binaryOperator, + *rightIntermediateType, + leftIntermediate.name(), + value.name() + ); + } } writeToLValue(*m_currentLValue, value); + m_currentLValue.reset(); if (*_assignment.annotation().type != *TypeProvider::emptyTuple()) define(_assignment, value); @@ -541,6 +565,12 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) solAssert(false, "Unknown comparison operator."); define(_binOp) << expr << "\n"; } + else if (TokenTraits::isShiftOp(op)) + { + IRVariable left = convert(_binOp.leftExpression(), *commonType); + IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType()); + define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n"; + } else { string left = expressionAsType(_binOp.leftExpression(), *commonType); @@ -1921,6 +1951,10 @@ string IRGeneratorForStatements::binaryOperation( string const& _right ) { + solAssert( + !TokenTraits::isShiftOp(_operator), + "Have to use specific shift operation function for shifts." + ); if (IntegerType const* type = dynamic_cast(&_type)) { string fun; @@ -1964,6 +1998,31 @@ string IRGeneratorForStatements::binaryOperation( return {}; } +std::string IRGeneratorForStatements::shiftOperation( + langutil::Token _operator, + IRVariable const& _value, + IRVariable const& _amountToShift +) +{ + IntegerType const* amountType = dynamic_cast(&_amountToShift.type()); + solAssert(amountType, ""); + + solAssert(_operator == Token::SHL || _operator == Token::SAR, ""); + + return + Whiskers(R"( + (, ) + )") + ("shift", + _operator == Token::SHL ? + m_utils.typedShiftLeftFunction(_value.type(), *amountType) : + m_utils.typedShiftRightFunction(_value.type(), *amountType) + ) + ("value", _value.name()) + ("amount", _amountToShift.name()) + .render(); +} + void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) { langutil::Token const op = _binOp.getOperator(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index f73c585b4..c51b2225d 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -147,6 +147,11 @@ private: std::string const& _right ); + /// @returns code to perform the given shift operation. + /// The operation itself will be performed in the type of the value, + /// while the amount to shift can have its own type. + std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount); + /// Assigns the value of @a _value to the lvalue @a _lvalue. void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value); /// @returns a fresh IR variable containing the value of the lvalue @a _lvalue. diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol index cc81c15e4..6789bc350 100644 --- a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol +++ b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol @@ -7,5 +7,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol index e5a4152b5..38a776b30 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol index 0f36c10ee..1853814c6 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_left.sol b/test/libsolidity/semanticTests/shifts/shift_left.sol index 15d2a972a..e72671ceb 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol index 06cb38606..fd5981996 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol index 5cc15c1a8..2f470d500 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint8): 0x4266, 0x0 -> 0x4266 // f(uint256,uint8): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol index 99ff376d6..de7b4ec3e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol @@ -6,6 +6,7 @@ contract C { return y << x; } } - +// ==== +// compileViaYul: also // ---- // f() -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol index 0f35077b1..a08f13aef 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol index 3070314f8..af214a244 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol index 77c18c44b..611458246 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol index e63a9a57e..623a715ec 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol @@ -10,6 +10,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_overflow.sol b/test/libsolidity/semanticTests/shifts/shift_overflow.sol index f1b4bca0a..54f5fcc2b 100644 --- a/test/libsolidity/semanticTests/shifts/shift_overflow.sol +++ b/test/libsolidity/semanticTests/shifts/shift_overflow.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // leftU(uint8,uint8): 255, 8 -> 0 // leftU(uint8,uint8): 255, 1 -> 254 diff --git a/test/libsolidity/semanticTests/shifts/shift_right.sol b/test/libsolidity/semanticTests/shifts/shift_right.sol index d78d18aba..bfdb665d1 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol index cfee67301..80f25238c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol index ba819fbce..5b8494167 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 0x4266, 0x0 -> 0x4266 // f(int256,int256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol index 0c1949a59..4c705337c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol @@ -18,6 +18,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe // f(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol index 54ac9540f..18ea9972c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol @@ -10,6 +10,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x00, 0x04 -> 0x0f // f(uint8,uint8): 0x00, 0x1004 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol index 73aae5bc9..2bac06e6e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol index 7f3beb59f..4fecffda4 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol index 24ab54123..883f004d0 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): -4266, 0 -> -4266 // f(int16,int16): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol index 7ff669dc9..4f689c015 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): -4266, 0 -> -4266 // f(int32,int32): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol index c6424f141..02f293e3c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): -66, 0 -> -66 // f(int8,int8): -66, 1 -> -33 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol index 6e462e704..850a89be3 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): 0xff99, 0x00 -> FAILURE // f(int16,int16): 0xff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol index 2466298f0..d797531ec 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): 0xffffff99, 0x00 -> FAILURE // f(int32,int32): 0xffffff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol index 643bc5e62..ee485335d 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): 0x99, 0x00 -> FAILURE // f(int8,int8): 0x99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol index 03573d985..8cc6c4a98 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol index 8457b10e1..acfd99b86 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol new file mode 100644 index 000000000..72b8f69c8 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a << b; + } + function g(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a >> b; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256,int8): 0x1234, 0x0 -> FAILURE +// g(uint256,int8): 0x1234, 0x0 -> FAILURE