Browse Source

Codegen for SIGNEXTEND [Delivers #81700414]

cl-refactor
artur-zawlocki 10 years ago
parent
commit
2524c729cf
  1. 1
      evmcc/test/arith/arith_bnot.evm
  2. 14
      evmcc/test/arith/arith_bnot.lll
  3. 1
      evmcc/test/ext/store_delete.evm
  4. 9
      evmcc/test/ext/store_delete.lll
  5. 42
      libevmjit/Compiler.cpp
  6. 14
      libevmjit/Ext.cpp
  7. 20
      libevmjit/GasMeter.cpp
  8. 10
      libevmjit/Type.cpp
  9. 2
      libevmjit/Type.h

1
evmcc/test/arith/arith_bnot.evm

@ -0,0 +1 @@
6201e2406000546000530960005460206000f2

14
evmcc/test/arith/arith_bnot.lll

@ -0,0 +1,14 @@
(asm
123456
0
MSTORE
0
MLOAD
BNOT
0
MSTORE
32
0
RETURN
)

1
evmcc/test/ext/store_delete.evm

@ -0,0 +1 @@
6104d26063576000606357

9
evmcc/test/ext/store_delete.lll

@ -0,0 +1,9 @@
(asm
1234
99
SSTORE
0
99
SSTORE
)

42
libevmjit/Compiler.cpp

@ -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;

14
libevmjit/Ext.cpp

@ -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)

20
libevmjit/GasMeter.cpp

@ -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,8 +116,7 @@ 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);
m_blockCost += getStepCost(_inst);
if (isCostBlockEnd(_inst))
commitCostBlock();
@ -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);
}

10
libevmjit/Type.cpp

@ -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));

2
libevmjit/Type.h

@ -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…
Cancel
Save