blob: eb7b265c10ef0b6b8de2b3e1ee06004afc89d0f7 [file] [log] [blame] [edit]
#pragma once
#include "llvm/IR/Module.h"
#include <string>
#include <vector>
//==============================================================================
// Simplifies the creation of functions.
//
// To create a function 'void foo( userType, i32, float* )' use the following
// code:
// FunctionBuilder(module,
// "foo").voidTy().type(userType).i32().floatPtr().build()
//
// The first type specified is the return type.
class FunctionBuilder {
public:
FunctionBuilder(llvm::Module *mod, const std::string &name)
: m_context(mod->getContext()), m_module(mod), m_name(name) {}
FunctionBuilder &voidTy() {
m_argNames.push_back("");
m_types.push_back(llvm::Type::getVoidTy(m_context));
return *this;
}
FunctionBuilder &floatTy(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getFloatTy(m_context));
return *this;
}
FunctionBuilder &floatPtr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getFloatPtrTy(m_context));
return *this;
}
FunctionBuilder &doubleTy(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getDoubleTy(m_context));
return *this;
}
FunctionBuilder &doublePtr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getDoublePtrTy(m_context));
return *this;
}
FunctionBuilder &i32(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt32Ty(m_context));
return *this;
}
FunctionBuilder &i32Ptr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt32PtrTy(m_context));
return *this;
}
FunctionBuilder &i16(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt16Ty(m_context));
return *this;
}
FunctionBuilder &i16Ptr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt16PtrTy(m_context));
return *this;
}
FunctionBuilder &i8(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt8Ty(m_context));
return *this;
}
FunctionBuilder &i8Ptr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt8PtrTy(m_context));
return *this;
}
FunctionBuilder &i1(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt1Ty(m_context));
return *this;
}
FunctionBuilder &i1Ptr(const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(llvm::Type::getInt1PtrTy(m_context));
return *this;
}
FunctionBuilder &type(llvm::Type *ty, const std::string &argName = "") {
m_argNames.push_back(argName);
m_types.push_back(ty);
return *this;
}
FunctionBuilder &types(const std::vector<llvm::Type *> &ty,
const std::vector<std::string> &argNames) {
if (argNames.empty())
for (size_t i = 0; i < ty.size(); ++i)
m_argNames.push_back("");
m_types.insert(m_types.end(), ty.begin(), ty.end());
return *this;
}
llvm::Function *build() {
using namespace llvm;
Type *retTy = m_types[0];
AttributeSet attributes;
Type **argsBegin = (&m_types[0]) + 1;
Type **argsEnd = argsBegin + m_types.size() - 1;
Constant *funcC = m_module->getOrInsertFunction(
m_name,
FunctionType::get(retTy, ArrayRef<Type *>(argsBegin, argsEnd), false),
attributes);
Function *func = cast<Function>(funcC);
std::string *argNamePtr = m_argNames.data() + 1;
for (auto &arg : func->args())
arg.setName(*argNamePtr++);
return func;
}
private:
llvm::LLVMContext &m_context;
llvm::Module *m_module = nullptr;
std::string m_name;
std::vector<std::string> m_argNames;
std::vector<llvm::Type *> m_types;
// forbidden
FunctionBuilder();
FunctionBuilder(const FunctionBuilder &);
};