mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
initial implementation of JUMP/JUMPI (untested)
This commit is contained in:
parent
eea755cfc6
commit
0b8ba6d2e4
2 changed files with 184 additions and 3 deletions
|
|
@ -39,6 +39,117 @@ Compiler::Compiler()
|
|||
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
|
||||
}
|
||||
|
||||
llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc)
|
||||
{
|
||||
llvm::BasicBlock* block = nullptr;
|
||||
auto blockIter = basicBlocks.find(pc);
|
||||
if (blockIter == basicBlocks.cend())
|
||||
{
|
||||
// Create a basic block at targetPC.
|
||||
std::ostringstream oss;
|
||||
oss << "instr." << pc;
|
||||
block = llvm::BasicBlock::Create(llvm::getGlobalContext(), oss.str());
|
||||
basicBlocks[pc] = block;
|
||||
}
|
||||
else
|
||||
{
|
||||
block = blockIter->second;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||
{
|
||||
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
|
||||
{
|
||||
using dev::eth::Instruction;
|
||||
|
||||
auto inst = static_cast<Instruction>(*curr);
|
||||
switch (inst)
|
||||
{
|
||||
case Instruction::PUSH1:
|
||||
case Instruction::PUSH2:
|
||||
case Instruction::PUSH3:
|
||||
case Instruction::PUSH4:
|
||||
case Instruction::PUSH5:
|
||||
case Instruction::PUSH6:
|
||||
case Instruction::PUSH7:
|
||||
case Instruction::PUSH8:
|
||||
case Instruction::PUSH9:
|
||||
case Instruction::PUSH10:
|
||||
case Instruction::PUSH11:
|
||||
case Instruction::PUSH12:
|
||||
case Instruction::PUSH13:
|
||||
case Instruction::PUSH14:
|
||||
case Instruction::PUSH15:
|
||||
case Instruction::PUSH16:
|
||||
case Instruction::PUSH17:
|
||||
case Instruction::PUSH18:
|
||||
case Instruction::PUSH19:
|
||||
case Instruction::PUSH20:
|
||||
case Instruction::PUSH21:
|
||||
case Instruction::PUSH22:
|
||||
case Instruction::PUSH23:
|
||||
case Instruction::PUSH24:
|
||||
case Instruction::PUSH25:
|
||||
case Instruction::PUSH26:
|
||||
case Instruction::PUSH27:
|
||||
case Instruction::PUSH28:
|
||||
case Instruction::PUSH29:
|
||||
case Instruction::PUSH30:
|
||||
case Instruction::PUSH31:
|
||||
case Instruction::PUSH32:
|
||||
{
|
||||
auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
|
||||
auto next = curr + numBytes + 1;
|
||||
if (next == bytecode.cend())
|
||||
break;
|
||||
|
||||
auto nextInst = static_cast<Instruction>(*next);
|
||||
|
||||
if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI)
|
||||
{
|
||||
// Compute target PC of the jump.
|
||||
dev::u256 val = 0;
|
||||
for (auto iter = curr + 1; iter < next; ++iter)
|
||||
{
|
||||
val <<= 8;
|
||||
val |= *iter;
|
||||
}
|
||||
|
||||
// Create a block for the JUMP target.
|
||||
ProgramCounter targetPC = val.convert_to<ProgramCounter>();
|
||||
auto targetBlock = getOrCreateBasicBlockAtPC(targetPC);
|
||||
|
||||
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
||||
jumpTargets[jumpPC] = targetBlock;
|
||||
|
||||
// Create a block following the JUMP.
|
||||
if (next + 1 < bytecode.cend())
|
||||
{
|
||||
ProgramCounter nextPC = (next + 1 - bytecode.cbegin());
|
||||
getOrCreateBasicBlockAtPC(nextPC);
|
||||
}
|
||||
|
||||
curr += 1; // skip over JUMP
|
||||
}
|
||||
|
||||
curr += numBytes;
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::JUMP:
|
||||
case Instruction::JUMPI:
|
||||
{
|
||||
std::cerr << "JUMP/JUMPI at " << (curr - bytecode.cbegin()) << " not preceded by PUSH\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||
{
|
||||
|
|
@ -52,23 +163,77 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false);
|
||||
auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get());
|
||||
|
||||
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
|
||||
builder.SetInsertPoint(entryBlock);
|
||||
|
||||
// Init stack and memory
|
||||
auto stack = Stack(builder, module.get());
|
||||
auto memory = Memory(builder, module.get());
|
||||
|
||||
auto ext = Ext(builder);
|
||||
|
||||
// Create the basic blocks.
|
||||
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
|
||||
basicBlocks[0] = entryBlock;
|
||||
createBasicBlocks(bytecode);
|
||||
|
||||
BasicBlock* currentBlock = nullptr;
|
||||
|
||||
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
|
||||
{
|
||||
using dev::eth::Instruction;
|
||||
|
||||
ProgramCounter currentPC = pc - bytecode.cbegin();
|
||||
|
||||
auto blockIter = basicBlocks.find(currentPC);
|
||||
if (blockIter != basicBlocks.end())
|
||||
{
|
||||
auto nextBlock = blockIter->second;
|
||||
if (currentBlock != nullptr)
|
||||
{
|
||||
// Terminate the current block by jumping to the next one.
|
||||
builder.CreateBr(nextBlock);
|
||||
}
|
||||
// Insert the next block into the main function.
|
||||
if (nextBlock != entryBlock)
|
||||
mainFunc->getBasicBlockList().push_back(nextBlock);
|
||||
builder.SetInsertPoint(nextBlock);
|
||||
currentBlock = nextBlock;
|
||||
}
|
||||
|
||||
assert(currentBlock != nullptr);
|
||||
|
||||
auto inst = static_cast<Instruction>(*pc);
|
||||
switch (inst)
|
||||
{
|
||||
|
||||
case Instruction::JUMP:
|
||||
{
|
||||
// The target address is computed at compile time,
|
||||
// just pop it without looking...
|
||||
stack.pop();
|
||||
|
||||
auto targetBlock = jumpTargets[currentPC];
|
||||
builder.CreateBr(targetBlock);
|
||||
|
||||
currentBlock = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::JUMPI:
|
||||
{
|
||||
assert(pc + 1 < bytecode.cend());
|
||||
|
||||
// The target address is computed at compile time,
|
||||
// just pop it without looking...
|
||||
stack.pop();
|
||||
|
||||
auto cond = stack.pop();
|
||||
auto targetBlock = jumpTargets[currentPC];
|
||||
auto followBlock = basicBlocks[currentPC + 1];
|
||||
builder.CreateCondBr(cond, targetBlock, followBlock);
|
||||
|
||||
currentBlock = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::ADD:
|
||||
{
|
||||
auto lhs = stack.pop();
|
||||
|
|
|
|||
|
|
@ -12,10 +12,26 @@ class Compiler
|
|||
{
|
||||
public:
|
||||
|
||||
using ProgramCounter = uint64_t;
|
||||
|
||||
Compiler();
|
||||
|
||||
std::unique_ptr<llvm::Module> compile(const dev::bytes& bytecode);
|
||||
|
||||
private:
|
||||
|
||||
llvm::BasicBlock* getOrCreateBasicBlockAtPC(ProgramCounter pc);
|
||||
void createBasicBlocks(const dev::bytes& bytecode);
|
||||
|
||||
/**
|
||||
* Maps a program counter pc to a basic block which starts at pc (if any).
|
||||
*/
|
||||
std::map<ProgramCounter, llvm::BasicBlock*> basicBlocks;
|
||||
|
||||
/**
|
||||
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
||||
*/
|
||||
std::map<ProgramCounter, llvm::BasicBlock*> jumpTargets;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue