From 00f993929f6ed76be3a28c714202e4d5aead84fc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 15:46:46 +0200 Subject: [PATCH 1/2] Implemented MLOAD, MSTORE, MSTORE8 and MSIZE --- evmcc/Compiler.cpp | 31 ++++++++++++++++++++ evmcc/Memory.cpp | 64 +++++++++++++++++++++++++++++++++--------- evmcc/Memory.h | 6 ++-- evmcc/lll/memtest1.lll | 17 +++++++++++ 4 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 evmcc/lll/memtest1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77aaaa92f6..2b27c6e320 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -247,6 +247,37 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } + case Instruction::SLOAD: { auto index = stack.pop(); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9e3c2942e7..bba929576b 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -34,18 +34,25 @@ using MemoryImpl = dev::bytes; Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { - auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(m_builder.getVoidTy(), false), + auto voidTy = m_builder.getVoidTy(); + auto i64Ty = m_builder.getInt64Ty(); + + auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(voidTy, false), llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_create", _module); m_builder.CreateCall(memoryCreate); - auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), m_builder.getInt64Ty(), false); + auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_require", _module); - auto i64Ty = m_builder.getInt64Ty(); + auto memSizeTy = llvm::FunctionType::get(i64Ty, false); + m_memSize = llvm::Function::Create(memSizeTy, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_size", _module); + std::vector argTypes = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, @@ -53,7 +60,7 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) } -llvm::Value* Memory::loadByte(llvm::Value* _addr) +llvm::Value* Memory::loadWord(llvm::Value* _addr) { // trunc _addr (an i256) to i64 index and use it to index the memory auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); @@ -61,7 +68,12 @@ llvm::Value* Memory::loadByte(llvm::Value* _addr) // load from evmccrt_memory_require()[index] auto base = m_builder.CreateCall(m_memRequire, index, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); - auto byte = m_builder.CreateLoad(ptr, "byte"); + + auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); + auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); + auto byte = m_builder.CreateLoad(wordPtr, "word"); + + dump(0); return byte; } @@ -76,19 +88,34 @@ void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); m_builder.CreateStore(_word, wordPtr); + + dump(0); } -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _byte) +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { + auto byte = m_builder.CreateTrunc(_word, m_builder.getInt8Ty(), "byte"); auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); auto base = m_builder.CreateCall(m_memRequire, index, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); - m_builder.CreateStore(_byte, ptr); + m_builder.CreateStore(byte, ptr); + + dump(0); +} + +llvm::Value* Memory::getSize() +{ + auto size = m_builder.CreateCall(m_memSize, "mem.size"); + auto word = m_builder.CreateZExt(size, m_builder.getIntNTy(256), "mem.wsize"); + return word; } void Memory::dump(uint64_t _begin, uint64_t _end) { + if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) + return; + auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin); auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end); @@ -106,26 +133,37 @@ EXPORT MemoryImpl* evmccrt_memory; EXPORT void evmccrt_memory_create(void) { - evmccrt_memory = new MemoryImpl(1); + evmccrt_memory = new MemoryImpl(); std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() << std::endl; } -// Resizes memory to contain at least _size bytes and returns the base address. -EXPORT void* evmccrt_memory_require(uint64_t _size) +// Resizes memory to contain at least _index + 1 bytes and returns the base address. +EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { + uint64_t size = _index + 1; + std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() - << ", required size = " << _size + << ", required size = " << size << std::endl; - if (evmccrt_memory->size() < _size) - evmccrt_memory->resize(_size); + if (evmccrt_memory->size() < size) + evmccrt_memory->resize(size); return &(*evmccrt_memory)[0]; } +EXPORT uint64_t evmccrt_memory_size() +{ + return (evmccrt_memory->size() + 31) / 32; +} + EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) { + if (_end == 0) + _end = evmccrt_memory->size(); + + std::cerr << "Active memory size: " << evmccrt_memory_size() << " words\n"; std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _end << ":"; if (_end <= _begin) return; diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 16a7ab4cac..8fbbe0a580 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -10,17 +10,19 @@ class Memory public: Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); - llvm::Value* loadByte(llvm::Value* _addr); + llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getSize(); - void dump(uint64_t _begin, uint64_t _end); + void dump(uint64_t _begin, uint64_t _end = 0); private: llvm::IRBuilder<>& m_builder; llvm::Function* m_memRequire; llvm::Function* m_memDump; + llvm::Function* m_memSize; }; } diff --git a/evmcc/lll/memtest1.lll b/evmcc/lll/memtest1.lll new file mode 100644 index 0000000000..016e4075f4 --- /dev/null +++ b/evmcc/lll/memtest1.lll @@ -0,0 +1,17 @@ + +(asm ;; [] +2 +0 +MSTORE8 ;; [02] +3 +1 +MSTORE8 ;; [02 03] +0 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +1 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +ADD +2 +MSTORE ;; [2 3 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] +) From eea755cfc6d5112944cf3784e4df2b67c04ba0f5 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 16:32:59 +0200 Subject: [PATCH 2/2] fixed bug in memory handling --- evmcc/Memory.cpp | 34 ++++++++++++++++++++-------------- evmcc/bytecode/memtest1.evm | 1 + evmcc/lll/memtest1.lll | 9 +++++---- 3 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 evmcc/bytecode/memtest1.evm diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index bba929576b..219dfe7fad 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -63,10 +63,11 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) llvm::Value* Memory::loadWord(llvm::Value* _addr) { // trunc _addr (an i256) to i64 index and use it to index the memory - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); + auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index.31"); // load from evmccrt_memory_require()[index] - auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto base = m_builder.CreateCall(m_memRequire, index31, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); @@ -79,10 +80,10 @@ llvm::Value* Memory::loadWord(llvm::Value* _addr) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); - auto index32 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 32), "index32"); + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); + auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index31"); - auto base = m_builder.CreateCall(m_memRequire, index32, "base"); + auto base = m_builder.CreateCall(m_memRequire, index31, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); @@ -141,21 +142,24 @@ EXPORT void evmccrt_memory_create(void) // Resizes memory to contain at least _index + 1 bytes and returns the base address. EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { - uint64_t size = _index + 1; + uint64_t requiredSize = (_index / 32 + 1) * 32; - std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() - << ", required size = " << size - << std::endl; + if (evmccrt_memory->size() < requiredSize) + { + std::cerr << "MEMORY: current size: " << std::dec + << evmccrt_memory->size() << " bytes, required size: " + << requiredSize << " bytes" + << std::endl; - if (evmccrt_memory->size() < size) - evmccrt_memory->resize(size); + evmccrt_memory->resize(requiredSize); + } return &(*evmccrt_memory)[0]; } EXPORT uint64_t evmccrt_memory_size() { - return (evmccrt_memory->size() + 31) / 32; + return evmccrt_memory->size() / 32; } EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) @@ -163,8 +167,10 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) if (_end == 0) _end = evmccrt_memory->size(); - std::cerr << "Active memory size: " << evmccrt_memory_size() << " words\n"; - std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _end << ":"; + std::cerr << "MEMORY: active size: " << std::dec + << evmccrt_memory_size() << " words\n"; + std::cerr << "MEMORY: dump from " << std::dec + << _begin << " to " << _end << ":"; if (_end <= _begin) return; diff --git a/evmcc/bytecode/memtest1.evm b/evmcc/bytecode/memtest1.evm new file mode 100644 index 0000000000..0506bf9282 --- /dev/null +++ b/evmcc/bytecode/memtest1.evm @@ -0,0 +1 @@ +6002600055600360015560005360015301600254 diff --git a/evmcc/lll/memtest1.lll b/evmcc/lll/memtest1.lll index 016e4075f4..4b4389ad8a 100644 --- a/evmcc/lll/memtest1.lll +++ b/evmcc/lll/memtest1.lll @@ -9,9 +9,10 @@ MSTORE8 ;; [02 03] 0 MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 1 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ADD 2 -MSTORE ;; [2 3 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] -) +MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +) \ No newline at end of file