diff options
author | Daniel Kirchner <daniel@ekpyron.org> | 2018-05-08 01:09:52 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-06-12 16:32:19 +0800 |
commit | f33dc92cbd908a6d852368fa30144bda9e8da439 (patch) | |
tree | a8bb2fd5921c71a8c898564a96ec1ee54d206dc6 /libsolidity/codegen | |
parent | 8999a2f375410a29bae46b8e87a70c62036c880d (diff) | |
download | dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar.gz dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar.bz2 dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar.lz dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar.xz dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.tar.zst dexon-solidity-f33dc92cbd908a6d852368fa30144bda9e8da439.zip |
Use proper SAR for signed right shifts and emulate on pre-constantinople.
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 93d440c8..908c703a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1737,11 +1737,28 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co m_context << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: - // NOTE: SAR rounds differently than SDIV - if (m_context.evmVersion().hasBitwiseShifting() && !c_valueSigned) - m_context << Instruction::SHR; + if (m_context.evmVersion().hasBitwiseShifting()) + m_context << (c_valueSigned ? Instruction::SAR : Instruction::SHR); else - m_context << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_valueSigned ? Instruction::SDIV : Instruction::DIV); + { + if (c_valueSigned) + // For negative values xor_mask has all bits set and xor(value_to_shift, xor_mask) will be + // the bitwise complement of value_to_shift, i.e. abs(value_to_shift) - 1. Dividing this by + // exp(2, shift_amount) results in a value that is positive and strictly smaller than the + // absolute value of the desired result. Taking the complement again changes the sign + // back to negative and subtracts one, resulting in rounding towards negative infinity. + // For positive values xor_mask is zero and xor(value_to_shift, xor_mask) is again value_to_shift. + m_context.appendInlineAssembly(R"({ + let xor_mask := sub(0, slt(value_to_shift, 0)) + value_to_shift := xor(div(xor(value_to_shift, xor_mask), exp(2, shift_amount)), xor_mask) + })", {"value_to_shift", "shift_amount"}); + else + m_context.appendInlineAssembly(R"({ + value_to_shift := div(value_to_shift, exp(2, shift_amount)) + })", {"value_to_shift", "shift_amount"}); + m_context << Instruction::POP; + + } break; case Token::SHR: default: |