diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index b5270d85aa..5857040f83 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -190,10 +190,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) IRBuilder<> builder(context); // Create main function - const auto i32Ty = builder.getInt32Ty(); - //Type* retTypeElems[] = {i32Ty, i32Ty}; - //auto retType = StructType::create(retTypeElems, "MemRef", true); - m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get()); + m_mainFunc = Function::Create(FunctionType::get(Type::MainReturn, false), Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); @@ -423,12 +420,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3)); + auto shbits = builder.CreateShl(byteNum, Constant::get(3)); value = builder.CreateShl(value, shbits); - value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8)); + value = builder.CreateLShr(value, Constant::get(31 * 8)); - auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32)); - value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0)); + auto byteNumValid = builder.CreateICmpULT(byteNum, Constant::get(32)); + value = builder.CreateSelect(byteNumValid, value, Constant::get(0)); stack.push(value); break; @@ -684,7 +681,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::PC: { - auto value = builder.getIntN(256, currentPC); + auto value = Constant::get(currentPC); stack.push(value); break; } @@ -756,7 +753,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::CODESIZE: { - auto value = builder.getIntN(256, bytecode.size()); + auto value = Constant::get(bytecode.size()); stack.push(value); break; } @@ -834,13 +831,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto index = stack.pop(); auto size = stack.pop(); - auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); - ret = builder.CreateShl(ret, 32); - size = builder.CreateTrunc(size, i32Ty); - size = builder.CreateZExt(size, builder.getInt64Ty()); - ret = builder.CreateOr(ret, size); + memory.registerReturnData(index, size); - builder.CreateRet(ret); + builder.CreateRet(Constant::get(ReturnCode::Return)); break; } @@ -852,7 +845,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } case Instruction::STOP: { - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -884,11 +877,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Note: Right now the codegen for special blocks depends only on createBasicBlock(), // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). builder.SetInsertPoint(m_finalBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) @@ -919,17 +912,22 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) void Compiler::linkBasicBlocks() { /// Helper function that finds basic block given LLVM basic block pointer - auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock& + auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock* { // TODO: Fix for finding jumpTableBlock if (_llbb == this->m_jumpTableBlock->llvm()) - return *this->m_jumpTableBlock; + return this->m_jumpTableBlock.get(); + + for (auto&& bb : this->basicBlocks) + if (_llbb == bb.second.llvm()) + return &bb.second; + return nullptr; // Name is used to get basic block index (index of first instruction) // TODO: If basicBlocs are still a map - multikey map can be used - auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); - auto idx = std::stoul(idxStr); - return basicBlocks.find(idx)->second; + //auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); + //auto idx = std::stoul(idxStr); + //return basicBlocks.find(idx)->second; }; auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void @@ -942,9 +940,14 @@ void Compiler::linkBasicBlocks() for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt) { // TODO: In case entry block is reached - report error - auto& predBB = findBasicBlock(*predIt); - auto value = predBB.getStack().get(valueIdx); - phi->addIncoming(value, predBB); + auto predBB = findBasicBlock(*predIt); + if (!predBB) + { + std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl; + std::exit(1); + } + auto value = predBB->getStack().get(valueIdx); + phi->addIncoming(value, predBB->llvm()); } } }; diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index be45ff838d..0e6df0b24b 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -14,6 +14,8 @@ #include #include "Runtime.h" +#include "Memory.h" +#include "Type.h" namespace evmcc { @@ -97,13 +99,13 @@ int ExecutionEngine::run(std::unique_ptr _module) auto result = exec->runFunction(entryFunc, {}); gas = static_cast(Runtime::getGas()); - if (auto intResult = result.IntVal.getZExtValue()) + auto returnCode = static_cast(result.IntVal.getZExtValue()); + if (returnCode == ReturnCode::Return) { - auto index = intResult >> 32; - auto size = 0xFFFFFFFF & intResult; + auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface std::cout << "RETURN [ "; - for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it) + for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 918be7bf75..aae67f9770 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -45,7 +45,7 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F return static_cast(c_createGas); default: // Assumes instruction code is valid - return static_cast(c_stepGas);; + return static_cast(c_stepGas); } } @@ -113,7 +113,7 @@ void GasMeter::commitCostBlock() if (m_checkCall) { if (m_blockCost > 0) // If any cost - m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call else m_checkCall->eraseFromParent(); // Remove the gas check call @@ -126,7 +126,7 @@ void GasMeter::commitCostBlock() void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) { // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, _builder.getIntN(256, static_cast(c_memoryGas)), "memcost"); + auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); _builder.CreateCall(m_gasCheckFunc, cost); } diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 8625d7b5b1..4d4a349280 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -21,20 +21,8 @@ namespace evmcc Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): m_builder(_builder) { - auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - - 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 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}; + llvm::Type* 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, "evmccrt_memory_dump", _module); @@ -42,9 +30,15 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_data = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); m_data->setUnnamedAddr(true); // Address is not important - m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); + m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important + m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); + m_returnDataOffset->setUnnamedAddr(true); // Address is not important + + m_returnDataSize = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); + 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_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); @@ -69,7 +63,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: llvm::Value* index = func->arg_begin(); index->setName("index"); auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); + auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired"); auto size = builder.CreateLoad(m_size, "size"); auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? @@ -77,8 +71,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: // BB "resize" builder.SetInsertPoint(resizeBB); // Check gas first - auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired"); - auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words"); + auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); + auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); _gasMeter.checkMemory(newWords, builder); // Resize @@ -137,6 +131,15 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } +void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) +{ + auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord"); + loadWord(lastWord); // Make sure that memory is allocated and count gas + + m_builder.CreateStore(_index, m_returnDataOffset); + m_builder.CreateStore(_size, m_returnDataSize); +} + void Memory::dump(uint64_t _begin, uint64_t _end) { if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) @@ -155,6 +158,9 @@ extern "C" { using namespace evmcc; +EXPORT i256 mem_returnDataOffset; +EXPORT i256 mem_returnDataSize; + EXPORT uint8_t* mem_resize(i256* _size) { auto size = _size->a; // Trunc to 64-bit @@ -163,37 +169,13 @@ EXPORT uint8_t* mem_resize(i256* _size) return memory.data(); } -// 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 requiredSize = (_index / 32 + 1) * 32; - auto&& memory = Runtime::getMemory(); - - if (memory.size() < requiredSize) - { - std::cerr << "MEMORY: current size: " << std::dec - << memory.size() << " bytes, required size: " - << requiredSize << " bytes" - << std::endl; - - memory.resize(requiredSize); - } - - return memory.data(); -} - -EXPORT uint64_t evmccrt_memory_size() -{ - return Runtime::getMemory().size() / 32; -} - EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) { if (_end == 0) _end = Runtime::getMemory().size(); std::cerr << "MEMORY: active size: " << std::dec - << evmccrt_memory_size() << " words\n"; + << Runtime::getMemory().size() / 32 << " words\n"; std::cerr << "MEMORY: dump from " << std::dec << _begin << " to " << _end << ":"; if (_end <= _begin) @@ -212,3 +194,12 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) } } // extern "C" + +dev::bytesConstRef evmcc::Memory::getReturnData() +{ + // TODO: Handle large indexes + auto offset = static_cast(llvm2eth(mem_returnDataOffset)); + auto size = static_cast(llvm2eth(mem_returnDataSize)); + auto& memory = Runtime::getMemory(); + return {memory.data() + offset, size}; +} diff --git a/evmcc/Memory.h b/evmcc/Memory.h index ed7273c5c6..c01bd6ef82 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,6 +20,9 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getSize(); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + static dev::bytesConstRef getReturnData(); + void dump(uint64_t _begin, uint64_t _end = 0); private: @@ -31,14 +34,16 @@ private: llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; + /// @TODO: m_data and m_size could be used + llvm::GlobalVariable* m_returnDataOffset; + llvm::GlobalVariable* m_returnDataSize; + llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; llvm::Function* m_resize; - llvm::Function* m_memRequire; llvm::Function* m_memDump; - llvm::Function* m_memSize; }; } diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index 0c8b6d92e0..4837829b42 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -12,6 +12,7 @@ llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; +llvm::Type* Type::MainReturn; void Type::init(llvm::LLVMContext& _context) { @@ -21,6 +22,17 @@ void Type::init(llvm::LLVMContext& _context) Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); + MainReturn = llvm::Type::getInt32Ty(_context); +} + +llvm::Constant* Constant::get(uint64_t _n) +{ + return llvm::ConstantInt::get(Type::i256, _n); +} + +llvm::Constant* Constant::get(ReturnCode _returnCode) +{ + return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); } } diff --git a/evmcc/Type.h b/evmcc/Type.h index fe4bce3351..a8501d897c 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -2,6 +2,7 @@ #pragma once #include +#include namespace evmcc { @@ -20,7 +21,27 @@ struct Type static llvm::Type* Void; + /// Main function return type + static llvm::Type* MainReturn; + static void init(llvm::LLVMContext& _context); }; +enum class ReturnCode +{ + Stop = 0, + Return = 1, + Suicide = 2, + + BadJumpDestination = 101, +}; + +struct Constant +{ + /// Returns word-size constant + static llvm::Constant* get(uint64_t _n); + + static llvm::Constant* get(ReturnCode _returnCode); +}; + } diff --git a/evmcc/bytecode/return2.evm b/evmcc/bytecode/return2.evm new file mode 100644 index 0000000000..e29da76645 --- /dev/null +++ b/evmcc/bytecode/return2.evm @@ -0,0 +1 @@ +6001620f4240f2 diff --git a/evmcc/lll/return2.lll b/evmcc/lll/return2.lll new file mode 100644 index 0000000000..f5ee68f6e0 --- /dev/null +++ b/evmcc/lll/return2.lll @@ -0,0 +1,6 @@ + +(asm +1 +1000000 +RETURN ;; return 1 byte from index 1M +) \ No newline at end of file diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm index e7cbc4aa9b..7724d6308a 100644 --- a/evmcc/test/jump/loop1.evm +++ b/evmcc/test/jump/loop1.evm @@ -1 +1 @@ -600a600181038060025960005460015460025460035400 +600a600181038060025960005460015460025400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll index 8ce24e4cd1..0044ec1fb7 100644 --- a/evmcc/test/jump/loop1.lll +++ b/evmcc/test/jump/loop1.lll @@ -18,8 +18,8 @@ MSTORE MSTORE 2 MSTORE -3 -MSTORE +;;3 +;;MSTORE STOP ) diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm index 6a55228a82..faffa4e5b5 100644 --- a/evmcc/test/jump/loop2.evm +++ b/evmcc/test/jump/loop2.evm @@ -1 +1 @@ -600a80600190038060025960005460015460025460035400 +600a80600190038060025960005460015460025400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll index b53e6713d0..9996c52ba7 100644 --- a/evmcc/test/jump/loop2.lll +++ b/evmcc/test/jump/loop2.lll @@ -5,7 +5,7 @@ ;; 2 DUP1 -1 +1 SWAP1 SUB DUP1 @@ -19,8 +19,8 @@ MSTORE MSTORE 2 MSTORE -3 -MSTORE +;;3 +;;MSTORE STOP )