mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
5dd30376d6
19 changed files with 261 additions and 54 deletions
|
|
@ -18,6 +18,13 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx,
|
||||||
m_stack(m_llvmBB)
|
m_stack(m_llvmBB)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) :
|
||||||
|
m_beginInstIdx(0),
|
||||||
|
m_endInstIdx(0),
|
||||||
|
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
|
||||||
|
m_stack(m_llvmBB)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
void BasicBlock::Stack::push(llvm::Value* _value)
|
void BasicBlock::Stack::push(llvm::Value* _value)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ public:
|
||||||
static const char* NamePrefix;
|
static const char* NamePrefix;
|
||||||
|
|
||||||
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc);
|
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc);
|
||||||
|
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc);
|
||||||
|
|
||||||
BasicBlock(const BasicBlock&) = delete;
|
BasicBlock(const BasicBlock&) = delete;
|
||||||
void operator=(const BasicBlock&) = delete;
|
void operator=(const BasicBlock&) = delete;
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ set(EXECUTABLE evmcc)
|
||||||
|
|
||||||
add_executable(${EXECUTABLE} ${SRC_LIST})
|
add_executable(${EXECUTABLE} ${SRC_LIST})
|
||||||
|
|
||||||
target_link_libraries(${EXECUTABLE} evmface)
|
|
||||||
target_link_libraries(${EXECUTABLE} devcore)
|
target_link_libraries(${EXECUTABLE} devcore)
|
||||||
target_link_libraries(${EXECUTABLE} ethcore)
|
target_link_libraries(${EXECUTABLE} ethcore)
|
||||||
|
target_link_libraries(${EXECUTABLE} evm)
|
||||||
|
target_link_libraries(${EXECUTABLE} evmface)
|
||||||
|
|
||||||
if ("${TARGET_PLATFORM}" STREQUAL "w64")
|
if ("${TARGET_PLATFORM}" STREQUAL "w64")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
#include <boost/dynamic_bitset.hpp>
|
||||||
|
|
||||||
#include <llvm/IR/IRBuilder.h>
|
#include <llvm/IR/IRBuilder.h>
|
||||||
#include <llvm/IR/CFG.h>
|
#include <llvm/IR/CFG.h>
|
||||||
|
|
||||||
|
|
@ -19,19 +21,28 @@ using namespace dev::eth; // We should move all the JIT code into dev::eth names
|
||||||
|
|
||||||
|
|
||||||
Compiler::Compiler()
|
Compiler::Compiler()
|
||||||
|
: m_finalBlock(nullptr)
|
||||||
|
, m_badJumpBlock(nullptr)
|
||||||
{
|
{
|
||||||
Type::init(llvm::getGlobalContext());
|
Type::init(llvm::getGlobalContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
{
|
{
|
||||||
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indecies where basic blocks start/end
|
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
|
||||||
splitPoints.insert(0); // First basic block
|
splitPoints.insert(0); // First basic block
|
||||||
|
|
||||||
|
std::map<ProgramCounter, ProgramCounter> directJumpTargets;
|
||||||
|
std::vector<ProgramCounter> indirectJumpTargets;
|
||||||
|
boost::dynamic_bitset<> validJumpTargets(bytecode.size());
|
||||||
|
|
||||||
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
|
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
|
||||||
{
|
{
|
||||||
using dev::eth::Instruction;
|
using dev::eth::Instruction;
|
||||||
|
|
||||||
|
ProgramCounter currentPC = curr - bytecode.cbegin();
|
||||||
|
validJumpTargets[currentPC] = 1;
|
||||||
|
|
||||||
auto inst = static_cast<Instruction>(*curr);
|
auto inst = static_cast<Instruction>(*curr);
|
||||||
switch (inst)
|
switch (inst)
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +81,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
{
|
{
|
||||||
auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
|
auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
|
||||||
auto next = curr + numBytes + 1;
|
auto next = curr + numBytes + 1;
|
||||||
if (next == bytecode.cend())
|
if (next >= bytecode.cend())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto nextInst = static_cast<Instruction>(*next);
|
auto nextInst = static_cast<Instruction>(*next);
|
||||||
|
|
@ -85,34 +96,30 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
val |= *iter;
|
val |= *iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a block following the JUMP.
|
|
||||||
if (next + 1 < bytecode.cend())
|
|
||||||
{
|
|
||||||
ProgramCounter nextPC = (next + 1 - bytecode.cbegin());
|
|
||||||
splitPoints.insert(nextPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a block for the JUMP target.
|
// Create a block for the JUMP target.
|
||||||
ProgramCounter targetPC = val.convert_to<ProgramCounter>();
|
ProgramCounter targetPC = val.convert_to<ProgramCounter>();
|
||||||
|
if (targetPC > bytecode.size())
|
||||||
|
targetPC = bytecode.size();
|
||||||
splitPoints.insert(targetPC);
|
splitPoints.insert(targetPC);
|
||||||
|
|
||||||
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
||||||
jumpTargets[jumpPC] = targetPC;
|
directJumpTargets[jumpPC] = targetPC;
|
||||||
|
|
||||||
curr += 1; // skip over JUMP
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curr += numBytes;
|
curr += numBytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Instruction::JUMP:
|
case Instruction::JUMPDEST:
|
||||||
case Instruction::JUMPI:
|
|
||||||
{
|
{
|
||||||
std::cerr << "JUMP/JUMPI at " << (curr - bytecode.cbegin()) << " not preceded by PUSH\n";
|
// A basic block starts here.
|
||||||
std::exit(1);
|
splitPoints.insert(currentPC);
|
||||||
|
indirectJumpTargets.push_back(currentPC);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Instruction::JUMP:
|
||||||
|
case Instruction::JUMPI:
|
||||||
case Instruction::RETURN:
|
case Instruction::RETURN:
|
||||||
case Instruction::STOP:
|
case Instruction::STOP:
|
||||||
case Instruction::SUICIDE:
|
case Instruction::SUICIDE:
|
||||||
|
|
@ -120,8 +127,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
// Create a basic block starting at the following instruction.
|
// Create a basic block starting at the following instruction.
|
||||||
if (curr + 1 < bytecode.cend())
|
if (curr + 1 < bytecode.cend())
|
||||||
{
|
{
|
||||||
ProgramCounter nextPC = (curr + 1 - bytecode.cbegin());
|
splitPoints.insert(currentPC + 1);
|
||||||
splitPoints.insert(nextPC);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -131,14 +137,42 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
splitPoints.insert(bytecode.size()); // For final block
|
for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();)
|
||||||
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
|
|
||||||
{
|
{
|
||||||
auto beginInstIdx = *it;
|
auto beginInstIdx = *it;
|
||||||
++it;
|
++it;
|
||||||
auto endInstIdx = it != splitPoints.cend() ? *it : beginInstIdx; // For final block
|
auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size();
|
||||||
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc));
|
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_finalBlock = std::make_unique<BasicBlock>("FinalBlock", m_mainFunc);
|
||||||
|
m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc);
|
||||||
|
|
||||||
|
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second >= bytecode.size()) // Jump out of code
|
||||||
|
{
|
||||||
|
m_directJumpTargets[it->first] = m_finalBlock.get();
|
||||||
|
}
|
||||||
|
else if (!validJumpTargets[it->second]) // Jump into data
|
||||||
|
{
|
||||||
|
std::cerr << "Bad JUMP at PC " << it->first
|
||||||
|
<< ": " << it->second << " is not a valid PC\n";
|
||||||
|
m_directJumpTargets[it->first] = m_badJumpBlock.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
|
||||||
|
{
|
||||||
|
if (*it >= bytecode.size())
|
||||||
|
m_indirectJumpTargets.push_back(m_finalBlock.get());
|
||||||
|
else
|
||||||
|
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
|
|
@ -546,30 +580,69 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Instruction::JUMP:
|
case Instruction::JUMP:
|
||||||
{
|
|
||||||
// The target address is computed at compile time,
|
|
||||||
// just pop it without looking...
|
|
||||||
stack.pop();
|
|
||||||
|
|
||||||
auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second;
|
|
||||||
builder.CreateBr(targetBlock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Instruction::JUMPI:
|
case Instruction::JUMPI:
|
||||||
{
|
{
|
||||||
assert(currentPC + 1 < bytecode.size());
|
// Generate direct jump iff:
|
||||||
|
// 1. this is not the first instruction in the block
|
||||||
|
// 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
|
||||||
|
// Otherwise generate a indirect jump (a switch).
|
||||||
|
if (currentPC != basicBlock.begin())
|
||||||
|
{
|
||||||
|
auto pairIter = m_directJumpTargets.find(currentPC);
|
||||||
|
if (pairIter != m_directJumpTargets.end())
|
||||||
|
{
|
||||||
|
auto targetBlock = pairIter->second;
|
||||||
|
|
||||||
// The target address is computed at compile time,
|
// The target address is computed at compile time,
|
||||||
// just pop it without looking...
|
// just pop it without looking...
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
|
if (inst == Instruction::JUMP)
|
||||||
|
{
|
||||||
|
builder.CreateBr(targetBlock->llvm());
|
||||||
|
}
|
||||||
|
else // JUMPI
|
||||||
|
{
|
||||||
auto top = stack.pop();
|
auto top = stack.pop();
|
||||||
auto zero = ConstantInt::get(Type::i256, 0);
|
auto zero = ConstantInt::get(Type::i256, 0);
|
||||||
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
||||||
auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second;
|
|
||||||
auto& followBlock = basicBlocks.find(currentPC + 1)->second;
|
// Assume the basic blocks are properly ordered:
|
||||||
builder.CreateCondBr(cond, targetBlock, followBlock);
|
auto nextBBIter = basicBlockPairIt;
|
||||||
|
++nextBBIter;
|
||||||
|
assert (nextBBIter != basicBlocks.end());
|
||||||
|
auto& followBlock = nextBBIter->second;
|
||||||
|
builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst == Instruction::JUMPI)
|
||||||
|
{
|
||||||
|
std::cerr << "Indirect JUMPI is not supported yet (at PC "
|
||||||
|
<< currentPC << ")\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate switch for indirect jump.
|
||||||
|
auto dest = stack.pop();
|
||||||
|
auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
|
||||||
|
m_indirectJumpTargets.size());
|
||||||
|
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
|
||||||
|
{
|
||||||
|
auto& bb = *it;
|
||||||
|
auto dest = ConstantInt::get(Type::i256, bb->begin());
|
||||||
|
switchInstr->addCase(dest, bb->llvm());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Instruction::JUMPDEST:
|
||||||
|
{
|
||||||
|
// Extra asserts just in case.
|
||||||
|
assert(currentPC == basicBlock.begin());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -741,17 +814,18 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated
|
if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated
|
||||||
{
|
{
|
||||||
if (basicBlock.begin() == bytecode.size()) // Special final block
|
if (basicBlock.end() == bytecode.size())
|
||||||
{
|
{
|
||||||
builder.CreateRet(builder.getInt64(0));
|
// Branch from the last regular block to the final block.
|
||||||
|
builder.CreateBr(m_finalBlock->llvm());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Branch to the next block.
|
||||||
auto iterCopy = basicBlockPairIt;
|
auto iterCopy = basicBlockPairIt;
|
||||||
++iterCopy;
|
++iterCopy;
|
||||||
auto& next = iterCopy->second;
|
auto& next = iterCopy->second;
|
||||||
|
|
@ -760,6 +834,14 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Code for special blocks:
|
||||||
|
builder.SetInsertPoint(m_finalBlock->llvm());
|
||||||
|
builder.CreateRet(builder.getInt64(0));
|
||||||
|
|
||||||
|
// TODO: throw an exception or something
|
||||||
|
builder.SetInsertPoint(m_badJumpBlock->llvm());
|
||||||
|
builder.CreateRet(builder.getInt64(1));
|
||||||
|
|
||||||
linkBasicBlocks();
|
linkBasicBlocks();
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,28 @@ private:
|
||||||
std::map<ProgramCounter, BasicBlock> basicBlocks;
|
std::map<ProgramCounter, BasicBlock> basicBlocks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a pc at which there is a JUMP or JUMPI to the target pc of the jump.
|
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
||||||
*/
|
*/
|
||||||
std::map<ProgramCounter, ProgramCounter> jumpTargets;
|
std::map<ProgramCounter, BasicBlock*> m_directJumpTargets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of possible blocks to which there may be indirect jumps.
|
||||||
|
*/
|
||||||
|
std::vector<BasicBlock*> m_indirectJumpTargets;
|
||||||
|
|
||||||
private:
|
|
||||||
/// Collection of basic blocks in program
|
/// Collection of basic blocks in program
|
||||||
//std::vector<BasicBlock> m_basicBlocks;
|
//std::vector<BasicBlock> m_basicBlocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final block for normal (non-exceptional) execution.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<BasicBlock> m_finalBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default destination for indirect jumps.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<BasicBlock> m_badJumpBlock;
|
||||||
|
|
||||||
/// Main program function
|
/// Main program function
|
||||||
llvm::Function* m_mainFunc = nullptr;
|
llvm::Function* m_mainFunc = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
namespace evmcc
|
namespace evmcc
|
||||||
{
|
{
|
||||||
|
|
||||||
llvm::Type* Type::i256;
|
llvm::IntegerType* Type::i256;
|
||||||
llvm::Type* Type::lowPrecision;
|
llvm::IntegerType* Type::lowPrecision;
|
||||||
llvm::Type* Type::Void;
|
llvm::Type* Type::Void;
|
||||||
|
|
||||||
void Type::init(llvm::LLVMContext& _context)
|
void Type::init(llvm::LLVMContext& _context)
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ namespace evmcc
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
static llvm::Type* i256;
|
static llvm::IntegerType* i256;
|
||||||
|
|
||||||
/// Type for doing low precision arithmetics where 256-bit precision is not supported by native target
|
/// Type for doing low precision arithmetics where 256-bit precision is not supported by native target
|
||||||
/// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
|
/// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
|
||||||
static llvm::Type* lowPrecision;
|
static llvm::IntegerType* lowPrecision;
|
||||||
|
|
||||||
static llvm::Type* Void;
|
static llvm::Type* Void;
|
||||||
|
|
||||||
|
|
|
||||||
1
evmcc/test/jump/jump1.evm
Normal file
1
evmcc/test/jump/jump1.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
600458006001600154
|
||||||
11
evmcc/test/jump/jump1.lll
Normal file
11
evmcc/test/jump/jump1.lll
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
;; Direct JUMP.
|
||||||
|
;; output: memory[1] == 1
|
||||||
|
|
||||||
|
(asm
|
||||||
|
4 ;; 0
|
||||||
|
JUMP ;; 2
|
||||||
|
STOP ;; 3
|
||||||
|
1 ;; 4
|
||||||
|
1 ;; 6
|
||||||
|
MSTORE ;; 8
|
||||||
|
)
|
||||||
1
evmcc/test/jump/jump2.evm
Normal file
1
evmcc/test/jump/jump2.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
6008586001600154
|
||||||
10
evmcc/test/jump/jump2.lll
Normal file
10
evmcc/test/jump/jump2.lll
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
;; Direct JUMP to the end of code.
|
||||||
|
;; output: memory should have size 0.
|
||||||
|
|
||||||
|
(asm
|
||||||
|
8 ;; 0
|
||||||
|
JUMP ;; 2
|
||||||
|
1 ;; 3
|
||||||
|
1 ;; 5
|
||||||
|
MSTORE ;; 7
|
||||||
|
)
|
||||||
1
evmcc/test/jump/jump3.evm
Normal file
1
evmcc/test/jump/jump3.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
602a586001600154
|
||||||
10
evmcc/test/jump/jump3.lll
Normal file
10
evmcc/test/jump/jump3.lll
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
;; Direct JUMP past the end of code.
|
||||||
|
;; output: memory should have size 0.
|
||||||
|
|
||||||
|
(asm
|
||||||
|
42
|
||||||
|
JUMP
|
||||||
|
1
|
||||||
|
1
|
||||||
|
MSTORE
|
||||||
|
)
|
||||||
1
evmcc/test/jump/jump4.evm
Normal file
1
evmcc/test/jump/jump4.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
600b6009580000600558005d6001600154
|
||||||
17
evmcc/test/jump/jump4.lll
Normal file
17
evmcc/test/jump/jump4.lll
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
;; Direct JUMP.
|
||||||
|
;; output: memory[1] = 1
|
||||||
|
|
||||||
|
(asm
|
||||||
|
11 ;; 0
|
||||||
|
9 ;; 2
|
||||||
|
JUMP ;; 4 --> 9
|
||||||
|
STOP ;; 5
|
||||||
|
STOP ;; 6
|
||||||
|
5 ;; 7
|
||||||
|
JUMP ;; 9 --> 11
|
||||||
|
STOP ;; 10
|
||||||
|
JUMPDEST
|
||||||
|
1 ;; 11
|
||||||
|
1
|
||||||
|
MSTORE
|
||||||
|
)
|
||||||
1
evmcc/test/jump/jump5.evm
Normal file
1
evmcc/test/jump/jump5.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
6005600e585d600160015400600f5800
|
||||||
16
evmcc/test/jump/jump5.lll
Normal file
16
evmcc/test/jump/jump5.lll
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
;; Direct JUMP.
|
||||||
|
;; output: memory[1] = 1
|
||||||
|
|
||||||
|
(asm
|
||||||
|
5 ;; 0
|
||||||
|
14 ;; 2
|
||||||
|
JUMP ;; 4 --> 14
|
||||||
|
JUMPDEST ;; 5
|
||||||
|
1 ;; 6
|
||||||
|
1 ;; 8
|
||||||
|
MSTORE ;; 10
|
||||||
|
STOP ;; 11
|
||||||
|
15 ;; 12
|
||||||
|
JUMP ;; 14 --> 5
|
||||||
|
STOP ;; 15
|
||||||
|
)
|
||||||
1
evmcc/test/jump/jump6.evm
Normal file
1
evmcc/test/jump/jump6.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
600358600f600d58006014600758005d6001600154005d600260025400
|
||||||
32
evmcc/test/jump/jump6.lll
Normal file
32
evmcc/test/jump/jump6.lll
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
;; Direct JUMP.
|
||||||
|
;; output: memory[1] = 1
|
||||||
|
|
||||||
|
;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19
|
||||||
|
|
||||||
|
(asm
|
||||||
|
3 ;; 0
|
||||||
|
JUMP ;; 2
|
||||||
|
|
||||||
|
15 ;; 3 <- start
|
||||||
|
13 ;; 5
|
||||||
|
JUMP ;; 7 <- b
|
||||||
|
STOP ;; 8
|
||||||
|
|
||||||
|
20 ;; 9
|
||||||
|
7 ;; 11
|
||||||
|
|
||||||
|
JUMP ;; 13 <- a
|
||||||
|
STOP ;; 14
|
||||||
|
|
||||||
|
JUMPDEST ;; 15 <- c
|
||||||
|
1 ;; 16
|
||||||
|
1 ;; 18
|
||||||
|
MSTORE ;; 19
|
||||||
|
STOP ;; 20
|
||||||
|
|
||||||
|
JUMPDEST ;; 21 <- d
|
||||||
|
2 ;; 22
|
||||||
|
2 ;; 24
|
||||||
|
MSTORE ;; 26
|
||||||
|
STOP ;; 27
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue