提交 41055352 编写于 作者: S Shreedhar Hardikar

Rewrite PGGenericFuncGenerator to support variable number of types

Currently PGFuncBaseGenerator and PGGenericFuncGenerator classes have
only one template that takes two argument only, i.e., two datums. These
templates can support only (built-in) functions that take two arguments
as input only (e.g., int4pl). However, there are built-in functions that
take either more or less than two arguments.
This will benefit count and average aggregate function.
上级 92cc0187
......@@ -315,6 +315,10 @@ if(EXISTS ${TXT_OBJFILE})
tests/codegen_framework_unittest.cc
${MOCK_DIR}/backend/postmaster/postmaster_mock.o
)
add_cmockery_gtest(codegen_pg_func_generator_unittest.t
tests/codegen_pg_func_generator_unittest.cc
${MOCK_DIR}/backend/postmaster/postmaster_mock.o
)
endif()
......
......@@ -214,10 +214,6 @@ bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
return true;
}
/** @} */
} // namespace gpcodegen
......
......@@ -24,99 +24,113 @@
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
typedef bool (*PGFuncGenerator)(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
// Helper template classes for gp_func_generators nested in here
namespace pg_func_generator_detail {
// PGFuncArgPreProcessor is a variadic template to assist in pre-processing a
// variable number of arguments to PGFuncBaseGenerator. Each specialization has
// a method called 'PreProcessArgs' that takes a pointer to 'CodegenUtils', an
// input vector of 'llvm:Values*' and another vector of 'llvm::Values*' that it
// populates by pre-processing the input vector. During pre-processsing, we
// generate LLVM instructions to convert the input 'llvm::Value*' values (that
// are expected to be of the type 'Datum') to the appropriate CppType from the
// variadic template list, and populate the output vector with coverted
// 'llvm::Values*' in the same order as input.
//
// e.g. PGFuncArgPreProcessor<int, bool>::PreProcessArgs(cu, vin, vout) will
// create instructions to convert vin[0] to int and vin[1] to bool and populate
// 'vout'.
template <typename... ArgumentTypes>
class PGFuncArgPreProcessor;
// Base version for zero argument types does nothing.
template <>
class PGFuncArgPreProcessor<> {
private:
static bool PreProcessArgsInternal(
gpcodegen::GpCodegenUtils* codegen_utils,
std::vector<llvm::Value*>::const_iterator llvm_in_args_iter,
std::vector<llvm::Value*>* llvm_out_args) {
return true;
}
// Make all template specializations of PGFuncArgPreProcessor friends
template <typename ... T>
friend class PGFuncArgPreProcessor;
};
/**
* @brief Base class for Greenplum Function generator.
*
* @tparam FuncPtrType Function type that generate code
* @tparam Arg0 First Argument CppType
* @tparam Arg1 Second Argument CppType
*
**/
// TODO(krajaraman) : Make Variadic template to take
// variable length argument instead of two arguments
template <typename FuncPtrType, typename Arg0, typename Arg1>
class PGFuncBaseGenerator : public PGFuncGeneratorInterface {
// Version for 1+ arguments that recurses
template <typename HeadType, typename ... TailTypes>
class PGFuncArgPreProcessor<HeadType, TailTypes...> {
public:
virtual ~PGFuncBaseGenerator() = default;
std::string GetName() final { return pg_func_name_; };
size_t GetTotalArgCount() final { return 2; }
protected:
/**
* @brief Check for expected arguments length and cast all the
* argument to given type.
*
* @param codegen_utils Utility to easy code generation.
* @param llvm_in_args Vector of llvm arguments
* @param llvm_out_args Vector of processed llvm arguments
*
* @return true on successful preprocess otherwise return false.
**/
bool PreProcessArgs(gpcodegen::GpCodegenUtils* codegen_utils,
const std::vector<llvm::Value*>& llvm_in_args,
std::vector<llvm::Value*>* llvm_out_args) {
static bool PreProcessArgs(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::vector<llvm::Value*>& llvm_in_args,
std::vector<llvm::Value*>* llvm_out_args) {
assert(nullptr != codegen_utils &&
nullptr != llvm_out_args);
if (llvm_in_args.size() != GetTotalArgCount()) {
if (llvm_in_args.size() != 1 /* HeadType */ + sizeof...(TailTypes)) {
return false;
}
// Convert Datum to given cpp type.
llvm_out_args->push_back(codegen_utils->CreateDatumToCppTypeCast
<Arg0>(llvm_in_args[0]));
llvm_out_args->push_back(codegen_utils->CreateDatumToCppTypeCast
<Arg1>(llvm_in_args[1]));
return true;
}
/**
* @return Function Pointer that generate code
**/
FuncPtrType func_ptr() {
return func_ptr_;
return PreProcessArgsInternal(
codegen_utils, llvm_in_args.begin(), llvm_out_args);
}
/**
* @brief Constructor.
*
* @param pg_func_oid Greenplum function Oid
* @param pg_func_name Greenplum function name
* @param func_ptr Function pointer that generate code
**/
PGFuncBaseGenerator(int pg_func_oid,
const std::string& pg_func_name,
FuncPtrType func_ptr) : pg_func_oid_(pg_func_oid),
pg_func_name_(pg_func_name),
func_ptr_(func_ptr) {
}
private:
unsigned int pg_func_oid_;
std::string pg_func_name_;
FuncPtrType func_ptr_;
static bool PreProcessArgsInternal(
gpcodegen::GpCodegenUtils* codegen_utils,
std::vector<llvm::Value*>::const_iterator llvm_in_args_iter,
std::vector<llvm::Value*>* llvm_out_args) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_args);
assert(nullptr != *llvm_in_args_iter);
assert(codegen_utils->GetType<Datum>() == (*llvm_in_args_iter)->getType());
// Convert Datum to given cpp type.
llvm_out_args->push_back(
codegen_utils->CreateDatumToCppTypeCast<HeadType>(*llvm_in_args_iter));
return PGFuncArgPreProcessor<TailTypes...>::PreProcessArgsInternal(
codegen_utils, ++llvm_in_args_iter, llvm_out_args);
}
// Make all template specializations of PGFuncArgPreProcessor friends
template <typename ... T>
friend class PGFuncArgPreProcessor;
};
} // namespace pg_func_generator_detail
/** \addtogroup gpcodegen
* @{
*/
typedef bool (*PGFuncGenerator)(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
/**
* @brief Object that use IRBuilder member function to generate code for
* given Greenplum function
* @brief Object that use an IRBuilder member function that to generate code for
* given binary GPDB function
*
* @tparam FuncPtrType Function type that generate code
* @tparam Arg0 First Argument CppType
* @tparam Arg1 Second Argument CppType
* @tparam ReturnType C++ type of return type of the GPDB function
* @tparam Arg0 C++ type of 1st argument of the GPDB function
* @tparam Arg1 C++ type of 2nd argument of the GPDB function
*
**/
template <typename FuncPtrType, typename Arg0, typename Arg1>
class PGIRBuilderFuncGenerator : public PGFuncBaseGenerator<FuncPtrType,
Arg0, Arg1> {
template <typename ReturnType, typename Arg0, typename Arg1>
class PGIRBuilderFuncGenerator
: public PGFuncGeneratorInterface {
public:
// Type of the IRBuilder function we need to call
using IRBuilderFuncPtrType = llvm::Value* (llvm::IRBuilder<>::*) (
llvm::Value*, llvm::Value*, const llvm::Twine&);
/**
* @brief Constructor.
*
......@@ -126,11 +140,19 @@ Arg0, Arg1> {
**/
PGIRBuilderFuncGenerator(int pg_func_oid,
const std::string& pg_func_name,
FuncPtrType mem_func_ptr) :
PGFuncBaseGenerator<FuncPtrType,
Arg0, Arg1>(pg_func_oid,
pg_func_name,
mem_func_ptr) {
IRBuilderFuncPtrType mem_func_ptr)
: pg_func_oid_(pg_func_oid),
pg_func_name_(pg_func_name),
func_ptr_(mem_func_ptr) {
}
std::string GetName() final {
return pg_func_name_;
}
size_t GetTotalArgCount() final {
// Support Binary IRBuilder functions only
return 2;
}
bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
......@@ -138,30 +160,37 @@ Arg0, Arg1> {
llvm::Value** llvm_out_value) final {
assert(nullptr != llvm_out_value);
std::vector<llvm::Value*> llvm_preproc_args;
if (!this->PreProcessArgs(codegen_utils,
pg_func_info.llvm_args,
&llvm_preproc_args)) {
if (!pg_func_generator_detail::PGFuncArgPreProcessor<Arg0, Arg1>::
PreProcessArgs(
codegen_utils, pg_func_info.llvm_args, &llvm_preproc_args)) {
return false;
}
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
*llvm_out_value = (irb->*this->func_ptr())(llvm_preproc_args[0],
*llvm_out_value = (irb->*this->func_ptr_)(llvm_preproc_args[0],
llvm_preproc_args[1], "");
assert((*llvm_out_value)->getType() ==
codegen_utils->GetType<ReturnType>());
return true;
}
private:
int pg_func_oid_;
std::string pg_func_name_;
IRBuilderFuncPtrType func_ptr_;
};
/**
* @brief Object that use static member function to generate code for
* @brief Object that uses a static member function to generate code for
* given Greenplum's function
*
* @tparam FuncPtrType Function type that generate code
* @tparam Arg0 First Argument CppType
* @tparam Arg1 Second Argument CppType
* @tparam Args Argument CppTypes
*
**/
template <typename Arg0, typename Arg1>
class PGGenericFuncGenerator : public PGFuncBaseGenerator<PGFuncGenerator,
Arg0, Arg1> {
template <typename ReturnType, typename ... Args>
class PGGenericFuncGenerator : public PGFuncGeneratorInterface {
public:
/**
* @brief Constructor.
......@@ -171,12 +200,19 @@ Arg0, Arg1> {
* @param func_ptr function pointer to static function
**/
PGGenericFuncGenerator(int pg_func_oid,
const std::string& pg_func_name,
PGFuncGenerator func_ptr) :
PGFuncBaseGenerator<PGFuncGenerator,
Arg0, Arg1>(pg_func_oid,
pg_func_name,
func_ptr) {
const std::string& pg_func_name,
PGFuncGenerator func_ptr)
: pg_func_oid_(pg_func_oid),
pg_func_name_(pg_func_name),
func_ptr_(func_ptr) {
}
std::string GetName() final {
return pg_func_name_;
}
size_t GetTotalArgCount() final {
return sizeof...(Args);
}
bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
......@@ -185,21 +221,33 @@ Arg0, Arg1> {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_value);
std::vector<llvm::Value*> llvm_preproc_args;
if (!this->PreProcessArgs(codegen_utils,
pg_func_info.llvm_args,
&llvm_preproc_args)) {
if (!pg_func_generator_detail::PGFuncArgPreProcessor<Args...>::
PreProcessArgs(
codegen_utils, pg_func_info.llvm_args, &llvm_preproc_args)) {
return false;
}
PGFuncGeneratorInfo pg_processed_func_info(pg_func_info.llvm_main_func,
pg_func_info.llvm_error_block,
llvm_preproc_args);
this->func_ptr()(codegen_utils,
this->func_ptr_(codegen_utils,
pg_processed_func_info,
llvm_out_value);
assert((*llvm_out_value)->getType() ==
codegen_utils->GetType<ReturnType>());
return true;
}
private:
int pg_func_oid_;
const std::string& pg_func_name_;
PGFuncGenerator func_ptr_;
};
/** @} */
} // namespace gpcodegen
......
......@@ -50,6 +50,7 @@ using gpcodegen::PGFuncGenerator;
using gpcodegen::CodeGenFuncMap;
using llvm::IRBuilder;
CodeGenFuncMap
OpExprTreeGenerator::supported_function_;
......@@ -57,17 +58,19 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
if (!supported_function_.empty()) { return; }
supported_function_[141] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
new PGGenericFuncGenerator<int32_t, int32_t, int32_t>(
141,
"int4mul",
&PGArithFuncGenerator<int32_t, int32_t, int32_t>::MulWithOverflow));
supported_function_[149] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGIRBuilderFuncGenerator<decltype(&IRBuilder<>::CreateICmpSLE),
int32_t, int32_t>(149, "int4le", &IRBuilder<>::CreateICmpSLE));
new PGIRBuilderFuncGenerator<int32_t, int32_t, int32_t>(
149,
"int4le",
&IRBuilder<>::CreateICmpSLE));
supported_function_[177] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
new PGGenericFuncGenerator<int32_t, int32_t, int32_t>(
177,
"int4pl",
&PGArithFuncGenerator<int32_t, int32_t, int32_t>::AddWithOverflow));
......@@ -79,7 +82,7 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
&PGArithFuncGenerator<int64_t, int64_t, int32_t>::AddWithOverflow));
supported_function_[181] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
new PGGenericFuncGenerator<int32_t, int32_t, int32_t>(
181,
"int4mi",
&PGArithFuncGenerator<int32_t, int32_t, int32_t>::SubWithOverflow));
......@@ -91,29 +94,29 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
&PGArithFuncGenerator<int64_t, int64_t, int64_t>::AddWithOverflow));
supported_function_[216] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<float8, float8>(
new PGGenericFuncGenerator<float8, float8, float8>(
216,
"float8mul",
&PGArithFuncGenerator<float8, float8, float8>::MulWithOverflow));
supported_function_[218] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<float8, float8>(
new PGGenericFuncGenerator<float8, float8, float8>(
218,
"float8pl",
&PGArithFuncGenerator<float8, float8, float8>::AddWithOverflow));
supported_function_[219] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<float8, float8>(
new PGGenericFuncGenerator<float8, float8, float8>(
219,
"float8mi",
&PGArithFuncGenerator<float8, float8, float8>::SubWithOverflow));
supported_function_[1088] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGIRBuilderFuncGenerator<decltype(&IRBuilder<>::CreateICmpSLE),
int32_t, int32_t>(1088, "date_le", &IRBuilder<>::CreateICmpSLE));
new PGIRBuilderFuncGenerator<bool, int32_t, int32_t>(
1088, "date_le", &IRBuilder<>::CreateICmpSLE));
supported_function_[2339] = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int64_t>(
new PGGenericFuncGenerator<int32_t, int32_t, int64_t>(
2339,
"date_le_timestamp",
&PGDateFuncGenerator::DateLETimestamp));
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright 2016 Pivotal Software, Inc.
//
// @filename:
// codegen_pg_func_generator_unittest.cc
//
// @doc:
// Unit tests for PGFuncGenerator
//
// @test:
//
//---------------------------------------------------------------------------
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <ctime>
#include <initializer_list>
#include <limits>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
extern "C" {
#include "postgres.h" // NOLINT(build/include)
#undef newNode // undef newNode so it doesn't have name collision with llvm
#include "utils/elog.h"
#undef elog
#define elog(...)
}
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Casting.h"
#include "codegen/utils/codegen_utils.h"
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/utils/utility.h"
#include "codegen/codegen_manager.h"
#include "codegen/codegen_wrapper.h"
#include "codegen/codegen_interface.h"
#include "codegen/base_codegen.h"
#include "codegen/pg_func_generator.h"
#include "codegen/pg_arith_func_generator.h"
namespace gpcodegen {
class PGFuncGeneratorTestEnvironment : public ::testing::Environment {
public:
virtual void SetUp() {
ASSERT_TRUE(CodegenUtils::InitializeGlobal());
}
};
class CodegenPGFuncGeneratorTest : public ::testing::Test {
protected:
virtual void SetUp() {
codegen_utils_.reset(new GpCodegenUtils("test_module"));
}
std::unique_ptr<gpcodegen::GpCodegenUtils> codegen_utils_;
};
// Helper Variadic template classes for recursive checking the types in an array
// of llvm::Values*
template<typename ... CppTypes>
class LLVMTypeChecker {
};
template<>
class LLVMTypeChecker<> {
public:
static void check(gpcodegen::GpCodegenUtils* codegen_utils,
std::vector<llvm::Value*>::const_iterator val_iter) {
}
};
template<typename HeadType, typename ... TailTypes>
class LLVMTypeChecker<HeadType, TailTypes...> {
public:
static void check(gpcodegen::GpCodegenUtils* codegen_utils,
std::vector<llvm::Value*>::const_iterator val_iter) {
EXPECT_EQ((*val_iter)->getType(), codegen_utils->GetType<HeadType>());
LLVMTypeChecker<TailTypes...>::check(codegen_utils, ++val_iter);
}
static void check(gpcodegen::GpCodegenUtils* codegen_utils,
const std::vector<llvm::Value*> & values) {
check(codegen_utils, values.begin());
}
};
// Helper method to check
template <typename ... CppTypes>
void CheckPGFuncArgPreProcessor(gpcodegen::GpCodegenUtils* codegen_utils) {
std::vector<llvm::Value*> in_values;
std::vector<llvm::Value*> out_values;
for (int i=0; i< sizeof...(CppTypes); ++i) {
in_values.push_back(codegen_utils->GetConstant<Datum>(i));
}
EXPECT_TRUE(pg_func_generator_detail::PGFuncArgPreProcessor<CppTypes...>
::PreProcessArgs(codegen_utils, in_values, &out_values));
EXPECT_EQ(sizeof...(CppTypes), out_values.size());
LLVMTypeChecker<CppTypes...>::check(codegen_utils, out_values);
}
// Test PGFuncArgPreProcessor with 1, 2 and 3 arguments of various types
TEST_F(CodegenPGFuncGeneratorTest, PGFuncArgPreProcessorTest ) {
using VoidFn = void (*) (void);
// Start of boiler plate
llvm::Function* dummy_fn =
codegen_utils_->CreateFunction<VoidFn>("dummy_fn");
llvm::BasicBlock* main_block =
codegen_utils_->CreateBasicBlock("main", dummy_fn);
codegen_utils_->ir_builder()->SetInsertPoint(main_block);
// end of boiler plate
// Test with one type
CheckPGFuncArgPreProcessor<u_int32_t>(codegen_utils_.get());
// Test with two types
CheckPGFuncArgPreProcessor<u_int32_t, u_int32_t>(
codegen_utils_.get());
// Test with three types
CheckPGFuncArgPreProcessor<u_int32_t, uint32_t, u_int32_t>(
codegen_utils_.get());
// Test with different types
CheckPGFuncArgPreProcessor<u_int32_t, int64_t, bool>(codegen_utils_.get());
// More boiler plate
codegen_utils_->ir_builder()->CreateRetVoid();
EXPECT_FALSE(llvm::verifyFunction(*dummy_fn));
EXPECT_FALSE(llvm::verifyModule(*codegen_utils_->module()));
// Prepare generated code for execution.
EXPECT_TRUE(codegen_utils_->PrepareForExecution(
CodegenUtils::OptimizationLevel::kNone,
true));
EXPECT_EQ(nullptr, codegen_utils_->module());
}
// Test PGGenericFuncGenerator with 2 arguments
TEST_F(CodegenPGFuncGeneratorTest, PGGenericFuncGeneratorTwoArgsTest) {
using DoubleFn = double (*) (Datum, Datum);
llvm::Function* double_add_fn =
codegen_utils_->CreateFunction<DoubleFn>("double_add_fn");
llvm::BasicBlock* main_block =
codegen_utils_->CreateBasicBlock("main", double_add_fn);
llvm::BasicBlock* error_block =
codegen_utils_->CreateBasicBlock("error", double_add_fn);
auto irb = codegen_utils_->ir_builder();
irb->SetInsertPoint(main_block);
auto generator = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<float8, float8, float8>(
218,
"float8pl",
&PGArithFuncGenerator<float8, float8, float8>::AddWithOverflow));
llvm::Value* result;
std::vector<llvm::Value*> args = {
ArgumentByPosition(double_add_fn, 0),
ArgumentByPosition(double_add_fn, 1)};
PGFuncGeneratorInfo pg_gen_info(double_add_fn, error_block, args);
EXPECT_TRUE(generator->GenerateCode(codegen_utils_.get(),
pg_gen_info, &result));
irb->CreateRet(result);
irb->SetInsertPoint(error_block);
irb->CreateRet(codegen_utils_->GetConstant<double>(0.0));
EXPECT_FALSE(llvm::verifyFunction(*double_add_fn));
EXPECT_FALSE(llvm::verifyModule(*codegen_utils_->module()));
// Prepare generated code for execution.
EXPECT_TRUE(codegen_utils_->PrepareForExecution(
CodegenUtils::OptimizationLevel::kNone,
true));
EXPECT_EQ(nullptr, codegen_utils_->module());
DoubleFn fn = codegen_utils_->GetFunctionPointer<DoubleFn>("double_add_fn");
double d1 = 1.0, d2 = 2.0;
EXPECT_EQ(3.0, fn(*reinterpret_cast<Datum*>(&d1),
*reinterpret_cast<Datum*>(&d2)));
}
// A method of type PGFuncGenerator as expected by PGGenericFuncGenerator
// that generates instructions to add 1 to the first input argument.
template <typename CppType>
bool GenerateAddOne(
gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
*llvm_out_value = codegen_utils->ir_builder()->CreateAdd(
pg_func_info.llvm_args[0],
codegen_utils->GetConstant<CppType>(1));
return true;
}
// Test PGGenericFuncGenerator with 1 arguments
TEST_F(CodegenPGFuncGeneratorTest, PGGenericFuncGeneratorOneArgTest) {
using AddOneFn = int32_t (*) (Datum);
llvm::Function* add_one_fn =
codegen_utils_->CreateFunction<AddOneFn>("add_one_fn");
llvm::BasicBlock* main_block =
codegen_utils_->CreateBasicBlock("main", add_one_fn);
llvm::BasicBlock* error_block =
codegen_utils_->CreateBasicBlock("error", add_one_fn);
auto irb = codegen_utils_->ir_builder();
irb->SetInsertPoint(main_block);
auto generator = std::unique_ptr<PGFuncGeneratorInterface>(
new PGGenericFuncGenerator<int32_t, int32_t>(
0,
"",
&GenerateAddOne<int32_t>));
llvm::Value* result = nullptr;
std::vector<llvm::Value*> args = {ArgumentByPosition(add_one_fn, 0)};
PGFuncGeneratorInfo pg_gen_info(add_one_fn, error_block, args);
EXPECT_TRUE(generator->GenerateCode(codegen_utils_.get(),
pg_gen_info,
&result));
irb->CreateRet(result);
irb->SetInsertPoint(error_block);
irb->CreateRet(codegen_utils_->GetConstant<int32_t>(-1));
EXPECT_FALSE(llvm::verifyFunction(*add_one_fn));
EXPECT_FALSE(llvm::verifyModule(*codegen_utils_->module()));
// Prepare generated code for execution.
EXPECT_TRUE(codegen_utils_->PrepareForExecution(
CodegenUtils::OptimizationLevel::kNone,
true));
EXPECT_EQ(nullptr, codegen_utils_->module());
AddOneFn fn = codegen_utils_->GetFunctionPointer<AddOneFn>("add_one_fn");
EXPECT_EQ(1, fn(0));
EXPECT_EQ(3, fn(2));
}
} // namespace gpcodegen
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
AddGlobalTestEnvironment(new gpcodegen::PGFuncGeneratorTestEnvironment);
return RUN_ALL_TESTS();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册