提交 88a04412 编写于 作者: S Shreedhar Hardikar

Use ExprTreeGeneratorInfo for expression tree generation.

ExprTreeGeneratorInfo object keeps track of metadata information
needed to generate code for expression trees.
Refactor ExprTreeGenerators to always use econtext->ecxt_scantuple to
generate the functions. We also have an extra slot_check block to fall
back if it is called with a different slot - which shouldn't happen for
Agg and Scan nodes.
上级 3b4af3bb
......@@ -173,6 +173,7 @@ set(GPCODEGEN_SRC
codegen_wrapper.cc
const_expr_tree_generator.cc
exec_variable_list_codegen.cc
slot_getattr_codegen.cc
exec_eval_expr_codegen.cc
expr_tree_generator.cc
op_expr_tree_generator.cc
......
......@@ -122,9 +122,10 @@ void* ExecEvalExprCodegenEnroll(
ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_chosen_func_ptr,
ExprState *exprstate,
ExprContext *econtext) {
ExprContext *econtext,
TupleTableSlot* slot) {
ExecEvalExprCodegen* generator = CodegenEnroll<ExecEvalExprCodegen>(
regular_func_ptr, ptr_to_chosen_func_ptr, exprstate, econtext);
regular_func_ptr, ptr_to_chosen_func_ptr, exprstate, econtext, slot);
return generator;
}
......
......@@ -24,8 +24,8 @@ using gpcodegen::ConstExprTreeGenerator;
using gpcodegen::ExprTreeGenerator;
bool ConstExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree) {
assert(nullptr != expr_state &&
nullptr != expr_state->expr &&
......@@ -35,16 +35,14 @@ bool ConstExprTreeGenerator::VerifyAndCreateExprTree(
return true;
}
ConstExprTreeGenerator::ConstExprTreeGenerator(ExprState* expr_state) :
ConstExprTreeGenerator::ConstExprTreeGenerator(const ExprState* expr_state) :
ExprTreeGenerator(expr_state, ExprTreeNodeType::kConst) {
}
bool ConstExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
llvm::Value** llvm_out_value) {
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) {
assert(nullptr != llvm_out_value);
Const* const_expr = reinterpret_cast<Const*>(expr_state()->expr);
*llvm_out_value = codegen_utils->GetConstant(const_expr->constvalue);
......
......@@ -13,12 +13,12 @@
#include <cstdint>
#include <string>
#include "codegen/slot_getattr_codegen.h"
#include "codegen/exec_eval_expr_codegen.h"
#include "codegen/expr_tree_generator.h"
#include "codegen/op_expr_tree_generator.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"
......@@ -44,6 +44,7 @@ extern "C" {
}
using gpcodegen::ExecEvalExprCodegen;
using gpcodegen::SlotGetAttrCodegen;
constexpr char ExecEvalExprCodegen::kExecEvalExprPrefix[];
......@@ -52,11 +53,13 @@ ExecEvalExprCodegen::ExecEvalExprCodegen
ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
ExprState *exprstate,
ExprContext *econtext) :
ExprContext *econtext,
TupleTableSlot* slot) :
BaseCodegen(kExecEvalExprPrefix,
regular_func_ptr, ptr_to_regular_func_ptr),
exprstate_(exprstate),
econtext_(econtext) {
econtext_(econtext),
slot_(slot) {
}
......@@ -86,27 +89,58 @@ bool ExecEvalExprCodegen::GenerateExecEvalExpr(
auto irb = codegen_utils->ir_builder();
irb->SetInsertPoint(llvm_entry_block);
codegen_utils->CreateElog(
DEBUG1,
"Calling codegen'ed expression evaluation");
// Check if we can codegen. If so create ExprTreeGenerator
ExprTreeGeneratorInfo gen_info(econtext_,
exec_eval_expr_func,
llvm_error_block,
nullptr,
0);
std::unique_ptr<ExprTreeGenerator> expr_tree_generator(nullptr);
bool can_generate = ExprTreeGenerator::VerifyAndCreateExprTree(
exprstate_, econtext_, &expr_tree_generator);
exprstate_, &gen_info, &expr_tree_generator);
if (!can_generate ||
expr_tree_generator.get() == nullptr) {
return false;
}
// Generate dependant slot_getattr() implementation for the given slot
if (gen_info.max_attr > 0) {
assert(nullptr != slot_);
std::string slot_getattr_func_name = "slot_getattr_" +
std::to_string(reinterpret_cast<uint64_t>(slot_)) + "_" +
std::to_string(gen_info.max_attr);
bool ok = SlotGetAttrCodegen::GenerateSlotGetAttr(
codegen_utils,
slot_getattr_func_name,
slot_,
gen_info.max_attr,
&gen_info.llvm_slot_getattr_func);
if (!ok) {
elog(DEBUG1, "slot_getattr generation for ExecEvalExpr failed!");
}
}
// In case the generation above failed either or it was not needed,
// we revert to use the external slot_getattr()
if (nullptr == gen_info.llvm_slot_getattr_func) {
gen_info.llvm_slot_getattr_func =
codegen_utils->GetOrRegisterExternalFunction(slot_getattr);
}
irb->SetInsertPoint(llvm_entry_block);
codegen_utils->CreateElog(
DEBUG1,
"Calling codegen'ed expression evaluation");
// Generate code from expression tree generator
llvm::Value* value = nullptr;
bool is_generated = expr_tree_generator->GenerateCode(codegen_utils,
econtext_,
exec_eval_expr_func,
llvm_error_block,
gen_info,
llvm_isnull_arg,
&value);
if (!is_generated ||
......
......@@ -9,15 +9,16 @@
// Contains different code generators
//
//---------------------------------------------------------------------------
#include "codegen/exec_variable_list_codegen.h"
#include <algorithm>
#include <cstdint>
#include <string>
#include "codegen/exec_variable_list_codegen.h"
#include "codegen/slot_getattr_codegen.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/base_codegen.h"
......@@ -46,6 +47,7 @@ extern "C" {
}
using gpcodegen::ExecVariableListCodegen;
using gpcodegen::SlotGetAttrCodegen;
constexpr char ExecVariableListCodegen::kExecVariableListPrefix[];
......@@ -137,9 +139,9 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// Generate slot_getattr for attributes all the way to max_attr
std::string slot_getattr_func_name = "slot_getattr_" + std::to_string(max_attr);
llvm::Function* slot_getattr_func = nullptr;
if (!ExecVariableListCodegen::WrapGenerateSlotGetAttr(
if (!SlotGetAttrCodegen::GenerateSlotGetAttr(
codegen_utils, slot_getattr_func_name, slot_, max_attr, &slot_getattr_func)) {
elog(DEBUG1, "Cannot generate code for ExecVariableList"
elog(DEBUG1, "Cannot generate code for ExecVariableList "
"because slot_getattr generation failed!");
return false;
}
......@@ -241,498 +243,6 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
}
// TODO(shardikar, krajaraman) Remove this wrapper after implementing shared
// code generation interface
bool ExecVariableListCodegen::WrapGenerateSlotGetAttr(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot *slot,
int max_attr,
llvm::Function** out_func) {
*out_func = nullptr;
bool ret = ExecVariableListCodegen::GenerateSlotGetAttr(
codegen_utils, function_name, slot, max_attr, out_func);
if (*out_func && !llvm::verifyFunction(**out_func)) {
(*out_func)->eraseFromParent();
}
return ret;
}
bool ExecVariableListCodegen::GenerateSlotGetAttr(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot *slot,
int max_attr,
llvm::Function** out_func) {
// So looks like we're going to generate code
llvm::Function* slot_getattr_func =
codegen_utils->CreateFunction<SlotGetAttrFn>(function_name);
auto irb = codegen_utils->ir_builder();
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
"entry", slot_getattr_func);
// BasicBlock for checking correct slot
llvm::BasicBlock* slot_check_block = codegen_utils->CreateBasicBlock(
"slot_check", slot_getattr_func);
// BasicBlock for checking tuple type.
llvm::BasicBlock* tuple_type_check_block = codegen_utils->CreateBasicBlock(
"tuple_type_check", slot_getattr_func);
// BasicBlock for heap tuple check.
llvm::BasicBlock* heap_tuple_check_block = codegen_utils->CreateBasicBlock(
"heap_tuple_check", slot_getattr_func);
// BasicBlock for main.
llvm::BasicBlock* main_block = codegen_utils->CreateBasicBlock(
"main", slot_getattr_func);
// BasicBlock for final computations.
llvm::BasicBlock* final_block = codegen_utils->CreateBasicBlock(
"final", slot_getattr_func);
// BasicBlock for fall back.
llvm::BasicBlock* fallback_block = codegen_utils->CreateBasicBlock(
"fallback", slot_getattr_func);
// External functions
llvm::Function* llvm_memset = codegen_utils->GetOrRegisterExternalFunction(memset);
// Generation-time constants
llvm::Value* llvm_slot = codegen_utils->GetConstant(slot);
llvm::Value* llvm_max_attr = codegen_utils->GetConstant(max_attr);
// Function arguments to slot_getattr
llvm::Value* llvm_slot_arg = ArgumentByPosition(slot_getattr_func, 0);
llvm::Value* llvm_attnum_arg = ArgumentByPosition(slot_getattr_func, 1);
llvm::Value* llvm_isnull_ptr_arg = ArgumentByPosition(slot_getattr_func, 2);
// Entry block
// -----------
irb->SetInsertPoint(entry_block);
// We start a sequence of checks to ensure that everything is fine and
// we do not need to fall back.
irb->CreateBr(tuple_type_check_block);
// Slot check block
// ----------------
irb->SetInsertPoint(slot_check_block);
// Compare slot given during code generation and the one passed
// in as an argument to slot_getattr
irb->CreateCondBr(
irb->CreateICmpEQ(llvm_slot, llvm_slot_arg),
main_block /* true */,
fallback_block /* false */);
// Tuple type check block
// ----------------------
// We fall back if we see a virtual tuple or mem tuple,
// but it's possible to partially handle those cases also
irb->SetInsertPoint(tuple_type_check_block);
llvm::Value* llvm_slot_PRIVATE_tts_flags_ptr =
codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_flags);
llvm::Value* llvm_slot_PRIVATE_tts_memtuple =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_memtuple));
// (slot->PRIVATE_tts_flags & TTS_VIRTUAL) != 0
llvm::Value* llvm_tuple_is_virtual = irb->CreateICmpNE(
irb->CreateAnd(
irb->CreateLoad(llvm_slot_PRIVATE_tts_flags_ptr),
codegen_utils->GetConstant(TTS_VIRTUAL)),
codegen_utils->GetConstant(0));
// slot->PRIVATE_tts_memtuple != NULL
llvm::Value* llvm_tuple_has_memtuple = irb->CreateICmpNE(
llvm_slot_PRIVATE_tts_memtuple,
codegen_utils->GetConstant((MemTuple) NULL));
// Fall back if tuple is virtual or memtuple is null
irb->CreateCondBr(
irb->CreateOr(llvm_tuple_is_virtual, llvm_tuple_has_memtuple),
fallback_block /*true*/, heap_tuple_check_block /*false*/);
// HeapTuple check block
// ---------------------
// We fall back if the given tuple is not a heaptuple.
irb->SetInsertPoint(heap_tuple_check_block);
// In _slot_getsomeattrs, check if: TupGetHeapTuple(slot) != NULL
llvm::Value* llvm_slot_PRIVATE_tts_heaptuple =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_heaptuple));
llvm::Value* llvm_tuple_has_heaptuple = irb->CreateICmpNE(
llvm_slot_PRIVATE_tts_heaptuple,
codegen_utils->GetConstant((HeapTuple) NULL));
irb->CreateCondBr(llvm_tuple_has_heaptuple,
main_block /*true*/,
fallback_block /*false*/);
// Main block
// ----------
// We generate code for slot_deform_tuple. Note that we do not need to check
// the type of the tuple, since previous check guarantees that the we use the
// enrolled slot, which includes a heap tuple.
irb->SetInsertPoint(main_block);
llvm::Value* llvm_heaptuple_t_data =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_slot_PRIVATE_tts_heaptuple,
&HeapTupleData::t_data));
llvm::Value* llvm_heaptuple_t_data_t_infomask =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_heaptuple_t_data, &HeapTupleHeaderData::t_infomask));
// Implementation for : {{{
// attno = HeapTupleHeaderGetNatts(tuple->t_data);
// attno = Min(attno, attnum);
llvm::Value* llvm_heaptuple_t_data_t_infomask2 =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_heaptuple_t_data,
&HeapTupleHeaderData::t_infomask2));
llvm::Value* llvm_attno_t0 =
irb->CreateZExt(
irb->CreateAnd(llvm_heaptuple_t_data_t_infomask2,
codegen_utils->GetConstant<int16>(HEAP_NATTS_MASK)),
codegen_utils->GetType<int>());
llvm::Value* llvm_attno =
irb->CreateSelect(
irb->CreateICmpSLT(llvm_attno_t0, llvm_max_attr),
llvm_attno_t0,
llvm_max_attr);
// }}}
// Retrieve slot's PRIVATE variables
llvm::Value* llvm_slot_PRIVATE_tts_isnull /* bool* */ =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_isnull));
llvm::Value* llvm_slot_PRIVATE_tts_values /* Datum* */ =
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_values));
llvm::Value* llvm_slot_PRIVATE_tts_nvalid_ptr /* int* */ =
codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_nvalid);
llvm::Value* llvm_heaptuple_t_data_t_hoff = irb->CreateLoad(
codegen_utils->GetPointerToMember(llvm_heaptuple_t_data,
&HeapTupleHeaderData::t_hoff));
// tup->t_bits
llvm::Value* llvm_heaptuple_t_data_t_bits =
codegen_utils->GetPointerToMember(
llvm_heaptuple_t_data,
&HeapTupleHeaderData::t_bits);
// Find the start of input data byte array
// same as tp in slot_deform_tuple (pointer to tuple data)
llvm::Value* llvm_tuple_data_ptr = irb->CreateInBoundsGEP(
llvm_heaptuple_t_data, {llvm_heaptuple_t_data_t_hoff});
int off = 0;
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
Form_pg_attribute* att = tupleDesc->attrs;
// For each attribute we use three blocks to i) check for null,
// ii) handle null case, and iii) handle not null case.
// Note that if an attribute cannot be null then we do not create
// the last two blocks.
llvm::BasicBlock* attribute_block = nullptr;
llvm::BasicBlock* is_null_block = nullptr;
llvm::BasicBlock* is_not_null_block = nullptr;
// points to the attribute_block of the next attribute
llvm::BasicBlock* next_attribute_block = nullptr;
// block of first attribute
attribute_block = codegen_utils->CreateBasicBlock(
"attribute_block_"+0, slot_getattr_func);
irb->CreateBr(attribute_block);
for (int attnum = 0; attnum < max_attr; ++attnum) {
Form_pg_attribute thisatt = att[attnum];
// If any thisatt is varlen
if (thisatt->attlen < 0) {
// We don't support variable length attributes.
return false;
}
// ith attribute's block
// ----------
// Check if attribute can be null. If yes, then create blocks
// to handle null and not null cases.
irb->SetInsertPoint(attribute_block);
// Create the block of (attnum+1)th attribute and jump to it after
// you finish with current attribute.
next_attribute_block = codegen_utils->CreateBasicBlock(
"attribute_block_" + std::to_string(attnum+1), slot_getattr_func);
llvm::Value* llvm_next_values_ptr =
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values,
{codegen_utils->GetConstant(attnum)});
// If attribute can be null, then create blocks to handle
// null and not null cases.
if (!thisatt->attnotnull) {
// Create blocks
is_null_block = codegen_utils->CreateBasicBlock(
"is_null_block_" + std::to_string(attnum), slot_getattr_func);
is_not_null_block = codegen_utils->CreateBasicBlock(
"is_not_null_block_" + std::to_string(attnum),
slot_getattr_func);
llvm::Value* llvm_attnum = codegen_utils->GetConstant(attnum);
// Check if attribute is null
// if (hasnulls && att_isnull(attnum, bp)) {{{
// att_isnull(attnum, bp): !((BITS)[(ATT) >> 3] & (1<<((ATT) & 0x07))) {{
// Expr_1: ((BITS)[(ATT) >> 3]
llvm::Value* llvm_expr_1 = irb->CreateLoad(irb->CreateGEP(
llvm_heaptuple_t_data_t_bits,
{codegen_utils->GetConstant(0),
irb->CreateAShr(llvm_attnum, codegen_utils->GetConstant(3))}));
// Expr_2: (1 << ((ATT) & 0x07))
llvm::Value* llvm_expr_2 = irb->CreateTrunc(
irb->CreateShl(codegen_utils->GetConstant(1),
irb->CreateAnd(llvm_attnum,
codegen_utils->GetConstant(0x07))),
codegen_utils->GetType<int8>());
// !(Exp_1 & Expr_2)
llvm::Value* llvm_att_isnull = irb->CreateNot(
irb->CreateTrunc(irb->CreateAnd(llvm_expr_1, llvm_expr_2),
codegen_utils->GetType<bool>()));
// }}
llvm::Value* llvm_hasnulls = irb->CreateTrunc(
irb->CreateAnd(llvm_heaptuple_t_data_t_infomask,
codegen_utils->GetConstant<uint16>(HEAP_HASNULL)),
codegen_utils->GetType<bool>());
// hasnulls && att_isnull(attnum, bp)
llvm::Value* llvm_is_null = irb->CreateAnd(
llvm_hasnulls, llvm_att_isnull);
irb->CreateCondBr(
llvm_is_null,
is_null_block, /* true */
is_not_null_block /* false */);
//}}} End of if (hasnulls && att_isnull(attnum, bp))
// Is null block
// ----------------
irb->SetInsertPoint(is_null_block);
// values[attnum] = (Datum) 0; {{{
irb->CreateStore(
codegen_utils->GetConstant<Datum>(0),
llvm_next_values_ptr);
// }}}
// isnull[attnum] = true; {{{
llvm::Value* llvm_isnull_ptr =
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull,
{llvm_attnum});
irb->CreateStore(
codegen_utils->GetConstant<bool>(true),
llvm_isnull_ptr);
// }}}
// Jump to next attribute
irb->CreateBr(next_attribute_block);
// Is not null block
// ----------------
irb->SetInsertPoint(is_not_null_block);
} // End of if ( !thisatt->attnotnull )
off = att_align_nominal(off, thisatt->attalign);
// values[attnum] = fetchatt(thisatt, tp + off) {{{
llvm::Value* llvm_next_t_data_ptr =
irb->CreateInBoundsGEP(llvm_tuple_data_ptr,
{codegen_utils->GetConstant(off)});
llvm::Value* llvm_colVal = nullptr;
if (thisatt->attbyval) {
// Load the value from the calculated input address.
switch (thisatt->attlen) {
case sizeof(char):
llvm_colVal = irb->CreateLoad(llvm_next_t_data_ptr);
break;
case sizeof(int16):
llvm_colVal = irb->CreateLoad(
codegen_utils->GetType<int16>(),
irb->CreateBitCast(llvm_next_t_data_ptr,
codegen_utils->GetType<int16*>()));
break;
case sizeof(int32):
llvm_colVal = irb->CreateLoad(
codegen_utils->GetType<int32>(),
irb->CreateBitCast(llvm_next_t_data_ptr,
codegen_utils->GetType<int32*>()));
break;
case sizeof(Datum):
llvm_colVal = irb->CreateLoad(
codegen_utils->GetType<int64>(),
irb->CreateBitCast(llvm_next_t_data_ptr,
codegen_utils->GetType<int64*>()));
break;
default:
// We do not support other data type length, passed by value
return false;
}
} else {
// We do not support attributes by reference
return false;
}
// store colVal into out_values[attnum]
irb->CreateStore(
irb->CreateZExt(llvm_colVal, codegen_utils->GetType<Datum>()),
llvm_next_values_ptr);
// }}} End of values[attnum] = fetchatt(thisatt, tp + off)
// isnull[attnum] = false; {{{
llvm::Value* llvm_next_isnull_ptr =
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull,
{codegen_utils->GetConstant(attnum)});
irb->CreateStore(
codegen_utils->GetConstant<bool>(false),
llvm_next_isnull_ptr);
// }}} End of isnull[attnum] = false;
// Jump to next attribute
irb->CreateBr(next_attribute_block);
off += thisatt->attlen;
// Process next attribute
attribute_block = next_attribute_block;
} // end for
// Next attribute block
// ----------------
// Note that we have iterated over all attributes already,
// so simply jump to final block.
irb->SetInsertPoint(next_attribute_block);
irb->CreateBr(final_block);
// Final block
// ----------------
irb->SetInsertPoint(final_block);
// slot->PRIVATE_tts_off = off;
llvm::Value* llvm_slot_PRIVATE_tts_off_ptr /* long* */ =
codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_off);
irb->CreateStore(
codegen_utils->GetConstant<long>(off), // NOLINT(runtime/int)
llvm_slot_PRIVATE_tts_off_ptr);
// slot->PRIVATE_tts_nvalid = attnum;
irb->CreateStore(llvm_max_attr, llvm_slot_PRIVATE_tts_nvalid_ptr);
// End of slot_deform_tuple
// _slot_getsomeattrs() after calling slot_deform_tuple {{{
// for (; attno < attnum; attno++)
// {
// slot->PRIVATE_tts_values[attno] = (Datum) 0;
// slot->PRIVATE_tts_isnull[attno] = true;
// }
// TODO(shardikar): Convert these to loops
llvm::Value* llvm_num_bytes = irb->CreateMul(
codegen_utils->GetConstant(sizeof(Datum)),
irb->CreateZExtOrTrunc(
irb->CreateSub(llvm_max_attr, llvm_attno),
codegen_utils->GetType<size_t>()));
codegen_utils->ir_builder()->CreateCall(
llvm_memset, {
irb->CreateBitCast(
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values,
{llvm_attno}),
codegen_utils->GetType<void*>()),
codegen_utils->GetConstant(0),
llvm_num_bytes});
codegen_utils->ir_builder()->CreateCall(
llvm_memset, {
irb->CreateBitCast(
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull,
{llvm_attno}),
codegen_utils->GetType<void*>()),
codegen_utils->GetConstant(static_cast<int>(true)),
llvm_num_bytes});
// TupSetVirtualTuple(slot);
irb->CreateStore(
irb->CreateOr(
irb->CreateLoad(llvm_slot_PRIVATE_tts_flags_ptr),
codegen_utils->GetConstant<int>(TTS_VIRTUAL)),
llvm_slot_PRIVATE_tts_flags_ptr);
// }}}
// slot_getattr() after calling _slot_getsomeattrs() {{{
//
// TODO (hardikar): We can optimize this further by getting rid of
// the follow computation and chanding the signature of this function
// *isnull = slot->PRIVATE_tts_isnull[attnum-1];
llvm::Value* llvm_isnull_from_slot_val =
irb->CreateLoad(irb->CreateInBoundsGEP(
llvm_slot_PRIVATE_tts_isnull,
{irb->CreateSub(llvm_attnum_arg, codegen_utils->GetConstant(1))}));
irb->CreateStore(llvm_isnull_from_slot_val, llvm_isnull_ptr_arg);
// return slot->PRIVATE_tts_values[attnum-1];
llvm::Value* llvm_value_from_slot_val =
irb->CreateLoad(irb->CreateInBoundsGEP(
llvm_slot_PRIVATE_tts_values,
{irb->CreateSub(llvm_attnum_arg, codegen_utils->GetConstant(1))}));
irb->CreateRet(llvm_value_from_slot_val);
// Fall back block
// ---------------
// Note: We collect error code information, based on the block from which we
// fall back, and log it for debugging purposes.
irb->SetInsertPoint(fallback_block);
llvm::PHINode* llvm_error = irb->CreatePHI(codegen_utils->GetType<int>(), 4);
llvm_error->addIncoming(codegen_utils->GetConstant(0),
slot_check_block);
llvm_error->addIncoming(codegen_utils->GetConstant(1),
tuple_type_check_block);
llvm_error->addIncoming(codegen_utils->GetConstant(2),
heap_tuple_check_block);
codegen_utils->CreateElog(
DEBUG1,
"Falling back to regular slot_getattr, reason = %d",
llvm_error);
codegen_utils->CreateFallback<SlotGetAttrFn>(
codegen_utils->GetOrRegisterExternalFunction(slot_getattr),
slot_getattr_func);
return true;
}
bool ExecVariableListCodegen::GenerateCodeInternal(
......
......@@ -26,8 +26,8 @@ extern "C" {
using gpcodegen::ExprTreeGenerator;
bool ExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree) {
assert(nullptr != expr_state &&
nullptr != expr_state->expr &&
......@@ -36,18 +36,18 @@ bool ExprTreeGenerator::VerifyAndCreateExprTree(
bool supported_expr_tree = false;
switch (nodeTag(expr_state->expr)) {
case T_OpExpr: {
supported_expr_tree = OpExprTreeGenerator::VerifyAndCreateExprTree(
expr_state, econtext, expr_tree);
break;
supported_expr_tree = OpExprTreeGenerator::VerifyAndCreateExprTree(
expr_state, gen_info, expr_tree);
break;
}
case T_Var: {
supported_expr_tree = VarExprTreeGenerator::VerifyAndCreateExprTree(
expr_state, econtext, expr_tree);
expr_state, gen_info, expr_tree);
break;
}
case T_Const: {
supported_expr_tree = ConstExprTreeGenerator::VerifyAndCreateExprTree(
expr_state, econtext, expr_tree);
expr_state, gen_info, expr_tree);
break;
}
default : {
......
......@@ -28,15 +28,13 @@ namespace gpcodegen {
class ConstExprTreeGenerator : public ExprTreeGenerator {
public:
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree);
bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) final;
protected:
......@@ -45,7 +43,7 @@ class ConstExprTreeGenerator : public ExprTreeGenerator {
*
* @param expr_state Expression state from epxression tree
**/
explicit ConstExprTreeGenerator(ExprState* expr_state);
explicit ConstExprTreeGenerator(const ExprState* expr_state);
};
/** @} */
......
......@@ -31,6 +31,8 @@ class ExecEvalExprCodegen: public BaseCodegen<ExecEvalExprFn> {
* @param ptr_to_chosen_func_ptr Reference to the function pointer that the
* caller will call.
* @param exprstate The ExprState to use for generating code.
* @param econtext The ExprContext to use for generating code.
* @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.
......@@ -39,7 +41,8 @@ class ExecEvalExprCodegen: public BaseCodegen<ExecEvalExprFn> {
explicit ExecEvalExprCodegen(ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
ExprState *exprstate,
ExprContext *econtext);
ExprContext *econtext,
TupleTableSlot* slot);
virtual ~ExecEvalExprCodegen() = default;
......@@ -67,6 +70,7 @@ class ExecEvalExprCodegen: public BaseCodegen<ExecEvalExprFn> {
private:
ExprState *exprstate_;
ExprContext *econtext_;
TupleTableSlot* slot_;
static constexpr char kExecEvalExprPrefix[] = "ExecEvalExpr";
......
......@@ -42,13 +42,7 @@ class ExecVariableListCodegen: public BaseCodegen<ExecVariableListFn> {
virtual ~ExecVariableListCodegen() = default;
static bool WrapGenerateSlotGetAttr(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot* slot,
int max_attr,
llvm::Function** out_func);
protected:
protected:
/**
* @brief Generate code for the code path ExecVariableList > slot_getattr >
* _slot_getsomeattrs > slot_deform_tuple.
......@@ -98,14 +92,6 @@ class ExecVariableListCodegen: public BaseCodegen<ExecVariableListFn> {
* @return true on successful generation.
**/
bool GenerateExecVariableList(gpcodegen::GpCodegenUtils* codegen_utils);
static bool GenerateSlotGetAttr(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot* slot,
int max_attr,
llvm::Function** out_func);
};
/** @} */
......
......@@ -19,6 +19,7 @@
#include <unordered_map>
#include "codegen/utils/gp_codegen_utils.h"
#include "codegen/codegen_wrapper.h"
#include "llvm/IR/Value.h"
......@@ -41,6 +42,51 @@ enum class ExprTreeNodeType {
kOperator = 2
};
/**
* @brief Object that holds the information needed for creating the ExprTree
* for the code generation of expressions in ExecQual, ExecEvalExpr etc.
*
* @note Members of this structures may be initialized at different stages (see
* ExecEvalExprCodegen::GenerateExecEvalExpr). Some are available immediately at
* the time of code generation, others need to be calculated by traversing the
* expression tree by the ExprTreeGenerator::VerifyAndCreateExprTree pass.
* However, all members must be initialized before the
* ExecEvalExprCodegen::GenerateCode pass when they are all required.
*
**/
struct ExprTreeGeneratorInfo {
// Members that are immediately available at operator init.
ExprContext* econtext;
// Convenience members for code generation
llvm::Function* llvm_main_func;
llvm::BasicBlock* llvm_error_block;
// Members that will be updated by the
// ExprTreeGenerator::VerifyAndCreateExprTree pass
// Keep track of the max_attr needed for the expression. Needed by
// the code generation logic for slot_getattr()
int16_t max_attr;
// Records the generated slot_getattr() if generation was successful; a
// pointer to the external function otherwise.
llvm::Function* llvm_slot_getattr_func;
ExprTreeGeneratorInfo(
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Function* llvm_slot_getattr_func,
int16_t max_attr) :
econtext(econtext),
llvm_main_func(llvm_main_func),
llvm_error_block(llvm_error_block),
max_attr(max_attr),
llvm_slot_getattr_func(llvm_slot_getattr_func) {
}
};
class ExprTreeGenerator {
public:
virtual ~ExprTreeGenerator() = default;
......@@ -50,39 +96,37 @@ class ExprTreeGenerator {
* instance of ExprTreeGenerator if supported.
*
* @param expr_state Expression state from expression tree.
* @param econtext Respective expression context.
* @param gen_info Information needed for generating the expression tree.
* @param expr_tree Hold the new instance of expression tree class.
*
* @return true when it can codegen otherwise it return false.
**/
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree);
/**
* @brief Generate the code for given expression.
*
* @param codegen_utils Utility to easy code generation.
* @param econtext Respective expression context.
* @param llvm_main_func Current function for which we are generating code
* @param gen_info Information needed for generating the expression
* tree.
* @param llvm_isnull_arg Set to true if current expr is null
* @param llvm_out_value Store the expression results
*
* @return true when it generated successfully otherwise it return false.
**/
virtual bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** value) = 0;
/**
* @return Expression state
**/
ExprState* expr_state() { return expr_state_; }
const ExprState* expr_state() { return expr_state_; }
protected:
/**
......@@ -91,12 +135,12 @@ class ExprTreeGenerator {
* @param expr_state Expression state
* @param node_type Type of the ExprTreeGenerator
**/
ExprTreeGenerator(ExprState* expr_state,
ExprTreeGenerator(const ExprState* expr_state,
ExprTreeNodeType node_type) :
expr_state_(expr_state) {}
private:
ExprState* expr_state_;
const ExprState* expr_state_;
DISALLOW_COPY_AND_ASSIGN(ExprTreeGenerator);
};
......
......@@ -41,15 +41,13 @@ class OpExprTreeGenerator : public ExprTreeGenerator {
static void InitializeSupportedFunction();
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree);
bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) final;
protected:
......@@ -60,7 +58,7 @@ class OpExprTreeGenerator : public ExprTreeGenerator {
* @param arguments Arguments to operator as list of ExprTreeGenerator
**/
OpExprTreeGenerator(
ExprState* expr_state,
const ExprState* expr_state,
std::vector<
std::unique_ptr<
ExprTreeGenerator>>&& arguments); // NOLINT(build/c++11)
......
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// slot_getattr_codegen.h
//
// @doc:
// Contains slot_getattr generator
//
//---------------------------------------------------------------------------
#ifndef GPCODEGEN_SLOT_GETATTR_CODEGEN_H_ // NOLINT(build/header_guard)
#define GPCODEGEN_SLOT_GETATTR_CODEGEN_H_
#include "codegen/codegen_wrapper.h"
#include "codegen/utils/gp_codegen_utils.h"
namespace gpcodegen {
/** \addtogroup gpcodegen
* @{
*/
class SlotGetAttrCodegen {
/**
* @brief Generate code for the codepath slot_getattr > _slot_getsomeattr >
* slot_deform_tuple
*
* @param codegen_utils
* @param function_name Name of the generated function
* @param slot Use the TupleDesc for this slot to generate
* @param max_attr Generate slot deformation upto this many attributes
* @param out_func Return the generated llvm::Function
*
* @note This is a wrapper around GenerateSlotGetAttrInternal that handles the
* case when generation fails, and cleans up a possible broken function by
* removing it from the module.
**/
public:
static bool GenerateSlotGetAttr(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot* slot,
int max_attr,
llvm::Function** out_func);
private:
/**
* @brief Generate code for the codepath slot_getattr > _slot_getsomeattr >
* slot_deform_tuple
*
* @param codegen_utils
* @param function_name Name of the generated function
* @param slot Use the TupleDesc for this slot to generate
* @param max_attr Generate slot deformation upto this many attributes
* @param out_func Return the generated llvm::Function
*
* @return true on success generation; false otherwise
*
* @note Generate code for code path slot_getattr > * _slot_getsomeattrs >
* slot_deform_tuple. slot_getattr() will eventually call slot_deform_tuple
* (through _slot_getsomeattrs), which fetches all yet unread attributes of
* the slot until the given attribute. Moreover, instead of looping over the
* target list one at a time, this approach uses slot_getattr only once, with
* the largest attribute index from the target list.
*
*
* This implementation does not support:
* (1) Variable length attributes
* (2) Attributes passed by reference
*
* If at execution time, we see any of the above types of attributes,
* we fall backs to the regular function.
**/
static bool GenerateSlotGetAttrInternal(
gpcodegen::GpCodegenUtils* codegen_utils,
const std::string& function_name,
TupleTableSlot* slot,
int max_attr,
llvm::Function** out_func);
};
/** @} */
} // namespace gpcodegen
#endif // GPCODEGEN_SLOT_GETATTR_CODEGEN_H_
......@@ -13,6 +13,7 @@
#define GPCODEGEN_VAR_EXPR_TREE_GENERATOR_H_
#include "codegen/expr_tree_generator.h"
#include "codegen/codegen_wrapper.h"
#include "llvm/IR/Value.h"
......@@ -28,15 +29,13 @@ namespace gpcodegen {
class VarExprTreeGenerator : public ExprTreeGenerator {
public:
static bool VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree);
bool GenerateCode(gpcodegen::GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) final;
protected:
/**
......@@ -44,7 +43,7 @@ class VarExprTreeGenerator : public ExprTreeGenerator {
*
* @param expr_state Expression state
**/
explicit VarExprTreeGenerator(ExprState* expr_state);
explicit VarExprTreeGenerator(const ExprState* expr_state);
};
/** @} */
......
......@@ -90,7 +90,7 @@ void OpExprTreeGenerator::InitializeSupportedFunction() {
}
OpExprTreeGenerator::OpExprTreeGenerator(
ExprState* expr_state,
const ExprState* expr_state,
std::vector<
std::unique_ptr<ExprTreeGenerator>>&& arguments) // NOLINT(build/c++11)
: ExprTreeGenerator(expr_state, ExprTreeNodeType::kOperator),
......@@ -98,8 +98,8 @@ OpExprTreeGenerator::OpExprTreeGenerator(
}
bool OpExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree) {
assert(nullptr != expr_state &&
nullptr != expr_state->expr &&
......@@ -115,7 +115,7 @@ bool OpExprTreeGenerator::VerifyAndCreateExprTree(
return false;
}
List *arguments = reinterpret_cast<FuncExprState*>(expr_state)->args;
List *arguments = reinterpret_cast<const FuncExprState*>(expr_state)->args;
assert(nullptr != arguments);
// In ExecEvalFuncArgs
assert(list_length(arguments) ==
......@@ -130,7 +130,7 @@ bool OpExprTreeGenerator::VerifyAndCreateExprTree(
assert(nullptr != argstate);
std::unique_ptr<ExprTreeGenerator> arg(nullptr);
supported_tree &= ExprTreeGenerator::VerifyAndCreateExprTree(argstate,
econtext,
gen_info,
&arg);
if (!supported_tree) {
break;
......@@ -147,10 +147,8 @@ bool OpExprTreeGenerator::VerifyAndCreateExprTree(
}
bool OpExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) {
assert(nullptr != llvm_out_value);
*llvm_out_value = nullptr;
......@@ -174,10 +172,8 @@ bool OpExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
for (auto& arg : arguments_) {
llvm::Value* llvm_arg = nullptr;
arg_generated &= arg->GenerateCode(codegen_utils,
econtext,
llvm_main_func,
llvm_error_block,
llvm_isnull_arg,
gen_info,
llvm_isnull_ptr,
&llvm_arg);
if (!arg_generated) {
return false;
......@@ -185,8 +181,8 @@ bool OpExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
llvm_arguments.push_back(llvm_arg);
}
return itr->second->GenerateCode(codegen_utils,
llvm_main_func,
llvm_error_block,
gen_info.llvm_main_func,
gen_info.llvm_error_block,
llvm_arguments,
llvm_out_value);
}
此差异已折叠。
......@@ -10,6 +10,8 @@
//
//---------------------------------------------------------------------------
#include <algorithm>
#include "codegen/expr_tree_generator.h"
#include "codegen/var_expr_tree_generator.h"
......@@ -26,26 +28,27 @@ using gpcodegen::ExprTreeGenerator;
using gpcodegen::GpCodegenUtils;
bool VarExprTreeGenerator::VerifyAndCreateExprTree(
ExprState* expr_state,
ExprContext* econtext,
const ExprState* expr_state,
ExprTreeGeneratorInfo* gen_info,
std::unique_ptr<ExprTreeGenerator>* expr_tree) {
assert(nullptr != expr_state &&
nullptr != expr_state->expr &&
T_Var == nodeTag(expr_state->expr) &&
nullptr != expr_tree);
nullptr != expr_tree &&
nullptr != gen_info);
expr_tree->reset(new VarExprTreeGenerator(expr_state));
gen_info->max_attr = std::max(gen_info->max_attr,
reinterpret_cast<Var*>(expr_state->expr)->varattno);
return true;
}
VarExprTreeGenerator::VarExprTreeGenerator(ExprState* expr_state) :
VarExprTreeGenerator::VarExprTreeGenerator(const ExprState* expr_state) :
ExprTreeGenerator(expr_state, ExprTreeNodeType::kVar) {
}
bool VarExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
ExprContext* econtext,
llvm::Function* llvm_main_func,
llvm::BasicBlock* llvm_error_block,
llvm::Value* llvm_isnull_arg,
const ExprTreeGeneratorInfo& gen_info,
llvm::Value* llvm_isnull_ptr,
llvm::Value** llvm_out_value) {
assert(nullptr != llvm_out_value);
*llvm_out_value = nullptr;
......@@ -60,15 +63,15 @@ bool VarExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
TupleTableSlot **ptr_to_slot_ptr = NULL;
switch (var_expr->varno) {
case INNER: /* get the tuple from the inner node */
ptr_to_slot_ptr = &econtext->ecxt_innertuple;
ptr_to_slot_ptr = &gen_info.econtext->ecxt_innertuple;
break;
case OUTER: /* get the tuple from the outer node */
ptr_to_slot_ptr = &econtext->ecxt_outertuple;
ptr_to_slot_ptr = &gen_info.econtext->ecxt_outertuple;
break;
default: /* get the tuple from the relation being scanned */
ptr_to_slot_ptr = &econtext->ecxt_scantuple;
ptr_to_slot_ptr = &gen_info.econtext->ecxt_scantuple;
break;
}
......@@ -79,15 +82,12 @@ bool VarExprTreeGenerator::GenerateCode(GpCodegenUtils* codegen_utils,
llvm::Value *llvm_variable_varattno = codegen_utils->
GetConstant<int32_t>(attnum);
// External functions
llvm::Function* llvm_slot_getattr =
codegen_utils->GetOrRegisterExternalFunction(slot_getattr);
assert(nullptr != gen_info.llvm_slot_getattr_func);
// retrieve variable
*llvm_out_value = irb->CreateCall(
llvm_slot_getattr, {
gen_info.llvm_slot_getattr_func, {
llvm_slot,
llvm_variable_varattno,
llvm_isnull_arg /* TODO: Fix isNull */ });
llvm_isnull_ptr /* TODO: Fix isNull */ });
return true;
}
......@@ -163,10 +163,10 @@ static void ExecCdbTraceNode(PlanState *node, bool entry, TupleTableSlot *result
int flags);
static void
EnrollQualList(PlanState* result);
EnrollQualList(PlanState* result, TupleTableSlot* slot);
static void
EnrollProjInfoTargetList(ProjectionInfo* ProjInfo);
EnrollProjInfoTargetList(ProjectionInfo* ProjInfo, TupleTableSlot* slot);
/*
* setSubplanSliceId
......@@ -346,10 +346,10 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
* Enroll targetlist & quals' expression evaluation functions
* in codegen_manager
*/
EnrollQualList(result);
EnrollQualList(result, ((ScanState*) result)->ss_ScanTupleSlot);
if (NULL !=result)
{
EnrollProjInfoTargetList(result->ps_ProjInfo);
EnrollProjInfoTargetList(result->ps_ProjInfo, ((ScanState*) result)->ss_ScanTupleSlot);
}
}
END_MEMORY_ACCOUNT();
......@@ -580,14 +580,14 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
* Enroll targetlist & quals' expression evaluation functions
* in codegen_manager
*/
EnrollQualList(result);
EnrollQualList(result, ((ScanState*) result)->ss_ScanTupleSlot);
if (NULL != result)
{
AggState* aggstate = (AggState*)result;
for (int aggno = 0; aggno < aggstate->numaggs; aggno++)
{
AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
EnrollProjInfoTargetList(peraggstate->evalproj);
EnrollProjInfoTargetList(peraggstate->evalproj, ((ScanState*) result)->ss_ScanTupleSlot);
}
}
}
......@@ -776,7 +776,7 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
* ----------------------------------------------------------------
*/
void
EnrollQualList(PlanState* result)
EnrollQualList(PlanState* result, TupleTableSlot* slot)
{
#ifdef USE_CODEGEN
if (NULL == result ||
......@@ -791,7 +791,9 @@ EnrollQualList(PlanState* result)
ExprState *exprstate = (ExprState*) lfirst(l);
enroll_ExecEvalExpr_codegen(exprstate->evalfunc,
&exprstate->evalfunc,
exprstate, result->ps_ExprContext);
exprstate,
result->ps_ExprContext,
slot);
}
#endif
......@@ -804,7 +806,7 @@ EnrollQualList(PlanState* result)
* ----------------------------------------------------------------
*/
void
EnrollProjInfoTargetList(ProjectionInfo* ProjInfo)
EnrollProjInfoTargetList(ProjectionInfo* ProjInfo, TupleTableSlot* slot)
{
#ifdef USE_CODEGEN
if (NULL == ProjInfo ||
......@@ -823,7 +825,8 @@ EnrollProjInfoTargetList(ProjectionInfo* ProjInfo)
enroll_ExecEvalExpr_codegen(gstate->arg->evalfunc,
&gstate->arg->evalfunc,
gstate->arg,
ProjInfo->pi_exprContext);
ProjInfo->pi_exprContext,
slot);
}
#endif
......
......@@ -155,7 +155,8 @@ void*
ExecEvalExprCodegenEnroll(ExecEvalExprFn regular_func_ptr,
ExecEvalExprFn* ptr_to_regular_func_ptr,
struct ExprState *exprstate,
struct ExprContext *econtext);
struct ExprContext *econtext,
struct TupleTableSlot* slot);
#ifdef __cplusplus
......@@ -217,9 +218,9 @@ ExecEvalExprCodegenEnroll(ExecEvalExprFn 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_ExecEvalExpr_codegen(regular_func, ptr_to_regular_func_ptr, exprstate, econtext) \
#define enroll_ExecEvalExpr_codegen(regular_func, ptr_to_regular_func_ptr, exprstate, econtext, slot) \
exprstate->ExecEvalExpr_code_generator = ExecEvalExprCodegenEnroll( \
(ExecEvalExprFn)regular_func, (ExecEvalExprFn*)ptr_to_regular_func_ptr, exprstate, econtext); \
(ExecEvalExprFn)regular_func, (ExecEvalExprFn*)ptr_to_regular_func_ptr, exprstate, econtext, slot); \
Assert(exprstate->evalfunc == regular_func); \
#endif //USE_CODEGEN
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册