Browse Source

Reimplementation of mem.require helper function. Uses 64-bit arithmetics.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
2aa0548674
  1. 57
      libevmjit/Memory.cpp
  2. 2
      libevmjit/Runtime.h

57
libevmjit/Memory.cpp

@ -30,14 +30,15 @@ llvm::Function* Memory::getRequireFunc()
{
llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
func->setDoesNotThrow();
auto mem = &func->getArgumentList().front();
mem->setName("mem");
auto offset = mem->getNextNode();
offset->setName("offset");
auto size = offset->getNextNode();
size->setName("size");
auto jmpBuf = size->getNextNode();
auto blkOffset = mem->getNextNode();
blkOffset->setName("blkOffset");
auto blkSize = blkOffset->getNextNode();
blkSize->setName("blkSize");
auto jmpBuf = blkSize->getNextNode();
jmpBuf->setName("jmpBuf");
auto gas = jmpBuf->getNextNode();
gas->setName("gas");
@ -51,36 +52,38 @@ llvm::Function* Memory::getRequireFunc()
// BB "Pre": Ignore checks with size 0
m_builder.SetInsertPoint(preBB);
auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);
m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue);
// BB "Check"
m_builder.SetInsertPoint(checkBB);
auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
auto currSize = m_memory.size(mem);
auto tooSmall = m_builder.CreateICmpULE(m_builder.CreateZExt(currSize, Type::Word), sizeRequired, "tooSmall");
auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?
static const auto c_inputMax = uint64_t(2) << 40; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below
auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk");
auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO");
auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk");
auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS");
auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0");
auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32
auto sizeCur = m_memory.size(mem);
auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk");
m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue);
// BB "Resize"
m_builder.SetInsertPoint(resizeBB);
// Check gas first
uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
auto words = m_builder.CreateUDiv(currSize, m_builder.getInt64(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, m_builder.CreateZExt(words, Type::Word), "addtionalWords");
m_gasMeter.countMemory(newWords, jmpBuf, gas);
auto sizeExt = m_builder.CreateNUWSub(sizeReq, sizeCur, "sizeExt");
auto sizeSum = m_builder.CreateNUWAdd(sizeReq, sizeCur, "sizeSum");
auto costL = m_builder.CreateLShr(sizeExt, 5, "costL");
auto costQ1 = m_builder.CreateLShr(sizeExt, 20, "costQ1");
auto costQ2 = m_builder.CreateLShr(sizeSum, 20, "costQ2");
auto costQ = m_builder.CreateNUWAdd(costQ1, costQ2, "costQ");
auto cost = m_builder.CreateNUWAdd(costL, costQ, "cost");
auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk");
auto c = m_builder.CreateSelect(costOk, costL, m_builder.getInt64(std::numeric_limits<int64_t>::max()), "c");
m_gasMeter.countMemory(c, jmpBuf, gas);
// Resize
auto extendSize = m_builder.CreateTrunc(sizeRequired, Type::Size, "extendSize");
m_memory.extend(mem, extendSize);
m_memory.extend(mem, sizeReq);
m_builder.CreateBr(returnBB);
// BB "Return"

2
libevmjit/Runtime.h

@ -27,7 +27,7 @@ private:
i256 m_memorySize;
public:
byte* m_memData = nullptr; // FIXME: Remember to free memory
uint64_t m_memSize = 0;
uint64_t m_memSize = 0; // TODO: Init array in LLVM, to allow more optimization
uint64_t m_memCap = 0;
};

Loading…
Cancel
Save