/ libevmjit / Array.cpp
Array.cpp
  1  #include "Array.h"
  2  
  3  #include "preprocessor/llvm_includes_start.h"
  4  #include <llvm/IR/Module.h>
  5  #include <llvm/IR/Function.h>
  6  #include "preprocessor/llvm_includes_end.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->addAttribute(1, llvm::Attribute::NoCapture);
 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->addAttribute(1, llvm::Attribute::NoCapture);
 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->addAttribute(1, llvm::Attribute::NoCapture);
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->addAttribute(1, llvm::Attribute::NoCapture);
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->addAttribute(1, llvm::Attribute::NoCapture);
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->addAttribute(1, llvm::Attribute::NoCapture);
159  
160  	llvm::Argument* arrayPtr{func->arg_begin()};
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->addAttribute(0, llvm::Attribute::NoAlias);
182  	reallocFunc->addAttribute(1, llvm::Attribute::NoCapture);
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->addAttribute(1, llvm::Attribute::NoCapture);
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  
247  llvm::Value* Array::size(llvm::Value* _array)
248  {
249  	auto sizePtr = m_builder.CreateStructGEP(getType(), _array ? _array : m_array, 1, "sizePtr");
250  	return m_builder.CreateLoad(sizePtr, "array.size");
251  }
252  
253  void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size)
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  }