Fabcoin Core  0.16.2
P2P Digital Currency
BasicBlock.cpp
Go to the documentation of this file.
1 #include "BasicBlock.h"
2 
3 #include <iostream>
4 
6 #include <llvm/IR/CFG.h>
7 #include <llvm/IR/Module.h>
8 #include <llvm/IR/Function.h>
9 #include <llvm/IR/Instructions.h>
10 #include <llvm/IR/IntrinsicInst.h>
11 #include <llvm/IR/IRBuilder.h>
12 #include <llvm/Support/raw_os_ostream.h>
14 
15 #include "RuntimeManager.h"
16 #include "Type.h"
17 #include "Utils.h"
18 
19 namespace dev
20 {
21 namespace eth
22 {
23 namespace jit
24 {
25 
26 BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc):
27  m_firstInstrIdx{_firstInstrIdx},
28  m_begin(_begin),
29  m_end(_end),
30  m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {".", std::to_string(_firstInstrIdx)}, _mainFunc))
31 {}
32 
33 LocalStack::LocalStack(IRBuilder& _builder, RuntimeManager& _runtimeManager):
34  CompilerHelper(_builder)
35 {
36  // Call stack.prepare. min, max, size args will be filled up in finalize().
37  auto undef = llvm::UndefValue::get(Type::Size);
38  m_sp = m_builder.CreateCall(getStackPrepareFunc(),
39  {_runtimeManager.getStackBase(), _runtimeManager.getStackSize(), undef, undef, undef, _runtimeManager.getJmpBuf()},
40  {"sp", m_builder.GetInsertBlock()->getName()});
41 }
42 
44 {
45  assert(_value->getType() == Type::Word);
46  m_local.push_back(_value);
48 }
49 
51 {
52  auto item = get(0);
53  assert(!m_local.empty() || !m_input.empty());
54 
55  if (m_local.size() > 0)
56  m_local.pop_back();
57  else
58  ++m_globalPops;
59 
61  return item;
62 }
63 
65 void LocalStack::dup(size_t _index)
66 {
67  auto val = get(_index);
68  push(val);
69 }
70 
72 void LocalStack::swap(size_t _index)
73 {
74  assert(_index > 0);
75  auto val = get(_index);
76  auto tos = get(0);
77  set(_index, tos);
78  set(0, val);
79 }
80 
82 {
83  if (_index < m_local.size())
84  return *(m_local.rbegin() + _index); // count from back
85 
86  auto idx = _index - m_local.size() + m_globalPops;
87  if (idx >= m_input.size())
88  m_input.resize(idx + 1);
89  auto& item = m_input[idx];
90 
91  if (!item)
92  {
93  // Fetch an item from global stack
94  ssize_t globalIdx = -static_cast<ssize_t>(idx) - 1;
95  auto slot = m_builder.CreateConstGEP1_64(m_sp, globalIdx);
96  item = m_builder.CreateAlignedLoad(slot, 16); // TODO: Handle malloc alignment. Also for 32-bit systems.
97  m_minSize = std::min(m_minSize, globalIdx); // remember required stack size
98  }
99 
100  return item;
101 }
102 
103 void LocalStack::set(size_t _index, llvm::Value* _word)
104 {
105  if (_index < m_local.size())
106  {
107  *(m_local.rbegin() + _index) = _word;
108  return;
109  }
110 
111  auto idx = _index - m_local.size() + m_globalPops;
112  assert(idx < m_input.size());
113  m_input[idx] = _word;
114 }
115 
116 
118 {
119  m_sp->setArgOperand(2, m_builder.getInt64(minSize()));
120  m_sp->setArgOperand(3, m_builder.getInt64(maxSize()));
121  m_sp->setArgOperand(4, m_builder.getInt64(size()));
122 
123  if (auto term = m_builder.GetInsertBlock()->getTerminator())
124  m_builder.SetInsertPoint(term); // Insert before terminator
125 
126  auto inputIt = m_input.rbegin();
127  auto localIt = m_local.begin();
128  for (auto globalIdx = -static_cast<ssize_t>(m_input.size()); globalIdx < size(); ++globalIdx)
129  {
130  llvm::Value* item = nullptr;
131  if (globalIdx < -m_globalPops)
132  {
133  item = *inputIt++; // update input items (might contain original value)
134  if (!item) // some items are skipped
135  continue;
136  }
137  else
138  item = *localIt++; // store new items
139 
140  auto slot = m_builder.CreateConstGEP1_64(m_sp, globalIdx);
141  m_builder.CreateAlignedStore(item, slot, 16); // TODO: Handle malloc alignment. Also for 32-bit systems.
142  }
143 }
144 
145 
147 {
148  static const auto c_funcName = "stack.prepare";
149  if (auto func = getModule()->getFunction(c_funcName))
150  return func;
151 
152  llvm::Type* argsTys[] = {Type::WordPtr, Type::Size->getPointerTo(), Type::Size, Type::Size, Type::Size, Type::BytePtr};
153  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argsTys, false), llvm::Function::PrivateLinkage, c_funcName, getModule());
154  func->setDoesNotThrow();
155  func->setDoesNotAccessMemory(1);
156  func->setDoesNotAlias(2);
157  func->setDoesNotCapture(2);
158 
159  auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
160  auto updateBB = llvm::BasicBlock::Create(func->getContext(), "Update", func);
161  auto outOfStackBB = llvm::BasicBlock::Create(func->getContext(), "OutOfStack", func);
162 
163  auto iter = func->arg_begin();
164  llvm::Argument* base = &(*iter++);
165  base->setName("base");
166  llvm::Argument* sizePtr = &(*iter++);
167  sizePtr->setName("size.ptr");
168  llvm::Argument* min = &(*iter++);
169  min->setName("min");
170  llvm::Argument* max = &(*iter++);
171  max->setName("max");
172  llvm::Argument* diff = &(*iter++);
173  diff->setName("diff");
174  llvm::Argument* jmpBuf = &(*iter);
175  jmpBuf->setName("jmpBuf");
176 
178  m_builder.SetInsertPoint(checkBB);
179  auto sizeAlignment = getModule()->getDataLayout().getABITypeAlignment(Type::Size);
180  auto size = m_builder.CreateAlignedLoad(sizePtr, sizeAlignment, "size");
181  auto minSize = m_builder.CreateAdd(size, min, "size.min", false, true);
182  auto maxSize = m_builder.CreateAdd(size, max, "size.max", true, true);
183  auto minOk = m_builder.CreateICmpSGE(minSize, m_builder.getInt64(0), "ok.min");
184  auto maxOk = m_builder.CreateICmpULE(maxSize, m_builder.getInt64(RuntimeManager::stackSizeLimit), "ok.max");
185  auto ok = m_builder.CreateAnd(minOk, maxOk, "ok");
186  m_builder.CreateCondBr(ok, updateBB, outOfStackBB, Type::expectTrue);
187 
188  m_builder.SetInsertPoint(updateBB);
189  auto newSize = m_builder.CreateNSWAdd(size, diff, "size.next");
190  m_builder.CreateAlignedStore(newSize, sizePtr, sizeAlignment);
191  auto sp = m_builder.CreateGEP(base, size, "sp");
192  m_builder.CreateRet(sp);
193 
194  m_builder.SetInsertPoint(outOfStackBB);
195  auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
196  m_builder.CreateCall(longjmp, {jmpBuf});
197  m_builder.CreateUnreachable();
198 
199  return func;
200 }
201 
202 
203 }
204 }
205 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void dup(size_t _index)
Duplicates _index&#39;th value on stack.
Definition: BasicBlock.cpp:65
void finalize()
Finalize local stack: check the requirements and update of the global stack.
Definition: BasicBlock.cpp:117
llvm::BasicBlock *const m_llvmBB
Reference to the LLVM BasicBlock.
Definition: BasicBlock.h:83
llvm::Module * getModule()
Reference to the IR module being compiled.
llvm::Value * pop()
Pops and returns top value.
Definition: BasicBlock.cpp:50
ssize_t m_minSize
Minimum reached local stack size. Can be negative.
Definition: BasicBlock.h:63
assert(len-trim+(2 *lenIndices)<=WIDTH)
llvm::Value * getStackSize() const
ExecStats::duration min
Definition: ExecStats.cpp:35
static llvm::PointerType * WordPtr
Definition: Type.h:22
byte const * code_iterator
Definition: Common.h:11
Base class for compiler helpers like Memory, GasMeter, etc.
void set(size_t _index, llvm::Value *_value)
Sets _index&#39;th value from top (counting from 0)
Definition: BasicBlock.cpp:103
static llvm::PointerType * BytePtr
Definition: Type.h:30
Config::Value_type Value
code_iterator const m_begin
Iterator pointing code beginning of the block.
Definition: BasicBlock.h:80
code_iterator const m_end
Iterator pointing code end of the block.
Definition: BasicBlock.h:81
LocalStack(IRBuilder &_builder, RuntimeManager &_runtimeManager)
Definition: BasicBlock.cpp:33
ExecStats::duration max
Definition: ExecStats.cpp:36
static llvm::IntegerType * Word
Definition: Type.h:21
ssize_t m_globalPops
Number of items poped from global stack. In other words: global - local stack overlap.
Definition: BasicBlock.h:62
void swap(size_t _index)
Swaps _index&#39;th value on stack with a value on stack top.
Definition: BasicBlock.cpp:72
llvm::CallInst * m_sp
Call to stack.prepare function which returns stack pointer for current basic block.
Definition: BasicBlock.h:60
ssize_t size() const
Definition: BasicBlock.h:37
uint64_t instr_idx
Definition: BasicBlock.h:15
void push(llvm::Value *_value)
Pushes value on stack.
Definition: BasicBlock.cpp:43
ssize_t m_maxSize
Maximum reached local stack size.
Definition: BasicBlock.h:64
static const size_t stackSizeLimit
std::vector< llvm::Value * > m_local
Local stack items that has not been pushed to global stack. First item is just above global stack...
Definition: BasicBlock.h:58
llvm::Value * get(size_t _index)
Gets _index&#39;th value from top (counting from 0)
Definition: BasicBlock.cpp:81
ssize_t maxSize() const
Definition: BasicBlock.h:39
N diff(N const &_a, N const &_b)
Definition: Common.h:212
BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function *_mainFunc)
Definition: BasicBlock.cpp:26
static llvm::IntegerType * Size
Definition: Type.h:25
IRBuilder & m_builder
Reference to parent compiler IR builder.
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
Definition: Common.h:326
llvm::IRBuilder<> IRBuilder
static llvm::MDNode * expectTrue
Definition: Type.h:42
llvm::Value * getStackBase() const
std::vector< llvm::Value * > m_input
Items fetched from global stack.
Definition: BasicBlock.h:55
ssize_t minSize() const
Definition: BasicBlock.h:38
llvm::Function * getStackPrepareFunc()
Definition: BasicBlock.cpp:146