提交 4916a606 编写于 作者: S Shreedhar Hardikar

Add support for registering vararg external functions with codegen utils.

上级 a9c1ef15
......@@ -162,11 +162,12 @@ class CodegenUtils {
*
* @tparam ReturnType The function's return type.
* @tparam ArgumentTypes The types of any number of arguments to the function.
* @param is_var_arg Whether the function has trailing variable arguments list
* @return A pointer to the complete function type-signature's equivalent as
* an LLVM FunctionType in this CodegenUtils's context.
**/
template <typename ReturnType, typename... ArgumentTypes>
llvm::FunctionType* GetFunctionType();
llvm::FunctionType* GetFunctionType(const bool is_var_arg = false);
/**
* @brief Get an LLVM constant based on a C++ value.
......@@ -231,6 +232,7 @@ class CodegenUtils {
* @tparam FuncType FunctionType. e.g ReturnType (*)(ArgumenTypes)
*
* @param name The function's name.
* @param is_var_arg Whether the function has trailing variable arguments list
* @param linkage The linkage visibility of the function. Defaults to
* ExternalLinkage, which makes the function visible and callable from
* anywhere.
......@@ -240,6 +242,7 @@ class CodegenUtils {
template <typename FuncType>
llvm::Function* CreateFunction(
const llvm::Twine& name,
const bool is_var_arg = false,
const llvm::GlobalValue::LinkageTypes linkage
= llvm::GlobalValue::ExternalLinkage);
......@@ -294,12 +297,14 @@ class CodegenUtils {
* so that the registered function will also be callable by its name
* in C++ source code compiled by ClangCompiler (see
* ClangCompiler::GenerateExternalFunctionDeclarations()).
* @param is_var_arg Whether the function has trailing variable arguments list
* @return A callable LLVM function.
**/
template <typename ReturnType, typename... ArgumentTypes>
llvm::Function* RegisterExternalFunction(
ReturnType (*external_function)(ArgumentTypes...),
const std::string& name = "") {
const std::string& name = "",
const bool is_var_arg = false) {
external_functions_.emplace_back(
name.empty() ? GenerateExternalFunctionName()
: name,
......@@ -310,9 +315,20 @@ class CodegenUtils {
}
return CreateFunctionImpl<ReturnType, ArgumentTypes...>(
external_functions_.back().first);
external_functions_.back().first, is_var_arg);
}
template <typename ReturnType, typename... ArgumentTypes>
llvm::Function* RegisterExternalFunction(
ReturnType (*external_function)(ArgumentTypes..., ...),
const std::string& name = "") {
return RegisterExternalFunction(
reinterpret_cast<ReturnType (*) (ArgumentTypes...)>(external_function),
name,
true);
}
/**
* @brief Optimize the code in the module managed by this CodegenUtils before
* execution.
......@@ -412,6 +428,7 @@ class CodegenUtils {
template <typename ReturnType, typename... ArgumentTypes>
llvm::Function* CreateFunctionImpl(
const llvm::Twine& name,
const bool is_var_arg = false,
const llvm::GlobalValue::LinkageTypes linkage
= llvm::GlobalValue::ExternalLinkage);
......@@ -781,12 +798,12 @@ class TypeVectorBuilder<HeadType, TailTypes...> {
} // namespace codegen_utils_detail
template <typename ReturnType, typename... ArgumentTypes>
llvm::FunctionType* CodegenUtils::GetFunctionType() {
llvm::FunctionType* CodegenUtils::GetFunctionType(const bool is_var_arg) {
std::vector<llvm::Type*> argument_types;
codegen_utils_detail::TypeVectorBuilder<ArgumentTypes...>::AppendTypes(
this,
&argument_types);
return llvm::FunctionType::get(GetType<ReturnType>(), argument_types, false);
return llvm::FunctionType::get(GetType<ReturnType>(), argument_types, is_var_arg);
}
// ----------------------------------------------------------------------------
......@@ -985,9 +1002,10 @@ class FunctionTypeUnpacker<ReturnType(*)(ArgumentTypes...)> {
static llvm::Function* CreateFunctionImpl(
CodegenUtils* codegen_utils,
const llvm::Twine& name,
const bool is_var_arg,
const llvm::GlobalValue::LinkageTypes linkage) {
return codegen_utils->CreateFunctionImpl<ReturnType, ArgumentTypes...>(
name, linkage);
name, is_var_arg, linkage);
}
static auto GetFunctionPointerImpl(gpcodegen::CodegenUtils* codegen_utils,
......@@ -1002,17 +1020,19 @@ class FunctionTypeUnpacker<ReturnType(*)(ArgumentTypes...)> {
template <typename FunctionType>
llvm::Function* CodegenUtils::CreateFunction(
const llvm::Twine& name,
const bool is_var_arg,
const llvm::GlobalValue::LinkageTypes linkage) {
return codegen_utils_detail::FunctionTypeUnpacker<FunctionType>::
CreateFunctionImpl(this, name, linkage);
CreateFunctionImpl(this, name, is_var_arg, linkage);
}
template <typename ReturnType, typename... ArgumentTypes>
llvm::Function* CodegenUtils::CreateFunctionImpl(
const llvm::Twine& name,
const bool is_var_arg,
const llvm::GlobalValue::LinkageTypes linkage) {
return llvm::Function::Create(
GetFunctionType<ReturnType, ArgumentTypes...>(),
GetFunctionType<ReturnType, ArgumentTypes...>(is_var_arg),
linkage,
name,
module_.get());
......
......@@ -1776,6 +1776,73 @@ TEST_F(CodegenUtilsTest, ExternalFunctionTest) {
EXPECT_EQ(42, StaticIntWrapper::Get());
}
TEST_F(CodegenUtilsTest, VariadicExternalFunctionTest) {
// Test a function with overloads an external function that contains
// variable length arguments : printf and sprintf
// Register printf with takes variable arguments past char*
llvm::Function* llvm_printf_function =
codegen_utils_->RegisterExternalFunction(printf);
ASSERT_NE(llvm_printf_function, nullptr);
ASSERT_EQ(
(codegen_utils_->GetFunctionType<int, char*>(true)->getPointerTo()),
llvm_printf_function->getType());
// Register sprintf with takes variable arguments past char*, char*
llvm::Function* llvm_sprintf_function =
codegen_utils_->RegisterExternalFunction(sprintf);
ASSERT_NE(llvm_sprintf_function, nullptr);
ASSERT_EQ(
(codegen_utils_->GetFunctionType<int, char*, char*>(true)->getPointerTo()),
llvm_sprintf_function->getType());
char sprintf_with_three_args_buffer[16], sprintf_with_four_args_buffer[16];
// Create a simple function that calls sprintf with 3 and 4 arguments and uses
// the buffers allocated above
typedef void (*SprintfTestType)();
llvm::Function* sprintf_test =
codegen_utils_->CreateFunction<SprintfTestType>("sprintf_test");
llvm::BasicBlock* main_block =
codegen_utils_->CreateBasicBlock( "main", sprintf_test);
codegen_utils_->ir_builder()->SetInsertPoint(main_block);
codegen_utils_->ir_builder()->CreateCall(
llvm_printf_function, {
codegen_utils_->GetConstant("%s %d"),
codegen_utils_->GetConstant("Zero is another way of saying "),
codegen_utils_->GetConstant(0)
});
codegen_utils_->ir_builder()->CreateCall(
llvm_sprintf_function, {
codegen_utils_->GetConstant(sprintf_with_three_args_buffer),
codegen_utils_->GetConstant("%d"),
codegen_utils_->GetConstant(42)
});
codegen_utils_->ir_builder()->CreateCall(
llvm_sprintf_function, {
codegen_utils_->GetConstant(sprintf_with_four_args_buffer),
codegen_utils_->GetConstant("%d %s"),
codegen_utils_->GetConstant(51),
codegen_utils_->GetConstant("fifty-one")
});
codegen_utils_->ir_builder()->CreateRetVoid();
// Check that the module is well-formed and prepare the generated wrapper
// functions for execution.
EXPECT_FALSE(llvm::verifyModule(*codegen_utils_->module()));
EXPECT_TRUE(codegen_utils_->PrepareForExecution(
CodegenUtils::OptimizationLevel::kNone,
true));
SprintfTestType llvm_sprintf_test =
codegen_utils_->GetFunctionPointer<SprintfTestType>("sprintf_test");
llvm_sprintf_test();
ASSERT_EQ(strcmp(sprintf_with_three_args_buffer, "42"), 0);
ASSERT_EQ(strcmp(sprintf_with_four_args_buffer, "51 fifty-one"), 0);
}
TEST_F(CodegenUtilsTest, RecursionTest) {
// Test a version of the factorial function that works by recursion.
typedef unsigned (*FactorialRecursiveFn) (unsigned);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册