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 }