mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 04:06:44 +00:00
Introducing BasicBlock class.
It is a wrapper for llvm::BasicBlock to provide additional information needed by EVM compiler. For now the order of basic blocks might not match bytecode. [#80113672]
This commit is contained in:
parent
cc51bfded6
commit
0961908efa
4 changed files with 60 additions and 27 deletions
13
evmcc/BasicBlock.cpp
Normal file
13
evmcc/BasicBlock.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include "BasicBlock.h"
|
||||||
|
|
||||||
|
#include <llvm/IR/Function.h>
|
||||||
|
|
||||||
|
namespace evmcc
|
||||||
|
{
|
||||||
|
|
||||||
|
BasicBlock::BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc)
|
||||||
|
: m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_instIdx)}, _mainFunc))
|
||||||
|
{}
|
||||||
|
|
||||||
|
}
|
||||||
22
evmcc/BasicBlock.h
Normal file
22
evmcc/BasicBlock.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
#include <llvm/IR/BasicBlock.h>
|
||||||
|
|
||||||
|
namespace evmcc
|
||||||
|
{
|
||||||
|
|
||||||
|
using ProgramCounter = uint64_t;
|
||||||
|
|
||||||
|
class BasicBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc);
|
||||||
|
BasicBlock(const BasicBlock&) = delete;
|
||||||
|
void operator=(const BasicBlock&) = delete;
|
||||||
|
|
||||||
|
operator llvm::BasicBlock*() { return m_llvmBB; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
llvm::BasicBlock* m_llvmBB;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -39,23 +39,15 @@ Compiler::Compiler()
|
||||||
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
|
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc)
|
BasicBlock& Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc)
|
||||||
{
|
{
|
||||||
llvm::BasicBlock* block = nullptr;
|
|
||||||
auto blockIter = basicBlocks.find(pc);
|
auto blockIter = basicBlocks.find(pc);
|
||||||
if (blockIter == basicBlocks.cend())
|
if (blockIter == basicBlocks.end())
|
||||||
{
|
{
|
||||||
// Create a basic block at targetPC.
|
// Create a basic block at target pc directly in collection
|
||||||
std::ostringstream oss;
|
blockIter = basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(pc), std::forward_as_tuple(pc, m_mainFunc)).first;
|
||||||
oss << "instr." << pc;
|
|
||||||
block = llvm::BasicBlock::Create(llvm::getGlobalContext(), oss.str());
|
|
||||||
basicBlocks[pc] = block;
|
|
||||||
}
|
}
|
||||||
else
|
return blockIter->second;
|
||||||
{
|
|
||||||
block = blockIter->second;
|
|
||||||
}
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
|
|
@ -122,7 +114,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
|
|
||||||
// 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>();
|
||||||
auto targetBlock = getOrCreateBasicBlockAtPC(targetPC);
|
auto& targetBlock = getOrCreateBasicBlockAtPC(targetPC);
|
||||||
|
|
||||||
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
||||||
jumpTargets[jumpPC] = targetBlock;
|
jumpTargets[jumpPC] = targetBlock;
|
||||||
|
|
@ -177,13 +169,12 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
|
|
||||||
// Create main function
|
// Create main function
|
||||||
const auto i32Ty = builder.getInt32Ty();
|
const auto i32Ty = builder.getInt32Ty();
|
||||||
Type* retTypeElems[] = {i32Ty, i32Ty};
|
//Type* retTypeElems[] = {i32Ty, i32Ty};
|
||||||
auto retType = StructType::create(retTypeElems, "MemRef", true);
|
//auto retType = StructType::create(retTypeElems, "MemRef", true);
|
||||||
auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false);
|
m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get());
|
||||||
auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get());
|
|
||||||
|
|
||||||
// Create the basic blocks.
|
// Create the basic blocks.
|
||||||
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
|
auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc);
|
||||||
builder.SetInsertPoint(entryBlock);
|
builder.SetInsertPoint(entryBlock);
|
||||||
createBasicBlocks(bytecode);
|
createBasicBlocks(bytecode);
|
||||||
|
|
||||||
|
|
@ -192,7 +183,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto memory = Memory(builder, module.get());
|
auto memory = Memory(builder, module.get());
|
||||||
auto ext = Ext(builder, module.get());
|
auto ext = Ext(builder, module.get());
|
||||||
|
|
||||||
BasicBlock* currentBlock = entryBlock;
|
llvm::BasicBlock* currentBlock = entryBlock;
|
||||||
BBStack stack(extStack); // Stack for current block
|
BBStack stack(extStack); // Stack for current block
|
||||||
|
|
||||||
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
|
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
|
||||||
|
|
@ -204,12 +195,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto blockIter = basicBlocks.find(currentPC);
|
auto blockIter = basicBlocks.find(currentPC);
|
||||||
if (blockIter != basicBlocks.end())
|
if (blockIter != basicBlocks.end())
|
||||||
{
|
{
|
||||||
auto nextBlock = blockIter->second;
|
auto& nextBlock = blockIter->second;
|
||||||
// Terminate the current block by jumping to the next one.
|
// Terminate the current block by jumping to the next one.
|
||||||
if (currentBlock != nullptr)
|
if (currentBlock != nullptr)
|
||||||
builder.CreateBr(nextBlock);
|
builder.CreateBr(nextBlock);
|
||||||
// Insert the next block into the main function.
|
// Insert the next block into the main function.
|
||||||
mainFunc->getBasicBlockList().push_back(nextBlock);
|
|
||||||
builder.SetInsertPoint(nextBlock);
|
builder.SetInsertPoint(nextBlock);
|
||||||
currentBlock = nextBlock;
|
currentBlock = nextBlock;
|
||||||
assert(stack.empty()); // Stack should be empty
|
assert(stack.empty()); // Stack should be empty
|
||||||
|
|
@ -601,7 +591,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
||||||
stack.reset();
|
stack.reset();
|
||||||
auto targetBlock = jumpTargets[currentPC];
|
auto targetBlock = jumpTargets[currentPC];
|
||||||
auto followBlock = basicBlocks[currentPC + 1];
|
auto& followBlock = basicBlocks.find(currentPC + 1)->second;
|
||||||
builder.CreateCondBr(cond, targetBlock, followBlock);
|
builder.CreateCondBr(cond, targetBlock, followBlock);
|
||||||
|
|
||||||
currentBlock = nullptr;
|
currentBlock = nullptr;
|
||||||
|
|
@ -792,12 +782,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto finalPC = bytecode.size();
|
auto finalPC = bytecode.size();
|
||||||
auto it = basicBlocks.find(finalPC);
|
auto it = basicBlocks.find(finalPC);
|
||||||
assert(it != basicBlocks.end());
|
assert(it != basicBlocks.end());
|
||||||
auto finalBlock = it->second;
|
auto& finalBlock = it->second;
|
||||||
|
|
||||||
if (currentBlock != nullptr)
|
if (currentBlock != nullptr)
|
||||||
builder.CreateBr(finalBlock);
|
builder.CreateBr(finalBlock);
|
||||||
|
|
||||||
mainFunc->getBasicBlockList().push_back(finalBlock);
|
|
||||||
builder.SetInsertPoint(finalBlock);
|
builder.SetInsertPoint(finalBlock);
|
||||||
builder.CreateRet(builder.getInt64(0));
|
builder.CreateRet(builder.getInt64(0));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
|
|
||||||
|
#include "BasicBlock.h"
|
||||||
|
|
||||||
namespace evmcc
|
namespace evmcc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -20,18 +22,25 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
llvm::BasicBlock* getOrCreateBasicBlockAtPC(ProgramCounter pc);
|
BasicBlock& getOrCreateBasicBlockAtPC(ProgramCounter pc);
|
||||||
void createBasicBlocks(const dev::bytes& bytecode);
|
void createBasicBlocks(const dev::bytes& bytecode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a program counter pc to a basic block which starts at pc (if any).
|
* Maps a program counter pc to a basic block which starts at pc (if any).
|
||||||
*/
|
*/
|
||||||
std::map<ProgramCounter, llvm::BasicBlock*> basicBlocks;
|
std::map<ProgramCounter, BasicBlock> basicBlocks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
||||||
*/
|
*/
|
||||||
std::map<ProgramCounter, llvm::BasicBlock*> jumpTargets;
|
std::map<ProgramCounter, llvm::BasicBlock*> jumpTargets;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Collection of basic blocks in program
|
||||||
|
//std::vector<BasicBlock> m_basicBlocks;
|
||||||
|
|
||||||
|
/// Main program function
|
||||||
|
llvm::Function* m_mainFunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue