llvm::Function* Array::createExtendFunc() { llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto newSize = arrayPtr->getNextNode(); newSize->setName("newSize"); InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize"); auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null auto extPtr = m_builder.CreateGEP(newData, size, "extPtr"); m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16); m_builder.CreateStore(newData, dataPtr); m_builder.CreateStore(newSize, sizePtr); m_builder.CreateStore(newSize, capPtr); m_builder.CreateRetVoid(); return func; }
llvm::Function* LocalStack::getStackPrepareFunc() { static const auto c_funcName = "stack.prepare"; if (auto func = getModule()->getFunction(c_funcName)) return func; llvm::Type* argsTys[] = {Type::WordPtr, Type::Size->getPointerTo(), Type::Size, Type::Size, Type::Size, Type::BytePtr}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argsTys, false), llvm::Function::PrivateLinkage, c_funcName, getModule()); func->setDoesNotThrow(); func->setDoesNotAccessMemory(1); func->setDoesNotAlias(2); func->setDoesNotCapture(2); auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); auto updateBB = llvm::BasicBlock::Create(func->getContext(), "Update", func); auto outOfStackBB = llvm::BasicBlock::Create(func->getContext(), "OutOfStack", func); auto iter = func->arg_begin(); llvm::Argument* base = &(*iter++); base->setName("base"); llvm::Argument* sizePtr = &(*iter++); sizePtr->setName("size.ptr"); llvm::Argument* min = &(*iter++); min->setName("min"); llvm::Argument* max = &(*iter++); max->setName("max"); llvm::Argument* diff = &(*iter++); diff->setName("diff"); llvm::Argument* jmpBuf = &(*iter); jmpBuf->setName("jmpBuf"); InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(checkBB); auto sizeAlignment = getModule()->getDataLayout().getABITypeAlignment(Type::Size); auto size = m_builder.CreateAlignedLoad(sizePtr, sizeAlignment, "size"); auto minSize = m_builder.CreateAdd(size, min, "size.min", false, true); auto maxSize = m_builder.CreateAdd(size, max, "size.max", true, true); auto minOk = m_builder.CreateICmpSGE(minSize, m_builder.getInt64(0), "ok.min"); auto maxOk = m_builder.CreateICmpULE(maxSize, m_builder.getInt64(RuntimeManager::stackSizeLimit), "ok.max"); auto ok = m_builder.CreateAnd(minOk, maxOk, "ok"); m_builder.CreateCondBr(ok, updateBB, outOfStackBB, Type::expectTrue); m_builder.SetInsertPoint(updateBB); auto newSize = m_builder.CreateNSWAdd(size, diff, "size.next"); m_builder.CreateAlignedStore(newSize, sizePtr, sizeAlignment); auto sp = m_builder.CreateGEP(base, size, "sp"); m_builder.CreateRet(sp); m_builder.SetInsertPoint(outOfStackBB); auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); m_builder.CreateCall(longjmp, {jmpBuf}); m_builder.CreateUnreachable(); return func; }
llvm::Function* Array::getReallocFunc() { if (auto func = getModule()->getFunction("ext_realloc")) return func; llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule()); reallocFunc->setDoesNotThrow(); reallocFunc->setDoesNotAlias(0); reallocFunc->setDoesNotCapture(1); return reallocFunc; }
llvm::Function* Array::createFreeFunc() { auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule()); freeFunc->setDoesNotThrow(); freeFunc->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem"); m_builder.CreateCall(freeFunc, mem); m_builder.CreateRetVoid(); return func; }
llvm::Function* Array::createArrayPushFunc() { llvm::Type* argTypes[] = {m_array->getType(), Type::Word}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto value = arrayPtr->getNextNode(); value->setName("value"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func); auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); m_builder.SetInsertPoint(entryBB); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto cap = m_builder.CreateLoad(capPtr, "cap"); auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq"); m_builder.CreateCondBr(reallocReq, reallocBB, pushBB); m_builder.SetInsertPoint(reallocBB); auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap"); auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32 auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes"); auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes"); auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData"); m_builder.CreateStore(newData, dataPtr); m_builder.CreateStore(newCap, capPtr); m_builder.CreateBr(pushBB); m_builder.SetInsertPoint(pushBB); auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi"); dataPhi->addIncoming(data, entryBB); dataPhi->addIncoming(newData, reallocBB); auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr"); m_builder.CreateStore(value, newElemPtr); auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize"); m_builder.CreateStore(newSize, sizePtr); m_builder.CreateRetVoid(); return func; }
llvm::Function* Array::createGetPtrFunc() { llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto index = arrayPtr->getNextNode(); index->setName("index"); InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr"); auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr"); m_builder.CreateRet(wordPtr); return func; }
llvm::Function* Array::createArraySetFunc() { llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto index = arrayPtr->getNextNode(); index->setName("index"); auto value = index->getNextNode(); value->setName("value"); InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); m_builder.CreateStore(value, valuePtr); m_builder.CreateRetVoid(); return func; }