/* * 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 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 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 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