提交 22a35fcc 编写于 作者: S Shreedhar Hardikar

Call ereport when code generating float operators

This fixes a failures in ICG that printed line numbers because we used
elog earlier. Part of this commit is a refector that uses const char*
instead of llvm::Value* for passing the correct error message
上级 6bb6f51e
......@@ -22,6 +22,10 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Value.h"
extern "C" {
#include "utils/elog.h"
}
namespace gpcodegen {
/** \addtogroup gpcodegen
......@@ -96,12 +100,10 @@ class PGArithFuncGenerator {
static bool MulWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg());
return ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateMulOverflow<rtype>,
llvm_err_msg,
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg(),
pg_func_info,
llvm_out_value);
}
......@@ -123,12 +125,10 @@ class PGArithFuncGenerator {
static bool AddWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg());
return ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateAddOverflow<rtype>,
llvm_err_msg,
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg(),
pg_func_info,
llvm_out_value);
}
......@@ -293,19 +293,17 @@ class PGArithFuncGenerator {
static bool SubWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg());
return ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateSubOverflow<rtype>,
llvm_err_msg,
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg(),
pg_func_info,
llvm_out_value);
}
static bool ArithOpWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const char* error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
};
......@@ -341,19 +339,17 @@ class PGArithUnaryFuncGenerator {
static bool IncWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg());
return PGArithUnaryFuncGenerator<rtype, Arg>::ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateIncOverflow<rtype>,
llvm_err_msg,
ArithOpOverFlowErrorMsg<rtype>::OverFlowErrMsg(),
pg_func_info,
llvm_out_value);
}
static bool ArithOpWithOverflow(gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const char* error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value);
};
......@@ -366,7 +362,7 @@ class PGArithUnaryFuncGenerator {
* @param codegen_utils Utility for easy code generation.
* @param pg_func_info Details for pgfunc generation
* @param llvm_arith_output Result of the arithmetic operation
* @param llvm_error_msg Error message to use when overflow occurs
* @param error_msg Error message to use when overflow occurs
* @param llvm_out_value Store location for the result
*
* @return true if generation was successful otherwise return false
......@@ -378,11 +374,11 @@ static bool CreateOverflowCheckLogic(
gpcodegen::GpCodegenUtils* codegen_utils,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value* llvm_arith_output,
llvm::Value* llvm_error_msg,
const char* error_msg,
llvm::Value** llvm_out_value) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_arith_output);
assert(nullptr != llvm_error_msg);
assert(nullptr != error_msg);
llvm::IRBuilder<>* irb = codegen_utils->ir_builder();
......@@ -399,9 +395,10 @@ static bool CreateOverflowCheckLogic(
llvm_non_overflow_block);
irb->SetInsertPoint(llvm_overflow_block);
EXPAND_CREATE_ELOG(codegen_utils,
ERROR,
"%s", llvm_error_msg);
EXPAND_CREATE_EREPORT(codegen_utils,
ERROR,
ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE,
error_msg);
irb->CreateBr(pg_func_info.llvm_error_block);
irb->SetInsertPoint(llvm_non_overflow_block);
......@@ -413,13 +410,13 @@ template <typename rtype, typename Arg>
bool PGArithUnaryFuncGenerator<rtype, Arg>::ArithOpWithOverflow(
gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const char* error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_value);
assert(nullptr != codegen_mem_funcptr);
assert(nullptr != llvm_error_msg);
assert(nullptr != error_msg);
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::Value* casted_arg =
......@@ -431,7 +428,7 @@ bool PGArithUnaryFuncGenerator<rtype, Arg>::ArithOpWithOverflow(
return CreateOverflowCheckLogic<rtype>(codegen_utils,
pg_func_info,
llvm_arith_output,
llvm_error_msg,
error_msg,
llvm_out_value);
}
......@@ -440,13 +437,13 @@ template <typename rtype, typename Arg0, typename Arg1>
bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
gpcodegen::GpCodegenUtils* codegen_utils,
CGArithOpFunc codegen_mem_funcptr,
llvm::Value* llvm_error_msg,
const char* error_msg,
const PGFuncGeneratorInfo& pg_func_info,
llvm::Value** llvm_out_value) {
assert(nullptr != codegen_utils);
assert(nullptr != llvm_out_value);
assert(nullptr != codegen_mem_funcptr);
assert(nullptr != llvm_error_msg);
assert(nullptr != error_msg);
// Assumed caller checked vector size and nullptr for codegen_utils
llvm::Value* casted_arg0 =
......@@ -460,7 +457,7 @@ bool PGArithFuncGenerator<rtype, Arg0, Arg1>::ArithOpWithOverflow(
return CreateOverflowCheckLogic<rtype>(codegen_utils,
pg_func_info,
llvm_arith_output,
llvm_error_msg,
error_msg,
llvm_out_value);
}
......
......@@ -27,8 +27,12 @@ extern "C" {
#define EXPAND_CREATE_ELOG(codegen_utils, elevel, ...) \
codegen_utils->CreateElog(__FILE__, __LINE__, PG_FUNCNAME_MACRO, \
elevel, __VA_ARGS__)
elevel, ##__VA_ARGS__)
#define EXPAND_CREATE_EREPORT(codegen_utils, elevel, ecode, errmsg_fmt, ...) \
codegen_utils->CreateEreport(__FILE__, __LINE__, PG_FUNCNAME_MACRO, \
TEXTDOMAIN, elevel, ecode, errmsg_fmt, \
##__VA_ARGS__)
namespace gpcodegen {
......@@ -85,8 +89,7 @@ class GpCodegenUtils : public CodegenUtils {
llvm_elog_finish, {
llvm_elevel,
llvm_fmt,
args...
});
args... });
}
/*
......@@ -118,6 +121,138 @@ class GpCodegenUtils : public CodegenUtils {
GetConstant(fmt), args...);
}
/*
* @brief Create LLVM instructions to implement ereport; but only for
* ereport calls of the form: ereport(elevel, (errcode(code), errmsg(fmt, args...)).
*
* The reason for support only this form is because the ereport() mechanism is
* very flexible because of overloaded C macros - so much so that it is tricky
* to implement using the LLVM API. For example, it may appear from the above
* code that errcode and errmsg are called before any errstart or errfinish.
* However because of the way the macro is implemented, errcode and errmsg are
* called *after* errstart and only if errstart returns true
*
* @note This function calls the following external functions: errstart, errcode, errmsg
* and errfinish.
*
* @param file_name name of the file from which CreateEreport is called
* @param lineno number of the line in the file from which CreateEreport is called
* @param func_name name of the function that calls CreateEreport
* @param domain llvm::Value pointer to message domain of the report
* @param elevel llvm::Value pointer to integer representing the error level
* @param ecode llvm::Value pointer to error code passed to a call to
* @param errmsg_fmt llvm::Value pointer to format string
* @tparam args llvm::Value pointers to arguments to elog()
*/
template<typename... V>
void CreateEreport(
const char* file_name,
int lineno,
const char* func_name,
const char* domain,
int elevel,
int ecode,
const char* errmsg_fmt,
const V ... args ) {
CreateEreport(file_name,
lineno,
func_name,
GetConstant(domain),
GetConstant(elevel),
GetConstant(ecode),
GetConstant(errmsg_fmt));
}
/*
* @brief Create LLVM instructions to implements ereport; but only for
* ereport calls of the form: ereport(elevel, (errcode(code), errmsg(fmt, args...)).
*
* @param file_name name of the file from which CreateEreport is called
* @param lineno number of the line in the file from which CreateEreport is called
* @param func_name name of the function that calls CreateEreport
* @param domain message domain of the report
* @param elevel Integer representing the error level
* @param ecode error code passed to a call to
* @param errmsg_fmt Format string
* @tparam args llvm::Value pointers to arguments to elog()
*/
template<typename... V>
void CreateEreport(
const char* file_name,
int lineno,
const char* func_name,
llvm::Value* domain,
llvm::Value* elevel,
llvm::Value* ecode,
llvm::Value* errmsg_fmt,
const V ... args ) {
// Make sure the external functions required are available
llvm::Function* llvm_errstart =
GetOrRegisterExternalFunction(errstart, "errstart");
llvm::Function* llvm_errcode =
GetOrRegisterExternalFunction(errcode, "errcode");
llvm::Function* llvm_errmsg =
GetOrRegisterExternalFunction(errmsg, "errmsg");
llvm::Function* llvm_errfinish =
GetOrRegisterExternalFunction(errfinish, "errfinish");
auto irb = ir_builder();
// Retrive the current function to create new blocks
llvm::Function* current_function = irb->GetInsertBlock()->getParent();
// Case when errstart returns true
llvm::BasicBlock* errfinish_block =
CreateBasicBlock("errfinish", current_function);
// Case when errstart returns false
llvm::BasicBlock* rest_ereport_block =
CreateBasicBlock("rest_ereport", current_function);
// Case when elevel >= ERROR
llvm::BasicBlock* abort_block =
CreateBasicBlock("abort", current_function);
// Done with all cases
llvm::BasicBlock* end_ereport_block =
CreateBasicBlock("end_ereport", current_function);
// if (errstart(...)) errfinish(...) {{{
llvm::Value* llvm_ret = irb->CreateCall(
llvm_errstart, {
elevel,
GetConstant(file_name),
GetConstant(lineno),
GetConstant(func_name),
domain
});
irb->CreateCondBr(llvm_ret,
errfinish_block /* true */,
rest_ereport_block /* false */);
irb->SetInsertPoint(errfinish_block);
irb->CreateCall(llvm_errfinish, {
irb->CreateCall(llvm_errcode, {ecode}),
irb->CreateCall(llvm_errmsg, {errmsg_fmt, args...}) });
irb->CreateBr(rest_ereport_block);
// }}}
// if (elevel >= ERROR) abort() {{{
irb->SetInsertPoint(rest_ereport_block);
irb->CreateCondBr(irb->CreateICmpSGE(elevel, GetConstant(ERROR)),
abort_block /* true */,
end_ereport_block /* false */);
irb->SetInsertPoint(abort_block);
irb->CreateCall(GetOrRegisterExternalFunction(abort, "abort"));
irb->CreateBr(end_ereport_block);
// }}}
// Set up for adding instructions past this point
irb->SetInsertPoint(end_ereport_block);
}
/**
* @brief Create a Cast instruction to convert given llvm::Value of Datum type
* to given Cpp type
......@@ -154,7 +289,6 @@ class GpCodegenUtils : public CodegenUtils {
// Get dest type as integer type with same size
llvm::Type* llvm_dest_as_int_type = llvm::IntegerType::get(*context(),
dest_size);
llvm::Value* llvm_casted_value = value;
if (dest_size < src_size) {
......
......@@ -73,8 +73,6 @@ llvm::Value* PGDateFuncGenerator::GenerateDate2Timestamp(
GetConstant<int64_t>(USECS_PER_DAY);
llvm::Value* llvm_out_value = nullptr;
llvm::Value* llvm_err_msg = codegen_utils->GetConstant(
"date out of range for timestamp");
PGFuncGeneratorInfo pg_timestamp_func_info(
pg_func_info.llvm_main_func,
pg_func_info.llvm_error_block,
......@@ -84,7 +82,7 @@ llvm::Value* PGDateFuncGenerator::GenerateDate2Timestamp(
PGArithFuncGenerator<int64_t, int32_t, int64_t>::ArithOpWithOverflow(
codegen_utils,
&gpcodegen::GpCodegenUtils::CreateMulOverflow<int64_t>,
llvm_err_msg,
"date out of range for timestamp",
pg_timestamp_func_info,
&llvm_out_value);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册