Browse Source

initial implementation of JUMP/JUMPI (untested)

cl-refactor
artur-zawlocki 10 years ago
parent
commit
ca49fe4897
  1. 171
      evmcc/Compiler.cpp
  2. 16
      evmcc/Compiler.h

171
evmcc/Compiler.cpp

@ -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();

16
evmcc/Compiler.h

@ -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…
Cancel
Save