提交 aae0ad3d 编写于 作者: N Nikos Armenatzoglou

Create naive code-generated version of ExecQual

This commit generates code for a naive code-generated version of ExecQual that simply fallbacks to regular ExecQual.
The code-generated ExecQual is enrolled in the existing codegen framework and is called only in ExecScan.
After the implementation of the function (i.e., generate code for expression evaluation), we can replace all calls to regular ExecQual with call_ExecQual macros.
上级 dce266ad
......@@ -165,6 +165,7 @@ set(GPCODEGEN_SRC
codegen_manager.cc
codegen_wrapper.cc
exec_variable_list_codegen.cc
exec_qual_codegen.cc
)
# Integrate with GPDB build system.
......
......@@ -13,12 +13,14 @@
#include "codegen/codegen_wrapper.h"
#include "codegen/codegen_manager.h"
#include "codegen/exec_variable_list_codegen.h"
#include "codegen/exec_qual_codegen.h"
#include "codegen/utils/codegen_utils.h"
using gpcodegen::CodegenManager;
using gpcodegen::BaseCodegen;
using gpcodegen::ExecVariableListCodegen;
using gpcodegen::ExecQualCodegen;
// Current code generator manager that oversees all code generators
static void* ActiveCodeGeneratorManager = nullptr;
......@@ -116,3 +118,13 @@ void* ExecVariableListCodegenEnroll(
regular_func_ptr, ptr_to_chosen_func_ptr, proj_info, slot);
return generator;
}
void* ExecQualCodegenEnroll(
ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_chosen_func_ptr,
PlanState *planstate) {
ExecQualCodegen* generator = CodegenEnroll<ExecQualCodegen>(
regular_func_ptr, ptr_to_chosen_func_ptr, planstate);
return generator;
}
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// ExecQual_codegen.cc
//
// @doc:
// Generates code for ExecQual function.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <cstdint>
#include <string>
#include "codegen/exec_qual_codegen.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
#include "codegen/utils/codegen_utils.h"
#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/Support/Casting.h"
extern "C" {
#include "postgres.h"
#include "utils/elog.h"
}
using gpcodegen::ExecQualCodegen;
constexpr char ExecQualCodegen::kExecQualPrefix[];
class ElogWrapper {
public:
ElogWrapper(gpcodegen::CodegenUtils* codegen_utils) :
codegen_utils_(codegen_utils) {
SetupElog();
}
~ElogWrapper() {
TearDownElog();
}
template<typename... V>
void CreateElog(
llvm::Value* llvm_elevel,
llvm::Value* llvm_fmt,
V ... args ) {
assert(NULL != llvm_elevel);
assert(NULL != llvm_fmt);
codegen_utils_->ir_builder()->CreateCall(
llvm_elog_start_, {
codegen_utils_->GetConstant(""), // Filename
codegen_utils_->GetConstant(0), // line number
codegen_utils_->GetConstant("") // function name
});
codegen_utils_->ir_builder()->CreateCall(
llvm_elog_finish_, {
llvm_elevel,
llvm_fmt,
args...
});
}
template<typename... V>
void CreateElog(
int elevel,
const char* fmt,
V ... args ) {
CreateElog(codegen_utils_->GetConstant(elevel),
codegen_utils_->GetConstant(fmt),
args...);
}
private:
llvm::Function* llvm_elog_start_;
llvm::Function* llvm_elog_finish_;
gpcodegen::CodegenUtils* codegen_utils_;
void SetupElog(){
assert(codegen_utils_ != nullptr);
llvm_elog_start_ = codegen_utils_->RegisterExternalFunction(elog_start);
assert(llvm_elog_start_ != nullptr);
llvm_elog_finish_ = codegen_utils_->RegisterExternalFunction(elog_finish);
assert(llvm_elog_finish_ != nullptr);
}
void TearDownElog(){
llvm_elog_start_ = nullptr;
llvm_elog_finish_ = nullptr;
}
};
ExecQualCodegen::ExecQualCodegen
(
ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
PlanState *planstate) :
BaseCodegen(kExecQualPrefix, regular_func_ptr, ptr_to_regular_func_ptr),
planstate_(planstate) {
}
bool ExecQualCodegen::GenerateExecQual(
gpcodegen::CodegenUtils* codegen_utils) {
assert(NULL != codegen_utils);
ElogWrapper elogwrapper(codegen_utils);
llvm::Function* exec_qual_func = codegen_utils->
CreateFunction<ExecQualFn>(
GetUniqueFuncName());
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
"entry", exec_qual_func);
auto irb = codegen_utils->ir_builder();
irb->SetInsertPoint(entry_block);
elogwrapper.CreateElog(DEBUG1, "Falling back to regular ExecQual.");
codegen_utils->CreateFallback<ExecQualFn>(
codegen_utils->RegisterExternalFunction(GetRegularFuncPointer()),
exec_qual_func);
return true;
}
bool ExecQualCodegen::GenerateCodeInternal(CodegenUtils* codegen_utils) {
bool isGenerated = GenerateExecQual(codegen_utils);
if (isGenerated) {
elog(DEBUG1, "ExecQual was generated successfully!");
return true;
}
else {
elog(DEBUG1, "ExecQual generation failed!");
return false;
}
}
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// ExecQual_codegen.h
//
// @doc:
// Headers for ExecQual codegen.
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_EXECQUAL_CODEGEN_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_EXECQUAL_CODEGEN_H_
#include "codegen/codegen_wrapper.h"
#include "codegen/base_codegen.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class ExecQualCodegen: public BaseCodegen<ExecQualFn> {
public:
/**
* @brief Constructor
*
* @param regular_func_ptr Regular version of the target function.
* @param ptr_to_chosen_func_ptr Reference to the function pointer that the caller will call.
* @param slot The slot to use for generating code.
*
* @note The ptr_to_chosen_func_ptr can refer to either the generated function or the
* corresponding regular version.
*
**/
explicit ExecQualCodegen(ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
PlanState *planstate);
virtual ~ExecQualCodegen() = default;
protected:
/**
* @brief Generate code for ExecQual.
*
* @param codegen_utils
*
* @return true on successful generation; false otherwise.
*
* @note Currently, it simply falls back to regular ExecQual.
*/
bool GenerateCodeInternal(gpcodegen::CodegenUtils* codegen_utils) final;
private:
PlanState *planstate_;
static constexpr char kExecQualPrefix[] = "ExecQual";
/**
* @brief Generates runtime code that implements ExecQual.
*
* @param codegen_utils Utility to ease the code generation process.
* @return true on successful generation.
**/
bool GenerateExecQual(gpcodegen::CodegenUtils* codegen_utils);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_EXECQUAL_CODEGEN_H_
......@@ -753,6 +753,9 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
if (result != NULL)
{
enroll_ExecQual_codegen(ExecQual,
&result->ExecQual_gen_info.ExecQual_fn, result);
SAVE_EXECUTOR_MEMORY_ACCOUNT(result, curMemoryAccount);
result->CodegenManager = CodegenManager;
CodeGeneratorManagerGenerateCode(CodegenManager);
......
......@@ -156,7 +156,7 @@ ExecScan(ScanState *node,
* when the qual is nil ... saves only a few cycles, but they add up
* ...
*/
if (!qual || ExecQual(qual, econtext, false))
if (!qual || call_ExecQual(node->ps, qual, econtext, false))
{
/*
* Found a satisfactory scan tuple.
......
......@@ -26,8 +26,11 @@ typedef int64 Datum;
*/
struct TupleTableSlot;
struct ProjectionInfo;
struct List;
struct ExprContext;
typedef void (*ExecVariableListFn) (struct ProjectionInfo *projInfo, Datum *values, bool *isnull);
typedef bool (*ExecQualFn) (struct List *qual, struct ExprContext *econtext, bool resultForNull);
#ifndef USE_CODEGEN
......@@ -44,9 +47,12 @@ typedef void (*ExecVariableListFn) (struct ProjectionInfo *projInfo, Datum *valu
#define END_CODE_GENERATOR_MANAGER()
#define init_codegen()
#define call_ExecVariableList(projInfo, values, isnull) ExecVariableList(projInfo, values, isnull)
#define enroll_ExecVariableList_codegen(regular_func, ptr_to_chosen_func, proj_info, slot)
#define call_ExecQual(planstate, qual, econtext, resultForNull) ExecQual(qual, econtext, resultForNull)
#define enroll_ExecQual_codegen(regular_func, ptr_to_chosen_func, planstate)
#else
/*
......@@ -76,7 +82,7 @@ extern "C" {
* Forward extern declaration of code generated functions if code gen is enabled
*/
extern void ExecVariableList(struct ProjectionInfo *projInfo, Datum *values, bool *isnull);
extern bool ExecQual(struct List *qual, struct ExprContext *econtext, bool resultForNull);
/*
* Do one-time global initialization of LLVM library. Returns 1
......@@ -137,6 +143,14 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
struct ProjectionInfo* proj_info,
struct TupleTableSlot* slot);
/*
* returns the pointer to the ExecQual
*/
void*
ExecQualCodegenEnroll(ExecQualFn regular_func_ptr,
ExecQualFn* ptr_to_regular_func_ptr,
struct PlanState *planstate);
#ifdef __cplusplus
} // extern "C"
#endif
......@@ -186,6 +200,14 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
*/
#define call_ExecVariableList(projInfo, values, isnull) \
projInfo->ExecVariableList_gen_info.ExecVariableList_fn(projInfo, values, isnull)
/*
* Call ExecQual using function pointer ExecQual_fn.
* Function pointer may point to regular version or generated function
*/
#define call_ExecQual(ps, qual, econtext, resultForNull) \
ps.ExecQual_gen_info.ExecQual_fn(qual, econtext, resultForNull)
/*
* Enrollment macros
* The enrollment process also ensures that the generated function pointer
......@@ -196,6 +218,11 @@ ExecVariableListCodegenEnroll(ExecVariableListFn regular_func_ptr,
regular_func, ptr_to_regular_func_ptr, proj_info, slot); \
Assert(proj_info->ExecVariableList_gen_info.ExecVariableList_fn == regular_func); \
#define enroll_ExecQual_codegen(regular_func, ptr_to_regular_func_ptr, planstate) \
planstate->ExecQual_gen_info.code_generator = ExecQualCodegenEnroll( \
regular_func, ptr_to_regular_func_ptr, planstate); \
Assert(planstate->ExecQual_gen_info.ExecQual_fn == regular_func); \
#endif //USE_CODEGEN
#endif // CODEGEN_WRAPPER_H_
......@@ -1316,6 +1316,14 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
typedef struct ExecQualCodegenInfo
{
/* Pointer to store ExecQualCodegen from Codegen */
void* code_generator;
/* Function pointer that points to either regular or generated slot_deform_tuple */
ExecQualFn ExecQual_fn;
} ExecQualCodegenInfo;
/* ----------------
* PlanState node
*
......@@ -1385,6 +1393,10 @@ typedef struct PlanState
*/
int gpmon_plan_tick;
gpmon_packet_t gpmon_pkt;
#ifdef USE_CODEGEN
ExecQualCodegenInfo ExecQual_gen_info;
#endif
} PlanState;
typedef struct Gpmon_NameUnit_MaxVal
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册