Files
openGauss-server/src/include/codegen/gscodegen.h
2022-11-10 10:26:10 +08:00

820 lines
32 KiB
C++

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* gscodegen.h
*
*
*
* IDENTIFICATION
* src/include/codegen/gscodegen.h
*
* ---------------------------------------------------------------------------------------
*/
#ifndef GS_CODEGENH
#define GS_CODEGENH
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "pg_config.h"
#ifdef ENABLE_LLVM_COMPILE
#include "llvm/IR/Verifier.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsX86.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/circular_raw_ostream.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/raw_os_ostream.h"
#endif
#undef __STDC_LIMIT_MACROS
#include "c.h"
#include "nodes/pg_list.h"
#include "lib/stringinfo.h"
#include "utils/dfs_vector.h"
#include "postgres.h"
#include "knl/knl_variable.h"
#ifndef BITS
#define BITS 8
#endif
/* The max length of the IR Function's path */
#define MAX_LLVMIR_PATH 1024
/* position of elements that needed in vechashtbl */
#define pos_hashtbl_size 0
#define pos_hashtbl_data 1
/* position of elements that needed in VectorBatch class */
#define pos_batch_mrows 0
#define pos_batch_mcols 1
#define pos_batch_marr 4
/* position of elements that needed in ScalarVector class */
#define pos_scalvec_mrows 0
#define pos_scalvec_flag 3
#define pos_scalvec_vals 5
/* position of elements that needed in hashJoinTbl class */
#define pos_hjointbl_inbatch 12
#define pos_hjointbl_outbatch 13
#define pos_hjointbl_StateLog 23
#define pos_hjointbl_match 26
/* position of elements that needed in hashBasedOperator class */
#define pos_hBOper_htbl 1
#define pos_hBOper_hcxt 2
#define pos_hBOper_cacheLoc 4
#define pos_hBOper_cellCache 5
#define pos_hBOper_keyMatch 6
#define pos_hBOper_cols 18
#define pos_hBOper_mkey 19
#define pos_hBOper_keyIdx 20
/* position of elements that needed in HashAggRunner class */
#define pos_hAggR_hashVal 3
#define pos_hAggR_hSegTbl 12
#define pos_hAggR_hsegmax 14
#define pos_hAggR_hashSize 15
/* position of elements that needed in BaseAggRunner class */
#define pos_bAggR_keyIdxInCell 8
#define pos_bAggR_keySimple 11
#define pos_bAggR_Loc 18
#define pos_bAggR_econtext 22
/* position of elements that needed in ExprContext structure */
#define pos_ecxt_pertuple 5
#define pos_ecxt_scanbatch 17
#define pos_ecxt_innerbatch 18
#define pos_ecxt_outerbatch 19
/* position of elements that needed in hashCell structure */
#define pos_hcell_mval 1
/* position of elements that needed in hashVal structure */
#define pos_hval_val 0
#define pos_hval_flag 1
/* position of elements that needed in StringInfo structure */
#define pos_strinfo_data 0
#define pos_strinfo_len 1
/* position of elements that needed in SonicHashAgg structure */
#define pos_shashagg_ecxt 12
/* position of elements that needed in SonicHash structure */
#define pos_shash_data 1
#define pos_shash_sonichmemctl 14
#define pos_shash_loc 16
/* position of elements that needed in SonicHashMemoryControl structure */
#define pos_sonichmemctl_hcxt 8
/* position of elements that needed in SonicDatumArray structure */
#define pos_sdarray_cxt 1
#define pos_sdarray_atomsize 5
#define pos_sdarray_nbit 7
#define pos_sdarray_arr 8
/* position of elements that needed in atom structure */
#define pos_atom_data 0
#define pos_atom_nullflag 1
#ifdef ENABLE_LLVM_COMPILE
/* The whole intrinsic methods are listed in include/llvm/IR/IntrinsicEnums.inc */
#ifdef LLVM_MAJOR_VERSION
#if (LLVM_MAJOR_VERSION - LLVM_MAJOR_VERSION -1 == 1)
#error LLVM version was defined as empty.
#else
#if (LLVM_MAJOR_VERSION == 10)
const int llvm_prefetch = 217;
const int llvm_sadd_with_overflow = 229;
const int llvm_smul_with_overflow = 236;
const int llvm_ssub_with_overflow = 241;
#elif (LLVM_MAJOR_VERSION == 11)
const int llvm_prefetch = 225;
const int llvm_sadd_with_overflow = 239;
const int llvm_smul_with_overflow = 247;
const int llvm_ssub_with_overflow = 252;
#elif (LLVM_MAJOR_VERSION == 12)
const int llvm_prefetch = 225;
const int llvm_sadd_with_overflow = 240;
const int llvm_smul_with_overflow = 250;
const int llvm_ssub_with_overflow = 256;
#else
#error Un-supported LLVM version.
#endif
#endif
#else
#error LLVM version is not defined.
#endif
/*
* Declare related LLVM classes to avoid namespace pollution.
*/
namespace llvm {
class AllocaInst;
class BasicBlock;
class ConstantFolder;
class ExecutionEngine;
class Function;
using legacy::FunctionPassManager;
class LLVMContext;
class Module;
class NoFolder;
using legacy::PassManager;
class PointerType;
class StructType;
class TargetData;
class Type;
class Value;
class PassManagerBuilder;
template <typename T, typename I>
class IRBuilder;
class IRBuilderDefaultInserter;
} // namespace llvm
#endif
namespace dorado {
/*
* @Description : Check whether we have the right to init codegen inviroment.
* @return : Return true if we can initialize the codgen inviroment.
*/
bool canInitCodegenInvironment();
/*
* @Description : Check whether we can initialize the CodeGen Object.
* @return : Return true if we can initialize the GsCodeGen Obj.
*/
bool canInitThreadCodeGen();
#ifdef ENABLE_LLVM_COMPILE
class GsCodeGen : public BaseObject {
public:
void initialize();
/*
* @Brief : Initialize LLVM environment.
* @Description : This function must be called once per process before
* any llvm API called. LLVM needs to allocate data
* structures for multi-threading support and to enable
* dynamic linking of jitted code. if 'load_backend' is
* true, load the backend static object for llvm. This
* is needed when libbackend.so is loaded from java. llvm
* will be default only look in the current object and
* not be able to find the backend symbols.
* @in load_backend : Decide to load the backend static object or not.
* The default value is false.
* @return : Return true if succeed.
*/
static bool InitializeLlvm(bool load_backend = false);
/*
* @Description : Clear up the LLVM environment.
*/
static void cleanUpLlvm();
/*
* @Description : Load IR file and create a module.
* @in filename : Finename, a IR file path, like:\user\xxx\xxx.ir.
* @return : Return true if succeed..
*/
bool parseIRFile(StringInfo filename);
/*
* @Description : Find the location of IR file and load it.
*/
void loadIRFile();
/*
* Typedef builder in case we want to change the template arguments later
*/
typedef llvm::IRBuilder<> LlvmBuilder;
/*
* Utility struct that wraps a variable name and llvm type.
*/
struct NamedVariable {
char* name;
llvm::Type* type;
NamedVariable(char* name = "", llvm::Type* type = NULL)
{
this->name = name;
this->type = type;
}
};
/*
* define a Llvm_map which is similar to std::map
* in order to stroe the key-value pairs.
*/
template <class T_KEY, class T_VALUE>
class Llvm_Map : public BaseObject {
public:
T_KEY key;
T_VALUE value;
};
/*
* Abstraction over function prototypes. Contains helpers to build prototypes and
* generate IR for the types.
*/
class FnPrototype {
public:
/*
* @Description : Create a function prototype object
* @in gen : A LlvmCodeGen pointer.
* @in name : A specified function name.
* @in ret_type : The return value of the LLVM function.
* @Notes : It is a constructor.
*/
FnPrototype(GsCodeGen* gen, const char* name, llvm::Type* ret_type);
/*
* @Description : Add a argument for the function.
* @in var : var, a struct for function argument
*/
void addArgument(const NamedVariable& var)
{
functionArgs.push_back(var);
}
/*
* @Description : Create a LLVM function prototype.
* @in builder : The LLVM object, obtain many api for building LLVM function.
* @in params : return argumnets of LLVM function created.
* @return : return a created LLVM function pointer.
* @Notes : If params is non-null, this function will also
* return the arguments.
*/
llvm::Function* generatePrototype(LlvmBuilder* builder = NULL, llvm::Value** params = NULL);
private:
friend class GsCodeGen;
GsCodeGen* codeGen;
char* functionName; /* functions name */
llvm::Type* returnType;
Vector<NamedVariable> functionArgs; /* the functions parameters */
};
/*
* @Brief : Get a PointerType pointer.
* @Description : Get a LLVM Type pointer point to 'type'.
* @in type : a type struct of LLVM namespace.
* @return : return a PointerType pointer.
*/
llvm::PointerType* getPtrType(llvm::Type* type);
/*
* @Brief : Get a Void Type of LLVM namespace
* @return : return the void type in LLVM Data Type.
*/
llvm::Type* getVoidType();
/*
* @Description : Get a Type of LLVM namespace according to a type OID.
* @in type : A type OID in Gauss200 database.
* @return : return a LLVM Data Type .
*/
llvm::Type* getType(unsigned int type);
/*
* @Description : Get a PointerType pointer of LLVM namespace.
* @in type : A type OID in Gauss200 database.
* @return : return a PointerType Type .
*/
llvm::PointerType* getPtrType(unsigned int type);
/*
* @Description : Get a Type of LLVM namespace according to a type name.
* : This name should be the one recorded in LLVM module.
* @in name : name of the struct type/class type.
* @return : return a Type .
*/
llvm::Type* getType(const char* name);
/*
* @Description : Get a Type of LLVM namespace according to the 'name' type.
* @in type : A type name which can be recognized in Gauss200 database.
* @return : return a PointerType Type.
*/
llvm::PointerType* getPtrType(const char* name);
llvm::PointerType* getPtrPtrType(const char* name);
/*
* @Description : Create a llvm pointer value from 'ptr'. This is used
* to pass pointers between c-code and code-generated IR.
* @in type : Data type in LLVM assemble with respect to the actual
* c-type we want to codegen.
* @in ptr : Pointer point to the actual c-code data type.
* @return : value in 'type' type.
*/
llvm::Value* CastPtrToLlvmPtr(llvm::Type* type, const void* ptr);
/*
* @Description : Get reference to llvm context object.
* Each GsCodeGen has its own context to allow multiple
* threads to be calling into llvm at the same time.
* @return : Return reference to llvm context object.
*/
llvm::LLVMContext& context();
/*
* @Description : Get a current module.
* Module looks likes a container, which contains varibles,
* functions and types.
* @return : Return the current module in use.
*/
llvm::Module* module()
{
return m_currentModule;
}
/*
* @Description : Adds the IR function to m_machineCodeJitCompiled List
* of GsCodeGen Object. Make a map which is consisted of
* IR function and machine code function pointer. At this
* time, the machine function pointer is a NULL pointer.
* @in F : A IR function which will be as a key of map.
* @in result_fn_ptr : A machine code function pointer which will be as
* a value of map.
* @return : void
*/
void addFunctionToMCJit(llvm::Function* F, void** result_fn_ptr);
/*
* @Description : Adds the c-function calls to m_cfunctions_calls List in case of
* codegen_strategy is 'full'.
* each element in this List is a pair of funcName and funcOid.
* @return : void
*/
void recordCFunctionCalls(char* name);
/*
* @Description : check whether we have used C-function calls in codegen.
* it will check C-function call recording list,
* and return whether m_cfunction_calls is empty or not
* @return : bool
*/
bool hasCFunctionCalls();
/*
* @Description : Clearing the C-function calls list m_cfunction_calls.
* @return : void
*/
void clearCFunctionCalls();
/*
* @Description : Dumping out the C-function calls in m_cfunction_calls.
* @in plan_id : plan id as extra information to display.
* @in location : description string for Filter Codegen or Targetlist Codegen.
* @return :void
*/
void dumpCFunctionCalls(const char* location, int plan_id);
/**
* @Description : Verfies the generated IR function.
*
* @in function : The compiled function.
* @return : Return true if the funcion is valid, else retrun false. .
*/
bool verifyFunction(llvm::Function* function);
/**
* @Description :
* @in function : LLVM Function we need to check.
* @in plan_node_id : The string flag of this IR function in module .
* @return : Void
*/
void FinalizeFunction(llvm::Function* function, int plan_node_id = 0);
/*
* @Description : Returns the constant 'val' of 'type'. Since LLVM could only
* deal with arguments with the same type, we should make a
* difference between these types, even with the same value,
* say, int32 0 and int64 0.
* @in type : The corresponding type defined in PG we need to use in LLVM
* @in val : the natural value
* @return : the actual value defined in LLVM
*/
llvm::Value* getIntConstant(unsigned int type, int64_t val);
/*
* @Description : Loads an LLVM module. 'file' should be the local path to the
* LLVM bitcode (.ll) file. If 'file_size' is not NULL, it will
* be set to the size of 'file'. The caller is responsible for
* cleaning up module.
* @in codegen : A GsCodeGen object.
* @in file : file, a IR file to be loaded.
* @in module : The current module we need to load.
* @return : Return true if successed.
*/
static bool loadModule(GsCodeGen* codegen, char* file, llvm::Module** module);
/*
* @Description : Get a new llvm::ExecutionEngine with all the IR function
* be compiled.
* @in M : A llvm::Module pointer.
* @in enable_jitcache : If enable_jitcache is true, we need to use cache,
* else we do not need to use cache.
* @return : ExecutionEngien, which includs the module.
*/
llvm::ExecutionEngine* compileModule(llvm::Module* M, bool enable_jitcache);
/*
* @Description : A GsCodeGen constructor.
* Initialize some variables of LlvmCodegen object.
*/
GsCodeGen();
/*
* @Description : release some variables of LlvmCodegen object.
*/
virtual ~GsCodeGen();
/*
* @Description : Turns on/off optimization passes for current module.
* @in : enable value, used to decide optimize passes or not
* @out : flag to optimization or not.
*/
void enableOptimizations(bool enable);
/*
* @Description : Create a new module.
*/
bool createNewModule();
/*
* @Description : Create a new engine.
*/
llvm::ExecutionEngine* createNewEngine(llvm::Module* module);
/*
* @Description : Close the current module.
*/
void closeCurrentModule()
{
m_currentModule = NULL;
}
/*
* @Description : Get m_moduleCompiled.
*/
inline bool IsCompiled()
{
return m_moduleCompiled;
}
/*
* @Description : IR compile to machine code.
*/
void compileCurrentModule(bool enable_jitcache);
/*
* @Description : Release resource.
* The resource includes IR function lists and execution engine.
*/
void releaseResource();
/*
* @Description : Get the pointer to the current module.
* @return : Current module in use.
*/
llvm::Module* getCurrentModule()
{
return m_currentModule;
}
/* reset m_machineCodeJitCompiled */
void resetMCJittedFunc()
{
m_machineCodeJitCompiled = NIL;
}
public:
/* The module in use during this query process */
llvm::Module* m_currentModule;
private:
/* Initializes the jitter and execution engine. */
bool init();
/*
* Optimize the module, this includes pruning the module of any unused
* functions.
*/
void optimizeModule(llvm::Module* module);
/*
* check preload module
*/
bool CheckPreloadModule(llvm::Module* module);
/* Flag used to optimize the module or not */
bool m_optimizations_enabled;
/* Flag used to mask if we have loaded the ir file or not */
bool m_llvmIRLoaded;
/*
* If true, the module is corrupt and we cannot codegen this query.
* we could consider just removing the offending function and attempting to
* codegen the rest of the query. This requires more testing though to make sure
* that the error is recoverable.
*/
bool m_isCorrupt;
/* Flag used to mask if the GsCodeGen Obj has been initialized or not */
bool m_initialized;
llvm::LLVMContext* m_llvmContext;
/* The map of function to MCJIT compiled object */
List* m_machineCodeJitCompiled;
/* Execution Engine in use during this query process */
llvm::ExecutionEngine* m_currentEngine;
/*
* If true, the module has been compiled. It is not valid to add additional
* functions after this point.
*/
bool m_moduleCompiled;
MemoryContext m_codeGenContext;
/* Records the c-function calls in codegen IR fucntion of expression tree */
List* m_cfunction_calls;
};
#endif
/*
* Macros used to define the variables
*
* By following all these regulars, we could easily define
* consts
*/
#define DEFINE_CGVAR_INT1(name, val) llvm::Value* name = llvmCodeGen->getIntConstant(BITOID, val)
#define DEFINE_CGVAR_INT8(name, val) llvm::Value* name = llvmCodeGen->getIntConstant(CHAROID, val)
#define DEFINE_CGVAR_INT16(name, val) llvm::Value* name = llvmCodeGen->getIntConstant(INT2OID, val)
#define DEFINE_CGVAR_INT32(name, val) llvm::Value* name = llvmCodeGen->getIntConstant(INT4OID, val)
#define DEFINE_CGVAR_INT64(name, val) llvm::Value* name = llvmCodeGen->getIntConstant(INT8OID, val)
/*
* Macros used to define the data types
*/
#define DEFINE_CG_VOIDTYPE(name) llvm::Type* name = llvmCodeGen->getVoidType()
#define DEFINE_CG_TYPE(name, typoid) llvm::Type* name = llvmCodeGen->getType(typoid)
#define DEFINE_CG_PTRTYPE(name, typoid) llvm::Type* name = llvmCodeGen->getPtrType(typoid)
#define DEFINE_CG_PTRPTRTYPE(name, typoid) llvm::Type* name = llvmCodeGen->getPtrPtrType(typoid)
#define DEFINE_CG_NINTTYP(name, nbit) llvm::Type* name = llvm::IntegerType::getIntNTy(context, nbit)
#define DEFINE_CG_ARRTYPE(name, typoid, num) llvm::Type* name = llvm::ArrayType::get(typoid, num)
/*
* Define some operation
*/
#define DEFINE_BLOCK(name, insertbfpointer) \
llvm::BasicBlock* name = llvm::BasicBlock::Create(context, #name, insertbfpointer);
/*
* Define macros which help to catch and print the exception
* use SEGSEGVhandler to catch internal coredump occurred in LLVM.
*/
#define LLVM_TRY() \
bool llvm_oper_success = true; \
try
#define LLVM_CATCH(msg) \
catch (...) \
{ \
llvm_oper_success = false; \
} \
if (!llvm_oper_success) { \
ereport(ERROR, (errcode(ERRCODE_CODEGEN_ERROR), errmodule(MOD_LLVM), errmsg(msg))); \
}
} // namespace dorado
/*
* Series of llvm::crc32 function.
*
* Contains llvm_crc32_32_8, llvm_crc32_32_16, llvm_crc32_32_32, llvm_crc32_32_64.
*
* All functions have three input parameters. The first parameter is the result value,
* and the next two parameters are input values.
* Each funtion's parameters are indicated through the function name.
*
* For example, llvm_crc32_32_8 indicates the result value is 32bits,
* the first input parameter is 32bits, and the second input is 8bits.
*/
#ifdef __aarch64__ /* on ARM platform */
/* its function proto is: i32 @llvm.aarch64.crc32cb(i32 %cur, i32 %bits) */
#define llvm_crc32_32_8(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::aarch64_crc32cb; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::aarch64_crc32cb function!\n"))); \
} \
llvm::Value* next_ext = builder.CreateZExt(next, int32Type); \
res = builder.CreateCall(fn_crc, {current, next_ext}, "crc32_8"); \
} while (0)
/* its function proto is: i32 @llvm.aarch64.crc32ch(i32 %cur, i32 %bits) */
#define llvm_crc32_32_16(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::aarch64_crc32ch; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::aarch64_crc32ch function!\n"))); \
} \
llvm::Value* next_ext = builder.CreateZExt(next, int32Type); \
res = builder.CreateCall(fn_crc, {current, next_ext}, "crc32_16"); \
} while (0)
/* its function proto is: i32 @llvm.aarch64.crc32cw(i32 %cur, i32 %next) */
#define llvm_crc32_32_32(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::aarch64_crc32cw; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::aarch64_crc32cw function!\n"))); \
} \
res = builder.CreateCall(fn_crc, {current, next}, "crc32_32"); \
} while (0)
/* its function proto is: i32 @llvm.aarch64.crc32cx(i32 %cur, i64 %next) */
#define llvm_crc32_32_64(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::aarch64_crc32cx; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::aarch64_crc32cx function!\n"))); \
} \
res = builder.CreateCall(fn_crc, {current, next}, "crc32_64"); \
} while (0)
#else /* on X86 platform */
/* its function proto is: i32 @llvm.x86.sse42.crc32.32.8(i32 %a, i8 %b) */
#define llvm_crc32_32_8(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::x86_sse42_crc32_32_8; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::x86_sse42_crc32_32_8 function!\n"))); \
} \
res = builder.CreateCall(fn_crc, {current, next}, "crc32_8"); \
} while (0)
/* its function proto is: i32 @llvm.x86.sse42.crc32.32.16(i32 %a, i16 %b) */
#define llvm_crc32_32_16(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::x86_sse42_crc32_32_16; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::x86_sse42_crc32_32_16 function!\n"))); \
} \
res = builder.CreateCall(fn_crc, {current, next}, "crc32_16"); \
} while (0)
/* its function proto is: i32 @llvm.x86.sse42.crc32.32.32(i32 %a, i32 %b) */
#define llvm_crc32_32_32(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::x86_sse42_crc32_32_32; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::x86_sse42_crc32_32_32 function!\n"))); \
} \
res = builder.CreateCall(fn_crc, {current, next}, "crc32_32"); \
} while (0)
/*
* its function proto is: i64 @llvm.x86.sse42.crc32.64.64(i64 %a0, i64 %a1).
* x86_sse42_crc32_64_64 gets two 64bit inputs, and returns 64bits.
* So we have to convert its first input param and the result.
*/
#define llvm_crc32_32_64(res, current, next) \
do { \
llvm::Intrinsic::ID id = (unsigned)llvm::Intrinsic::x86_sse42_crc32_64_64; \
llvm::Function* fn_crc = llvm::Intrinsic::getDeclaration(mod, id); \
if (fn_crc == NULL) { \
ereport(ERROR, \
(errcode(ERRCODE_LOAD_INTRINSIC_FUNCTION_FAILED), \
errmodule(MOD_LLVM), \
errmsg("Failed to get function Intrinsic::x86_sse42_crc32_64_64 function!\n"))); \
} \
llvm::Value* current_ext = builder.CreateZExt(current, int64Type); \
res = builder.CreateCall(fn_crc, {current_ext, next}, "crc32_64"); \
res = builder.CreateTrunc(res, int32Type); \
} while (0)
#endif /* end of definition of series of llvm::crc32 function */
#endif