mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
720312004d
7 changed files with 98 additions and 38 deletions
|
|
@ -851,7 +851,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto outOff = stack.pop();
|
auto outOff = stack.pop();
|
||||||
auto outSize = stack.pop();
|
auto outSize = stack.pop();
|
||||||
|
|
||||||
|
gasMeter.commitCostBlock(gas);
|
||||||
auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize);
|
auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize);
|
||||||
|
gasMeter.giveBack(gas);
|
||||||
stack.push(ret);
|
stack.push(ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value*
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize)
|
llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize)
|
||||||
{
|
{
|
||||||
m_builder.CreateStore(_gas, m_args[0]);
|
m_builder.CreateStore(_gas, m_args[0]);
|
||||||
auto receiveAddress = bswap(_receiveAddress); // to BE
|
auto receiveAddress = bswap(_receiveAddress); // to BE
|
||||||
|
|
@ -177,6 +177,7 @@ llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Va
|
||||||
m_builder.CreateStore(_outSize, m_arg7);
|
m_builder.CreateStore(_outSize, m_arg7);
|
||||||
llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_args[1]};
|
llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_args[1]};
|
||||||
m_builder.CreateCall(m_call, args);
|
m_builder.CreateCall(m_call, args);
|
||||||
|
_gas = m_builder.CreateLoad(m_args[0]); // Return gas
|
||||||
return m_builder.CreateLoad(m_args[1]);
|
return m_builder.CreateLoad(m_args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,10 +285,10 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO
|
||||||
auto value = llvm2eth(*_value);
|
auto value = llvm2eth(*_value);
|
||||||
|
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
|
auto gas = llvm2eth(*_gas);
|
||||||
if (ext.balance(ext.myAddress) >= value)
|
if (ext.balance(ext.myAddress) >= value)
|
||||||
{
|
{
|
||||||
ext.subBalance(value);
|
ext.subBalance(value);
|
||||||
auto gas = llvm2eth(*_gas);
|
|
||||||
auto receiveAddress = dev::right160(*_receiveAddress);
|
auto receiveAddress = dev::right160(*_receiveAddress);
|
||||||
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
|
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
|
||||||
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
|
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
|
||||||
|
|
@ -299,7 +300,7 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO
|
||||||
auto ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress);
|
auto ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// m_gas += gas; // TODO: Handle gas
|
*_gas = eth2llvm(gas);
|
||||||
_ret->a = ret ? 1 : 0;
|
_ret->a = ret ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public:
|
||||||
void suicide(llvm::Value* _address);
|
void suicide(llvm::Value* _address);
|
||||||
llvm::Value* calldataload(llvm::Value* _index);
|
llvm::Value* calldataload(llvm::Value* _index);
|
||||||
llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
|
llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize);
|
||||||
llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize);
|
llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize);
|
||||||
|
|
||||||
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);
|
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);
|
||||||
llvm::Value* exp(llvm::Value* _left, llvm::Value* _right);
|
llvm::Value* exp(llvm::Value* _left, llvm::Value* _right);
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ bool isCostBlockEnd(Instruction _inst)
|
||||||
{
|
{
|
||||||
// Basic block terminators like STOP are not needed on the list
|
// Basic block terminators like STOP are not needed on the list
|
||||||
// as cost will be commited at the end of basic block
|
// as cost will be commited at the end of basic block
|
||||||
|
|
||||||
|
// CALL & CALLCODE are commited manually
|
||||||
|
|
||||||
switch (_inst)
|
switch (_inst)
|
||||||
{
|
{
|
||||||
case Instruction::CALLDATACOPY:
|
case Instruction::CALLDATACOPY:
|
||||||
|
|
@ -63,8 +66,6 @@ bool isCostBlockEnd(Instruction _inst)
|
||||||
case Instruction::SSTORE:
|
case Instruction::SSTORE:
|
||||||
case Instruction::GAS:
|
case Instruction::GAS:
|
||||||
case Instruction::CREATE:
|
case Instruction::CREATE:
|
||||||
case Instruction::CALL:
|
|
||||||
case Instruction::CALLCODE:
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -107,16 +108,31 @@ void GasMeter::count(Instruction _inst)
|
||||||
commitCostBlock();
|
commitCostBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GasMeter::commitCostBlock()
|
void GasMeter::giveBack(llvm::Value* _gas)
|
||||||
{
|
{
|
||||||
|
llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas");
|
||||||
|
gasCounter = m_builder.CreateAdd(gasCounter, _gas);
|
||||||
|
m_builder.CreateStore(gasCounter, m_gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
|
||||||
|
{
|
||||||
|
assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block
|
||||||
|
|
||||||
// If any uncommited block
|
// If any uncommited block
|
||||||
if (m_checkCall)
|
if (m_checkCall)
|
||||||
{
|
{
|
||||||
if (m_blockCost > 0) // If any cost
|
if (m_blockCost == 0 && !_additionalCost) // Do not check 0
|
||||||
m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
|
{
|
||||||
else
|
|
||||||
m_checkCall->eraseFromParent(); // Remove the gas check call
|
m_checkCall->eraseFromParent(); // Remove the gas check call
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* cost = Constant::get(m_blockCost);
|
||||||
|
if (_additionalCost)
|
||||||
|
cost = m_builder.CreateAdd(cost, _additionalCost);
|
||||||
|
|
||||||
|
m_checkCall->setArgOperand(0, cost); // Update block cost in gas check call
|
||||||
m_checkCall = nullptr; // End cost-block
|
m_checkCall = nullptr; // End cost-block
|
||||||
m_blockCost = 0;
|
m_blockCost = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,12 @@ public:
|
||||||
/// Count step cost of instruction
|
/// Count step cost of instruction
|
||||||
void count(dev::eth::Instruction _inst);
|
void count(dev::eth::Instruction _inst);
|
||||||
|
|
||||||
/// Finalize cost block by checking gas needed for the block before the block
|
/// Finalize cost-block by checking gas needed for the block before the block
|
||||||
void commitCostBlock();
|
/// @param _additionalCost adds additional cost to cost-block before commit
|
||||||
|
void commitCostBlock(llvm::Value* _additionalCost = nullptr);
|
||||||
|
|
||||||
|
/// Give back an amount of gas not used by a call
|
||||||
|
void giveBack(llvm::Value* _gas);
|
||||||
|
|
||||||
/// Generate code that checks the cost of additional memory used by program
|
/// Generate code that checks the cost of additional memory used by program
|
||||||
void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder);
|
void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder);
|
||||||
|
|
|
||||||
|
|
@ -40,33 +40,27 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga
|
||||||
m_returnDataSize->setUnnamedAddr(true); // Address is not important
|
m_returnDataSize->setUnnamedAddr(true); // Address is not important
|
||||||
|
|
||||||
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module);
|
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module);
|
||||||
|
m_require = createRequireFunc(_module, _gasMeter);
|
||||||
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
|
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
|
||||||
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
|
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
|
||||||
m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter);
|
m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter)
|
llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter)
|
||||||
{
|
{
|
||||||
auto isWord = _valueType == Type::i256;
|
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", _module);
|
||||||
|
|
||||||
llvm::Type* storeArgs[] = {Type::i256, _valueType};
|
|
||||||
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
|
|
||||||
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false);
|
|
||||||
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module);
|
|
||||||
|
|
||||||
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func);
|
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func);
|
||||||
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
|
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
|
||||||
auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func);
|
auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func);
|
||||||
|
|
||||||
// BB "check"
|
// BB "check"
|
||||||
llvm::IRBuilder<> builder(checkBB);
|
llvm::IRBuilder<> builder(checkBB);
|
||||||
llvm::Value* index = func->arg_begin();
|
llvm::Value* sizeRequired = func->arg_begin();
|
||||||
index->setName("index");
|
sizeRequired->setName("sizeRequired");
|
||||||
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
|
|
||||||
auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired");
|
|
||||||
auto size = builder.CreateLoad(m_size, "size");
|
auto size = builder.CreateLoad(m_size, "size");
|
||||||
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
|
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
|
||||||
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
|
builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?
|
||||||
|
|
||||||
// BB "resize"
|
// BB "resize"
|
||||||
builder.SetInsertPoint(resizeBB);
|
builder.SetInsertPoint(resizeBB);
|
||||||
|
|
@ -79,26 +73,51 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
|
||||||
builder.CreateStore(sizeRequired, m_size);
|
builder.CreateStore(sizeRequired, m_size);
|
||||||
auto newData = builder.CreateCall(m_resize, m_size, "newData");
|
auto newData = builder.CreateCall(m_resize, m_size, "newData");
|
||||||
builder.CreateStore(newData, m_data);
|
builder.CreateStore(newData, m_data);
|
||||||
builder.CreateBr(accessBB);
|
builder.CreateBr(returnBB);
|
||||||
|
|
||||||
// BB "access"
|
// BB "return"
|
||||||
builder.SetInsertPoint(accessBB);
|
builder.SetInsertPoint(returnBB);
|
||||||
auto data = builder.CreateLoad(m_data, "data");
|
builder.CreateRetVoid();
|
||||||
auto ptr = builder.CreateGEP(data, index, "ptr");
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter)
|
||||||
|
{
|
||||||
|
auto isWord = _valueType == Type::i256;
|
||||||
|
|
||||||
|
llvm::Type* storeArgs[] = {Type::i256, _valueType};
|
||||||
|
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
|
||||||
|
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false);
|
||||||
|
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module);
|
||||||
|
|
||||||
|
auto origBB = m_builder.GetInsertBlock();
|
||||||
|
auto origPt = m_builder.GetInsertPoint();
|
||||||
|
|
||||||
|
m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
|
||||||
|
llvm::Value* index = func->arg_begin();
|
||||||
|
index->setName("index");
|
||||||
|
|
||||||
|
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
|
||||||
|
this->require(index, Constant::get(valueSize));
|
||||||
|
auto data = m_builder.CreateLoad(m_data, "data");
|
||||||
|
auto ptr = m_builder.CreateGEP(data, index, "ptr");
|
||||||
if (isWord)
|
if (isWord)
|
||||||
ptr = builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
|
ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
|
||||||
if (_isStore)
|
if (_isStore)
|
||||||
{
|
{
|
||||||
llvm::Value* value = ++func->arg_begin();
|
llvm::Value* value = ++func->arg_begin();
|
||||||
value->setName("value");
|
value->setName("value");
|
||||||
builder.CreateStore(value, ptr);
|
m_builder.CreateStore(value, ptr);
|
||||||
builder.CreateRetVoid();
|
m_builder.CreateRetVoid();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto ret = builder.CreateLoad(ptr);
|
auto ret = m_builder.CreateLoad(ptr);
|
||||||
builder.CreateRet(ret);
|
m_builder.CreateRet(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_builder.SetInsertPoint(origBB, origPt);
|
||||||
|
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,10 +155,20 @@ llvm::Value* Memory::getSize()
|
||||||
return m_builder.CreateLoad(m_size);
|
return m_builder.CreateLoad(m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size)
|
void Memory::require(llvm::Value* _size)
|
||||||
{
|
{
|
||||||
auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord");
|
m_builder.CreateCall(m_require, _size);
|
||||||
loadWord(lastWord); // Make sure that memory is allocated and count gas
|
}
|
||||||
|
|
||||||
|
void Memory::require(llvm::Value* _offset, llvm::Value* _size)
|
||||||
|
{
|
||||||
|
auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired");
|
||||||
|
require(sizeRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size)
|
||||||
|
{
|
||||||
|
require(_index, _size); // Make sure that memory is allocated and count gas
|
||||||
|
|
||||||
m_builder.CreateStore(_index, m_returnDataOffset);
|
m_builder.CreateStore(_index, m_returnDataOffset);
|
||||||
m_builder.CreateStore(_size, m_returnDataSize);
|
m_builder.CreateStore(_size, m_returnDataSize);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ public:
|
||||||
llvm::Value* getData();
|
llvm::Value* getData();
|
||||||
llvm::Value* getSize();
|
llvm::Value* getSize();
|
||||||
|
|
||||||
|
/// Requires this amount of memory. And counts gas fee for that memory.
|
||||||
|
void require(llvm::Value* _size);
|
||||||
|
|
||||||
|
/// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory.
|
||||||
|
void require(llvm::Value* _offset, llvm::Value* _size);
|
||||||
|
|
||||||
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
|
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
|
||||||
static dev::bytesConstRef getReturnData();
|
static dev::bytesConstRef getReturnData();
|
||||||
|
|
||||||
|
|
@ -28,6 +34,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter);
|
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter);
|
||||||
|
llvm::Function* createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::IRBuilder<>& m_builder;
|
llvm::IRBuilder<>& m_builder;
|
||||||
|
|
@ -42,6 +49,7 @@ private:
|
||||||
llvm::Function* m_loadWord;
|
llvm::Function* m_loadWord;
|
||||||
llvm::Function* m_storeWord;
|
llvm::Function* m_storeWord;
|
||||||
llvm::Function* m_storeByte;
|
llvm::Function* m_storeByte;
|
||||||
|
llvm::Function* m_require;
|
||||||
llvm::Function* m_resize;
|
llvm::Function* m_resize;
|
||||||
|
|
||||||
llvm::Function* m_memDump;
|
llvm::Function* m_memDump;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue