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

Minor code quality fixes in src/backend/codegen

 * Address a number of cpplint errors
 * Fix files and variable naming for ExecVariableList codegen
 * Ignore Testing directory created by ctest
上级 86244b64
......@@ -43,3 +43,4 @@ CTestTestfile.cmake
cmake_install.cmake
install_manifest.txt
Makefile
Testing
......@@ -164,7 +164,7 @@ set(GPCODEGEN_SRC
codegen_interface.cc
codegen_manager.cc
codegen_wrapper.cc
ExecVariableList_codegen.cc
exec_variable_list_codegen.cc
)
# Integrate with GPDB build system.
......
......@@ -10,6 +10,10 @@
//
//---------------------------------------------------------------------------
extern "C" {
#include <utils/elog.h>
}
#include <cstdint>
#include <string>
......@@ -36,10 +40,6 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Casting.h"
extern "C" {
#include <utils/elog.h>
}
using gpcodegen::CodegenManager;
CodegenManager::CodegenManager(const std::string& module_name) {
......@@ -66,7 +66,6 @@ unsigned int CodegenManager::GenerateCode() {
}
unsigned int CodegenManager::PrepareGeneratedFunctions() {
unsigned int success_count = 0;
// If no generator registered, just return with success count as 0
......
......@@ -12,7 +12,7 @@
#include "codegen/codegen_wrapper.h"
#include "codegen/codegen_manager.h"
#include "codegen/ExecVariableList_codegen.h"
#include "codegen/exec_variable_list_codegen.h"
#include "codegen/utils/codegen_utils.h"
......@@ -111,7 +111,7 @@ void* ExecVariableListCodegenEnroll(
ExecVariableListFn regular_func_ptr,
ExecVariableListFn* ptr_to_chosen_func_ptr,
ProjectionInfo* proj_info,
TupleTableSlot* slot) {
TupleTableSlot* slot) {
ExecVariableListCodegen* generator = CodegenEnroll<ExecVariableListCodegen>(
regular_func_ptr, ptr_to_chosen_func_ptr, proj_info, slot);
return generator;
......
......@@ -9,11 +9,12 @@
// Contains different code generators
//
//---------------------------------------------------------------------------
#include "codegen/exec_variable_list_codegen.h"
#include <algorithm>
#include <cstdint>
#include <string>
#include "codegen/ExecVariableList_codegen.h"
#include "codegen/utils/clang_compiler.h"
#include "codegen/utils/utility.h"
#include "codegen/utils/instance_method_wrappers.h"
......@@ -49,7 +50,7 @@ constexpr char ExecVariableListCodegen::kExecVariableListPrefix[];
class ElogWrapper {
public:
ElogWrapper(gpcodegen::CodegenUtils* codegen_utils) :
explicit ElogWrapper(gpcodegen::CodegenUtils* codegen_utils) :
codegen_utils_(codegen_utils) {
SetupElog();
}
......@@ -62,15 +63,14 @@ class ElogWrapper {
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_->GetConstant(""), // Filename
codegen_utils_->GetConstant(0), // line number
codegen_utils_->GetConstant("") // function name
});
codegen_utils_->ir_builder()->CreateCall(
llvm_elog_finish_, {
......@@ -88,13 +88,14 @@ class ElogWrapper {
codegen_utils_->GetConstant(fmt),
args...);
}
private:
llvm::Function* llvm_elog_start_;
llvm::Function* llvm_elog_finish_;
gpcodegen::CodegenUtils* codegen_utils_;
void SetupElog(){
void SetupElog() {
assert(codegen_utils_ != nullptr);
llvm_elog_start_ = codegen_utils_->RegisterExternalFunction(elog_start);
assert(llvm_elog_start_ != nullptr);
......@@ -106,7 +107,6 @@ class ElogWrapper {
llvm_elog_start_ = nullptr;
llvm_elog_finish_ = nullptr;
}
};
ExecVariableListCodegen::ExecVariableListCodegen
......@@ -115,7 +115,9 @@ ExecVariableListCodegen::ExecVariableListCodegen
ExecVariableListFn* ptr_to_regular_func_ptr,
ProjectionInfo* proj_info,
TupleTableSlot* slot) :
BaseCodegen(kExecVariableListPrefix, regular_func_ptr, ptr_to_regular_func_ptr),
BaseCodegen(kExecVariableListPrefix,
regular_func_ptr,
ptr_to_regular_func_ptr),
proj_info_(proj_info),
slot_(slot) {
}
......@@ -127,18 +129,23 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
assert(NULL != codegen_utils);
ElogWrapper elogwrapper(codegen_utils);
static_assert(sizeof(Datum) == sizeof(int64), "sizeof(Datum) doesn't match sizeof(int64)");
static_assert(sizeof(Datum) == sizeof(int64),
"sizeof(Datum) doesn't match sizeof(int64)");
if ( NULL == proj_info_->pi_varSlotOffsets ) {
elog(DEBUG1, "Cannot codegen ExecVariableList because varSlotOffsets are null");
elog(DEBUG1,
"Cannot codegen ExecVariableList because varSlotOffsets are null");
return false;
}
// Only do codegen if all the elements in the target list are on the same tuple slot
// This is an assumption for scan nodes, but we fall back when joins are involved.
for (int i = list_length(proj_info_->pi_targetlist) - 1; i > 0; i--){
if (proj_info_->pi_varSlotOffsets[i] != proj_info_->pi_varSlotOffsets[i-1]){
elog(DEBUG1, "Cannot codegen ExecVariableList because multiple slots to deform.");
// Only do codegen if all the elements in the target list are on the same
// tuple slot This is an assumption for scan nodes, but we fall back when
// joins are involved.
for (int i = list_length(proj_info_->pi_targetlist) - 1; i > 0; i--) {
if (proj_info_->pi_varSlotOffsets[i] !=
proj_info_->pi_varSlotOffsets[i-1]) {
elog(DEBUG1,
"Cannot codegen ExecVariableList because multiple slots to deform.");
return false;
}
}
......@@ -149,42 +156,43 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
proj_info_->pi_varNumbers + list_length(proj_info_->pi_targetlist));
// System attribute
if(max_attr <= 0)
{
elog(DEBUG1, "Cannot generate code for ExecVariableList because max_attr is negative (i.e., system attribute).");
if (max_attr <= 0) {
elog(DEBUG1, "Cannot generate code for ExecVariableList"
"because max_attr is negative (i.e., system attribute).");
return false;
}else if (max_attr > slot_->tts_tupleDescriptor->natts) {
elog(DEBUG1, "Cannot generate code for ExecVariableList because max_attr is greater than natts.");
} else if (max_attr > slot_->tts_tupleDescriptor->natts) {
elog(DEBUG1, "Cannot generate code for ExecVariableList"
"because max_attr is greater than natts.");
return false;
}
// So looks like we're going to generate code
llvm::Function* ExecVariableList_func = CreateFunction<ExecVariableListFn>(
llvm::Function* exec_variable_list_func = CreateFunction<ExecVariableListFn>(
codegen_utils, GetUniqueFuncName());
auto irb = codegen_utils->ir_builder();
// BasicBlock of function entry.
llvm::BasicBlock* entry_block = codegen_utils->CreateBasicBlock(
"entry", ExecVariableList_func);
"entry", exec_variable_list_func);
// BasicBlock for checking correct slot
llvm::BasicBlock* slot_check_block = codegen_utils->CreateBasicBlock(
"slot_check", ExecVariableList_func);
"slot_check", exec_variable_list_func);
// BasicBlock for checking tuple type.
llvm::BasicBlock* tuple_type_check_block = codegen_utils->CreateBasicBlock(
"tuple_type_check", ExecVariableList_func);
"tuple_type_check", exec_variable_list_func);
// BasicBlock for heap tuple check.
llvm::BasicBlock* heap_tuple_check_block = codegen_utils->CreateBasicBlock(
"heap_tuple_check", ExecVariableList_func);
"heap_tuple_check", exec_variable_list_func);
// BasicBlock for main.
llvm::BasicBlock* main_block = codegen_utils->CreateBasicBlock(
"main", ExecVariableList_func);
"main", exec_variable_list_func);
// BasicBlock for final computations.
llvm::BasicBlock* final_block = codegen_utils->CreateBasicBlock(
"final", ExecVariableList_func);
"final", exec_variable_list_func);
// BasicBlock for fall back.
llvm::BasicBlock* fallback_block = codegen_utils->CreateBasicBlock(
"fallback", ExecVariableList_func);
"fallback", exec_variable_list_func);
// External functions
llvm::Function* llvm_memset = codegen_utils->RegisterExternalFunction(memset);
......@@ -194,9 +202,9 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
llvm::Value* llvm_slot = codegen_utils->GetConstant(slot_);
// Function arguments to ExecVariableList
llvm::Value* llvm_projInfo_arg = ArgumentByPosition(ExecVariableList_func, 0);
llvm::Value* llvm_values_arg = ArgumentByPosition(ExecVariableList_func, 1);
llvm::Value* llvm_isnull_arg = ArgumentByPosition(ExecVariableList_func, 2);
llvm::Value* llvm_projInfo_arg = ArgumentByPosition(exec_variable_list_func, 0);
llvm::Value* llvm_values_arg = ArgumentByPosition(exec_variable_list_func, 1);
llvm::Value* llvm_isnull_arg = ArgumentByPosition(exec_variable_list_func, 2);
// Entry block
// -----------
......@@ -228,8 +236,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
irb->CreateCondBr(
irb->CreateICmpEQ(llvm_slot, llvm_slot_arg),
tuple_type_check_block /* true */,
fallback_block /* false */
);
fallback_block /* false */);
// Tuple type check block
// ----------------------
......@@ -253,7 +260,8 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// slot->PRIVATE_tts_memtuple != NULL
llvm::Value* llvm_tuple_has_memtuple = irb->CreateICmpNE(
llvm_slot_PRIVATE_tts_memtuple, codegen_utils->GetConstant((MemTuple) NULL));
llvm_slot_PRIVATE_tts_memtuple,
codegen_utils->GetConstant((MemTuple) NULL));
// Fall back if tuple is virtual or memtuple is null
irb->CreateCondBr(
......@@ -278,19 +286,18 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// 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.
// 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
));
&HeapTupleData::t_data));
llvm::Value* llvm_heaptuple_t_data_t_infomask =
irb->CreateLoad( codegen_utils->GetPointerToMember(
irb->CreateLoad(codegen_utils->GetPointerToMember(
llvm_heaptuple_t_data, &HeapTupleHeaderData::t_infomask));
// Implementation for : {{{
......@@ -310,18 +317,17 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
irb->CreateSelect(
irb->CreateICmpSLT(llvm_attno_t0, llvm_max_attr),
llvm_attno_t0,
llvm_max_attr
);
llvm_max_attr);
// }}}
// Retrieve slot's PRIVATE variables
llvm::Value* llvm_slot_PRIVATE_tts_isnull /* bool* */=
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* */=
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* */=
llvm::Value* llvm_slot_PRIVATE_tts_nvalid_ptr /* int* */ =
codegen_utils->GetPointerToMember(
llvm_slot, &TupleTableSlot::PRIVATE_tts_nvalid);
......@@ -357,7 +363,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// block of first attribute
attribute_block = codegen_utils->CreateBasicBlock(
"attribute_block_"+0, ExecVariableList_func);
"attribute_block_"+0, exec_variable_list_func);
irb->CreateBr(attribute_block);
......@@ -379,7 +385,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// 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_"+(attnum+1), ExecVariableList_func);
"attribute_block_"+(attnum+1), exec_variable_list_func);
llvm::Value* llvm_next_values_ptr =
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values,
......@@ -390,9 +396,9 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
if (!thisatt->attnotnull) {
// Create blocks
is_null_block = codegen_utils->CreateBasicBlock(
"is_null_block_"+attnum, ExecVariableList_func);
"is_null_block_"+attnum, exec_variable_list_func);
is_not_null_block = codegen_utils->CreateBasicBlock(
"is_not_null_block_"+attnum, ExecVariableList_func);
"is_not_null_block_"+attnum, exec_variable_list_func);
llvm::Value* llvm_attnum = codegen_utils->GetConstant(attnum);
......@@ -400,7 +406,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// 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::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))}));
......@@ -458,8 +464,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// ----------------
irb->SetInsertPoint(is_not_null_block);
} // End of if (!thisatt->attnotnull)
} // End of if ( !thisatt->attnotnull )
off = att_align(off, thisatt->attalign);
......@@ -469,10 +474,9 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
{codegen_utils->GetConstant(off)});
llvm::Value* llvm_colVal = nullptr;
if( thisatt->attbyval) {
if (thisatt->attbyval) {
// Load the value from the calculated input address.
switch(thisatt->attlen)
{
switch (thisatt->attlen) {
case sizeof(char):
llvm_colVal = irb->CreateLoad(llvm_next_t_data_ptr);
break;
......@@ -525,7 +529,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
off += thisatt->attlen;
// Process next attribute
attribute_block = next_attribute_block;
} // end for
} // end for
// Next attribute block
// ----------------
......@@ -541,7 +545,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
irb->SetInsertPoint(final_block);
// slot->PRIVATE_tts_off = off;
llvm::Value* llvm_slot_PRIVATE_tts_off_ptr /* long* */=
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),
......@@ -559,7 +563,7 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// slot->PRIVATE_tts_isnull[attno] = true;
// }
// TODO: Convert these to loops
// TODO(shardikar): Convert these to loops
llvm::Value* llvm_num_bytes = irb->CreateMul(
codegen_utils->GetConstant(sizeof(Datum)),
irb->CreateZExtOrTrunc(
......@@ -568,7 +572,8 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
codegen_utils->ir_builder()->CreateCall(
llvm_memset, {
irb->CreateBitCast(
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values, {llvm_attno}),
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values,
{llvm_attno}),
codegen_utils->GetType<void*>()),
codegen_utils->GetConstant(0),
llvm_num_bytes});
......@@ -576,9 +581,10 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
codegen_utils->ir_builder()->CreateCall(
llvm_memset, {
irb->CreateBitCast(
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull, {llvm_attno}),
irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull,
{llvm_attno}),
codegen_utils->GetType<void*>()),
codegen_utils->GetConstant((int) true),
codegen_utils->GetConstant(static_cast<int>(true)),
llvm_num_bytes});
// TupSetVirtualTuple(slot);
......@@ -590,26 +596,32 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// }}}
// slot_getattr() after calling _slot_getsomeattrs() and remainder of ExecVariableList {{{
// slot_getattr() after calling _slot_getsomeattrs() and remainder of
// ExecVariableList {{{
//
// This code from ExecVariableList copies the contents of the isnull & values arrays
// in the slot to output variable from the function parameters to ExecVariableList
// This code from ExecVariableList copies the contents of the isnull & values
// arrays in the slot to output variable from the function parameters to
// ExecVariableList
int *varNumbers = proj_info_->pi_varNumbers;
for (int i = list_length(proj_info_->pi_targetlist) - 1; i >= 0; i--) {
// *isnull = slot->PRIVATE_tts_isnull[attnum-1];
llvm::Value* llvm_isnull_from_slot_val =
irb->CreateLoad(irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_isnull,
{codegen_utils->GetConstant(varNumbers[i] - 1)}));
irb->CreateLoad(irb->CreateInBoundsGEP(
llvm_slot_PRIVATE_tts_isnull,
{codegen_utils->GetConstant(varNumbers[i] - 1)}));
llvm::Value* llvm_isnull_ptr =
irb->CreateInBoundsGEP(llvm_isnull_arg, {codegen_utils->GetConstant(i)});
irb->CreateInBoundsGEP(llvm_isnull_arg,
{codegen_utils->GetConstant(i)});
irb->CreateStore(llvm_isnull_from_slot_val, llvm_isnull_ptr);
// values[i] = slot_getattr(varSlot, varNumber+1, &(isnull[i]));
llvm::Value* llvm_value_from_slot_val =
irb->CreateLoad(irb->CreateInBoundsGEP(llvm_slot_PRIVATE_tts_values,
{codegen_utils->GetConstant(varNumbers[i] - 1)}));
irb->CreateLoad(irb->CreateInBoundsGEP(
llvm_slot_PRIVATE_tts_values,
{codegen_utils->GetConstant(varNumbers[i] - 1)}));
llvm::Value* llvm_values_ptr =
irb->CreateInBoundsGEP(llvm_values_arg, {codegen_utils->GetConstant(i)});
irb->CreateInBoundsGEP(llvm_values_arg,
{codegen_utils->GetConstant(i)});
irb->CreateStore(llvm_value_from_slot_val, llvm_values_ptr);
}
......@@ -619,31 +631,37 @@ bool ExecVariableListCodegen::GenerateExecVariableList(
// Fall back block
// ---------------
// Note: We collect error code information, based on the block from which we fall back,
// and log it for debugging purposes.
// 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);
elogwrapper.CreateElog(DEBUG1, "Falling back to regular ExecVariableList, reason = %d", llvm_error);
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);
elogwrapper.CreateElog(
DEBUG1,
"Falling back to regular ExecVariableList, reason = %d",
llvm_error);
codegen_utils->CreateFallback<ExecVariableListFn>(
codegen_utils->RegisterExternalFunction(GetRegularFuncPointer()),
ExecVariableList_func);
exec_variable_list_func);
return true;
}
bool ExecVariableListCodegen::GenerateCodeInternal(CodegenUtils* codegen_utils) {
bool ExecVariableListCodegen::GenerateCodeInternal(
CodegenUtils* codegen_utils) {
bool isGenerated = GenerateExecVariableList(codegen_utils);
if (isGenerated) {
elog(DEBUG1, "ExecVariableList was generated successfully!");
return true;
}
else {
} else {
elog(DEBUG1, "ExecVariableList generation failed!");
return false;
}
......
......@@ -3,7 +3,7 @@
// Copyright (C) 2016 Pivotal Software, Inc.
//
// @filename:
// ExecVariableList_codegen.h
// exec_variable_list.h
//
// @doc:
// Headers for slot_deform_tuple codegen
......
......@@ -323,7 +323,7 @@ class CodegenUtils {
ReturnType (*external_function)(ArgumentTypes..., ...),
const std::string& name = "") {
return RegisterExternalFunction(
reinterpret_cast<ReturnType (*) (ArgumentTypes...)>(external_function),
reinterpret_cast<ReturnType (*)(ArgumentTypes...)>(external_function),
name,
true);
}
......@@ -745,11 +745,12 @@ class TypeMaker<ReferentType&> {
// corresponding llvm array types
template <typename ArrayElementType, size_t N>
class TypeMaker<ArrayElementType[N]> {
public:
static llvm::Type* Get(llvm::LLVMContext* context) {
llvm::Type* unit_type = codegen_utils_detail::TypeMaker<ArrayElementType>::Get(context);
return llvm::ArrayType::get(unit_type, N);
}
public:
static llvm::Type* Get(llvm::LLVMContext* context) {
llvm::Type* unit_type =
codegen_utils_detail::TypeMaker<ArrayElementType>::Get(context);
return llvm::ArrayType::get(unit_type, N);
}
};
} // namespace codegen_utils_detail
......@@ -828,7 +829,9 @@ llvm::FunctionType* CodegenUtils::GetFunctionType(const bool is_var_arg) {
codegen_utils_detail::TypeVectorBuilder<ArgumentTypes...>::AppendTypes(
this,
&argument_types);
return llvm::FunctionType::get(GetType<ReturnType>(), argument_types, is_var_arg);
return llvm::FunctionType::get(GetType<ReturnType>(),
argument_types,
is_var_arg);
}
// ----------------------------------------------------------------------------
......@@ -1088,7 +1091,6 @@ auto CodegenUtils::GetFunctionPointerImpl(const std::string& function_name)
template <typename FunctionType>
void CodegenUtils::CreateFallback(llvm::Function* regular_function,
llvm::Function* generated_function) {
assert(regular_function != nullptr);
assert(generated_function != nullptr);
......@@ -1100,7 +1102,9 @@ void CodegenUtils::CreateFallback(llvm::Function* regular_function,
llvm::CallInst* call_fallback_func = ir_builder()->CreateCall(
regular_function, forwarded_args);
/* Return the result of the call, or void if the function returns void. */
if (std::is_same<typename codegen_utils_detail::FunctionTypeUnpacker<FunctionType>::R, void>::value) {
if (std::is_same<typename
codegen_utils_detail::FunctionTypeUnpacker<FunctionType>::R,
void>::value) {
ir_builder()->CreateRetVoid();
} else {
ir_builder()->CreateRet(call_fallback_func);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册