mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
Codegen for SIGNEXTEND [Delivers #81700414]
This commit is contained in:
commit
2524c729cf
9 changed files with 71 additions and 42 deletions
1
evmcc/test/arith/arith_bnot.evm
Normal file
1
evmcc/test/arith/arith_bnot.evm
Normal file
|
|
@ -0,0 +1 @@
|
|||
6201e2406000546000530960005460206000f2
|
||||
14
evmcc/test/arith/arith_bnot.lll
Normal file
14
evmcc/test/arith/arith_bnot.lll
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
(asm
|
||||
123456
|
||||
0
|
||||
MSTORE
|
||||
0
|
||||
MLOAD
|
||||
BNOT
|
||||
0
|
||||
MSTORE
|
||||
32
|
||||
0
|
||||
RETURN
|
||||
)
|
||||
1
evmcc/test/ext/store_delete.evm
Normal file
1
evmcc/test/ext/store_delete.evm
Normal file
|
|
@ -0,0 +1 @@
|
|||
6104d26063576000606357
|
||||
9
evmcc/test/ext/store_delete.lll
Normal file
9
evmcc/test/ext/store_delete.lll
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
(asm
|
||||
1234
|
||||
99
|
||||
SSTORE
|
||||
0
|
||||
99
|
||||
SSTORE
|
||||
)
|
||||
|
|
@ -374,10 +374,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
|
||||
case Instruction::BNOT:
|
||||
{
|
||||
auto top = stack.pop();
|
||||
auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256));
|
||||
auto res = m_builder.CreateXor(top, allones);
|
||||
stack.push(res);
|
||||
auto value = stack.pop();
|
||||
auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot");
|
||||
stack.push(ret);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -507,28 +506,29 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
|
||||
case Instruction::SIGNEXTEND:
|
||||
{
|
||||
auto k = stack.pop();
|
||||
auto b = stack.pop();
|
||||
auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32");
|
||||
auto k32ext = m_builder.CreateZExt(k32, Type::i256);
|
||||
auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8");
|
||||
auto idx = stack.pop();
|
||||
auto word = stack.pop();
|
||||
|
||||
auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32");
|
||||
auto k32 = m_builder.CreateZExt(k32_, Type::i256);
|
||||
auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8");
|
||||
|
||||
// test for b >> (k * 8 + 7)
|
||||
auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7));
|
||||
auto tmp = m_builder.CreateAShr(b, val);
|
||||
auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty());
|
||||
auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos");
|
||||
auto bitval = m_builder.CreateLShr(word, bitpos, "bitval");
|
||||
auto bittest = m_builder.CreateTrunc(bitval, m_builder.getInt1Ty(), "bittest");
|
||||
|
||||
// shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount.
|
||||
auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8);
|
||||
auto bshl = m_builder.CreateShl(b, shiftSize);
|
||||
auto bshr = m_builder.CreateAShr(bshl, shiftSize);
|
||||
auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos);
|
||||
auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask");
|
||||
|
||||
// bshr is our final value if 0 <= k <= 30 and bitset is true,
|
||||
// otherwise we push back b unchanged
|
||||
auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30));
|
||||
auto cond = m_builder.CreateAnd(kInRange, bitset);
|
||||
auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::i256), "negmask");
|
||||
auto val1 = m_builder.CreateOr(word, negmask);
|
||||
auto val0 = m_builder.CreateAnd(word, mask);
|
||||
|
||||
auto result = m_builder.CreateSelect(cond, bshr, b);
|
||||
auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::i256, 30));
|
||||
auto result = m_builder.CreateSelect(kInRange,
|
||||
m_builder.CreateSelect(bittest, val1, val0),
|
||||
word);
|
||||
stack.push(result);
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <llvm/IR/IntrinsicInst.h>
|
||||
|
||||
#include <libdevcrypto/SHA3.h>
|
||||
#include <libevm/FeeStructure.h>
|
||||
|
||||
#include "Runtime.h"
|
||||
#include "Type.h"
|
||||
|
|
@ -24,12 +25,6 @@ inline u256 fromAddress(Address _a)
|
|||
return (u160)_a;
|
||||
}
|
||||
|
||||
struct ExtData
|
||||
{
|
||||
const byte* calldata;
|
||||
const byte* code;
|
||||
};
|
||||
|
||||
Ext::Ext(RuntimeManager& _runtimeManager):
|
||||
RuntimeHelper(_runtimeManager),
|
||||
m_data()
|
||||
|
|
@ -184,7 +179,12 @@ extern "C"
|
|||
{
|
||||
auto index = llvm2eth(*_index);
|
||||
auto value = llvm2eth(*_value);
|
||||
_rt->getExt().setStore(index, value); // Interface uses native endianness
|
||||
auto& ext = _rt->getExt();
|
||||
|
||||
if (value == 0 && ext.store(index) != 0) // If delete
|
||||
ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter
|
||||
|
||||
ext.setStore(index, value); // Interface uses native endianness
|
||||
}
|
||||
|
||||
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value)
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
|
|||
{
|
||||
case Instruction::STOP:
|
||||
case Instruction::SUICIDE:
|
||||
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
|
||||
return 0;
|
||||
|
||||
case Instruction::SSTORE:
|
||||
return static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas
|
||||
|
||||
case Instruction::SLOAD:
|
||||
return static_cast<uint64_t>(c_sloadGas);
|
||||
|
||||
|
|
@ -118,7 +116,6 @@ void GasMeter::count(Instruction _inst)
|
|||
m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
|
||||
}
|
||||
|
||||
if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore()
|
||||
m_blockCost += getStepCost(_inst);
|
||||
|
||||
if (isCostBlockEnd(_inst))
|
||||
|
|
@ -129,20 +126,15 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
|
|||
{
|
||||
assert(!m_checkCall); // Everything should've been commited before
|
||||
|
||||
static const auto sstoreCost = static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas
|
||||
|
||||
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
|
||||
// [DEL] if oldValue != 0 and newValue == 0 => 0
|
||||
|
||||
auto oldValue = _ext.store(_index);
|
||||
auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
|
||||
auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
|
||||
auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
|
||||
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
|
||||
auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd");
|
||||
auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel");
|
||||
auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost");
|
||||
cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost");
|
||||
auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
|
||||
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
|
||||
auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost");
|
||||
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost");
|
||||
createCall(m_gasCheckFunc, cost);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,16 @@ llvm::ConstantInt* Constant::get(uint64_t _n)
|
|||
return llvm::ConstantInt::get(Type::i256, _n);
|
||||
}
|
||||
|
||||
llvm::ConstantInt* Constant::get(u256 _n)
|
||||
{
|
||||
auto& backend = _n.backend();
|
||||
auto words = reinterpret_cast<uint64_t*>(backend.limbs());
|
||||
auto nWords = backend.limb_bits == 64 ? backend.size() : (backend.size() + 1) / 2;
|
||||
llvm::APInt n(256, nWords, words);
|
||||
assert(n.toString(10, false) == _n.str());
|
||||
return static_cast<llvm::ConstantInt*>(llvm::ConstantInt::get(Type::i256, n));
|
||||
}
|
||||
|
||||
llvm::ConstantInt* Constant::get(ReturnCode _returnCode)
|
||||
{
|
||||
return llvm::ConstantInt::get(Type::MainReturn, static_cast<uint64_t>(_returnCode));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
|
|
@ -51,6 +52,7 @@ struct Constant
|
|||
{
|
||||
/// Returns word-size constant
|
||||
static llvm::ConstantInt* get(uint64_t _n);
|
||||
static llvm::ConstantInt* get(u256 _n);
|
||||
|
||||
static llvm::ConstantInt* get(ReturnCode _returnCode);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue