Fabcoin Core  0.16.2
P2P Digital Currency
Array.cpp
Go to the documentation of this file.
1 #include "Array.h"
2 
4 #include <llvm/IR/Module.h>
5 #include <llvm/IR/Function.h>
7 
8 #include "RuntimeManager.h"
9 #include "Utils.h"
10 
11 namespace dev
12 {
13 namespace eth
14 {
15 namespace jit
16 {
17 
18 static const auto c_reallocStep = 1;
19 
20 llvm::Value* LazyFunction::call(IRBuilder& _builder, std::initializer_list<llvm::Value*> const& _args, llvm::Twine const& _name)
21 {
22  if (!m_func)
23  m_func = m_creator();
24 
25  return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name);
26 }
27 
28 llvm::Function* Array::createArrayPushFunc()
29 {
30  llvm::Type* argTypes[] = {m_array->getType(), Type::Word};
31  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule());
32  func->setDoesNotThrow();
33  func->setDoesNotCapture(1);
34 
35  auto iter = func->arg_begin();
36  llvm::Argument* arrayPtr = &(*iter++);
37  arrayPtr->setName("arrayPtr");
38  llvm::Argument* value = &(*iter);
39  value->setName("value");
40 
41  InsertPointGuard guard{m_builder};
42  auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func);
43  auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func);
44  auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
45 
46  m_builder.SetInsertPoint(entryBB);
47  auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
48  auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr");
49  auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr");
50  auto data = m_builder.CreateLoad(dataPtr, "data");
51  auto size = m_builder.CreateLoad(sizePtr, "size");
52  auto cap = m_builder.CreateLoad(capPtr, "cap");
53  auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq");
54  m_builder.CreateCondBr(reallocReq, reallocBB, pushBB);
55 
56  m_builder.SetInsertPoint(reallocBB);
57  auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap");
58  auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32
59  auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes");
60  auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes");
61  auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
62  m_builder.CreateStore(newData, dataPtr);
63  m_builder.CreateStore(newCap, capPtr);
64  m_builder.CreateBr(pushBB);
65 
66  m_builder.SetInsertPoint(pushBB);
67  auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi");
68  dataPhi->addIncoming(data, entryBB);
69  dataPhi->addIncoming(newData, reallocBB);
70  auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr");
71  m_builder.CreateStore(value, newElemPtr);
72  auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize");
73  m_builder.CreateStore(newSize, sizePtr);
74  m_builder.CreateRetVoid();
75 
76  return func;
77 }
78 
79 llvm::Function* Array::createArraySetFunc()
80 {
81  llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word};
82  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule());
83  func->setDoesNotThrow();
84  func->setDoesNotCapture(1);
85 
86  auto iter = func->arg_begin();
87  llvm::Argument* arrayPtr = &(*iter++);
88  arrayPtr->setName("arrayPtr");
89  llvm::Argument* index = &(*iter++);
90  index->setName("index");
91  llvm::Argument* value = &(*iter);
92  value->setName("value");
93 
94  InsertPointGuard guard{m_builder};
95  m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
96  auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
97  auto data = m_builder.CreateLoad(dataPtr, "data");
98  auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
99  m_builder.CreateStore(value, valuePtr);
100  m_builder.CreateRetVoid();
101  return func;
102 }
103 
104 llvm::Function* Array::createArrayGetFunc()
105 {
106  llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
107  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule());
108  func->setDoesNotThrow();
109  func->setDoesNotCapture(1);
110 
111  auto iter = func->arg_begin();
112  llvm::Argument* arrayPtr = &(*iter++);
113  arrayPtr->setName("arrayPtr");
114  llvm::Argument* index = &(*iter++);
115  index->setName("index");
116 
117  InsertPointGuard guard{m_builder};
118  m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
119  auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
120  auto data = m_builder.CreateLoad(dataPtr, "data");
121  auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
122  auto value = m_builder.CreateLoad(valuePtr, "value");
123  m_builder.CreateRet(value);
124  return func;
125 }
126 
127 llvm::Function* Array::createGetPtrFunc()
128 {
129  llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
130  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule());
131  func->setDoesNotThrow();
132  func->setDoesNotCapture(1);
133 
134  auto iter = func->arg_begin();
135  llvm::Argument* arrayPtr = &(*iter++);
136  arrayPtr->setName("arrayPtr");
137  llvm::Argument* index = &(*iter++);
138  index->setName("index");
139 
140  InsertPointGuard guard{m_builder};
141  m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
142  auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");
143  auto data = m_builder.CreateLoad(dataPtr, "data");
144  auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr");
145  auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr");
146  m_builder.CreateRet(wordPtr);
147  return func;
148 }
149 
150 llvm::Function* Array::createFreeFunc()
151 {
152  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule());
153  func->setDoesNotThrow();
154  func->setDoesNotCapture(1);
155 
156  auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "free", getModule());
157  freeFunc->setDoesNotThrow();
158  freeFunc->setDoesNotCapture(1);
159 
160  auto arrayPtr = &func->getArgumentList().front();
161  arrayPtr->setName("arrayPtr");
162 
163  InsertPointGuard guard{m_builder};
164  m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
165  auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr");
166  auto data = m_builder.CreateLoad(dataPtr, "data");
167  auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
168  m_builder.CreateCall(freeFunc, mem);
169  m_builder.CreateRetVoid();
170  return func;
171 }
172 
173 llvm::Function* Array::getReallocFunc()
174 {
175  if (auto func = getModule()->getFunction("realloc"))
176  return func;
177 
178  llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
179  auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "realloc", getModule());
180  reallocFunc->setDoesNotThrow();
181  reallocFunc->setDoesNotAlias(0);
182  reallocFunc->setDoesNotCapture(1);
183  return reallocFunc;
184 }
185 
186 llvm::Function* Array::createExtendFunc()
187 {
188  llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
189  auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule());
190  func->setDoesNotThrow();
191  func->setDoesNotCapture(1);
192 
193  auto iter = func->arg_begin();
194  llvm::Argument* arrayPtr = &(*iter++);
195  arrayPtr->setName("arrayPtr");
196  llvm::Argument* newSize = &(*iter++);
197  newSize->setName("newSize");
198 
199  InsertPointGuard guard{m_builder};
200  m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
201  auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array
202  auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr");
203  auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr");
204  auto data = m_builder.CreateLoad(dataPtr, "data");
205  auto size = m_builder.CreateLoad(sizePtr, "size");
206  auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize");
207  auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null
208  auto extPtr = m_builder.CreateGEP(newData, size, "extPtr");
209  m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16);
210  m_builder.CreateStore(newData, dataPtr);
211  m_builder.CreateStore(newSize, sizePtr);
212  m_builder.CreateStore(newSize, capPtr);
213  m_builder.CreateRetVoid();
214  return func;
215 }
216 
217 llvm::Type* Array::getType()
218 {
219  llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
220  static auto arrayTy = llvm::StructType::create(elementTys, "Array");
221  return arrayTy;
222 }
223 
224 Array::Array(IRBuilder& _builder, char const* _name) :
225  CompilerHelper(_builder)
226 {
227  m_array = m_builder.CreateAlloca(getType(), nullptr, _name);
228  m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
229 }
230 
231 Array::Array(IRBuilder& _builder, llvm::Value* _array) :
232  CompilerHelper(_builder),
233  m_array(_array)
234 {
235  m_builder.CreateStore(llvm::ConstantAggregateZero::get(getType()), m_array);
236 }
237 
238 
239 void Array::pop(llvm::Value* _count)
240 {
241  auto sizePtr = m_builder.CreateStructGEP(getType(), m_array, 1, "sizePtr");
242  auto size = m_builder.CreateLoad(sizePtr, "size");
243  auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
244  m_builder.CreateStore(newSize, sizePtr);
245 }
246 
248 {
249  auto sizePtr = m_builder.CreateStructGEP(getType(), _array ? _array : m_array, 1, "sizePtr");
250  return m_builder.CreateLoad(sizePtr, "array.size");
251 }
252 
254 {
255  assert(_arrayPtr->getType() == m_array->getType());
256  assert(_size->getType() == Type::Size);
257  m_extendFunc.call(m_builder, {_arrayPtr, _size});
258 }
259 
260 }
261 }
262 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
llvm::Function * createFreeFunc()
Definition: Array.cpp:150
llvm::Function * createExtendFunc()
Definition: Array.cpp:186
static llvm::Type * Void
Definition: Type.h:32
llvm::Value * call(IRBuilder &_builder, std::initializer_list< llvm::Value * > const &_args, llvm::Twine const &_name="")
Definition: Array.cpp:20
assert(len-trim+(2 *lenIndices)<=WIDTH)
LazyFunction m_extendFunc
Definition: Array.h:66
static llvm::Type * getType()
Definition: Array.cpp:217
static llvm::PointerType * WordPtr
Definition: Type.h:22
Base class for compiler helpers like Memory, GasMeter, etc.
llvm::Function * createArrayPushFunc()
Definition: Array.cpp:28
static llvm::PointerType * BytePtr
Definition: Type.h:30
Config::Value_type Value
llvm::Value * m_array
Definition: Array.h:51
void extend(llvm::Value *_arrayPtr, llvm::Value *_size)
Definition: Array.cpp:253
static llvm::IntegerType * Word
Definition: Type.h:21
std::vector< byte > bytes
Definition: Common.h:75
llvm::Function * createGetPtrFunc()
Definition: Array.cpp:127
void pop(llvm::Value *_count)
Definition: Array.cpp:239
llvm::Function * createArrayGetFunc()
Definition: Array.cpp:104
uint8_t const size_t const size
Definition: sha3.h:20
llvm::Function * getReallocFunc()
Definition: Array.cpp:173
Array(IRBuilder &_builder, char const *_name)
Definition: Array.cpp:224
static llvm::IntegerType * Size
Definition: Type.h:25
IRBuilder & m_builder
Reference to parent compiler IR builder.
llvm::Value * size(llvm::Value *_array=nullptr)
Definition: Array.cpp:247
llvm::IRBuilder<> IRBuilder
llvm::Function * createArraySetFunc()
Definition: Array.cpp:79
llvm::Function * m_func
Definition: Array.h:26
uint8_t const * data
Definition: sha3.h:19