| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * llvmjit.c |
| 4 | * Core part of the LLVM JIT provider. |
| 5 | * |
| 6 | * Copyright (c) 2016-2019, PostgreSQL Global Development Group |
| 7 | * |
| 8 | * IDENTIFICATION |
| 9 | * src/backend/jit/llvm/llvmjit.c |
| 10 | * |
| 11 | *------------------------------------------------------------------------- |
| 12 | */ |
| 13 | |
| 14 | #include "postgres.h" |
| 15 | |
| 16 | #include "jit/llvmjit.h" |
| 17 | #include "jit/llvmjit_emit.h" |
| 18 | |
| 19 | #include "miscadmin.h" |
| 20 | |
| 21 | #include "utils/memutils.h" |
| 22 | #include "utils/resowner_private.h" |
| 23 | #include "portability/instr_time.h" |
| 24 | #include "storage/ipc.h" |
| 25 | |
| 26 | |
| 27 | #include <llvm-c/Analysis.h> |
| 28 | #include <llvm-c/BitReader.h> |
| 29 | #include <llvm-c/BitWriter.h> |
| 30 | #include <llvm-c/Core.h> |
| 31 | #include <llvm-c/ExecutionEngine.h> |
| 32 | #include <llvm-c/OrcBindings.h> |
| 33 | #include <llvm-c/Support.h> |
| 34 | #include <llvm-c/Target.h> |
| 35 | #include <llvm-c/Transforms/IPO.h> |
| 36 | #include <llvm-c/Transforms/PassManagerBuilder.h> |
| 37 | #include <llvm-c/Transforms/Scalar.h> |
| 38 | #if LLVM_VERSION_MAJOR > 6 |
| 39 | #include <llvm-c/Transforms/Utils.h> |
| 40 | #endif |
| 41 | |
| 42 | |
| 43 | /* Handle of a module emitted via ORC JIT */ |
| 44 | typedef struct LLVMJitHandle |
| 45 | { |
| 46 | LLVMOrcJITStackRef stack; |
| 47 | LLVMOrcModuleHandle orc_handle; |
| 48 | } LLVMJitHandle; |
| 49 | |
| 50 | |
| 51 | /* types & functions commonly needed for JITing */ |
| 52 | LLVMTypeRef TypeSizeT; |
| 53 | LLVMTypeRef TypeParamBool; |
| 54 | LLVMTypeRef TypeStorageBool; |
| 55 | LLVMTypeRef TypePGFunction; |
| 56 | LLVMTypeRef StructNullableDatum; |
| 57 | LLVMTypeRef StructHeapTupleFieldsField3; |
| 58 | LLVMTypeRef StructHeapTupleFields; |
| 59 | LLVMTypeRef ; |
| 60 | LLVMTypeRef StructHeapTupleDataChoice; |
| 61 | LLVMTypeRef StructHeapTupleData; |
| 62 | LLVMTypeRef StructMinimalTupleData; |
| 63 | LLVMTypeRef StructItemPointerData; |
| 64 | LLVMTypeRef StructBlockId; |
| 65 | LLVMTypeRef StructFormPgAttribute; |
| 66 | LLVMTypeRef StructTupleConstr; |
| 67 | LLVMTypeRef StructTupleDescData; |
| 68 | LLVMTypeRef StructTupleTableSlot; |
| 69 | LLVMTypeRef StructHeapTupleTableSlot; |
| 70 | LLVMTypeRef StructMinimalTupleTableSlot; |
| 71 | LLVMTypeRef StructMemoryContextData; |
| 72 | LLVMTypeRef StructPGFinfoRecord; |
| 73 | LLVMTypeRef StructFmgrInfo; |
| 74 | LLVMTypeRef StructFunctionCallInfoData; |
| 75 | LLVMTypeRef StructExprContext; |
| 76 | LLVMTypeRef StructExprEvalStep; |
| 77 | LLVMTypeRef StructExprState; |
| 78 | LLVMTypeRef StructAggState; |
| 79 | LLVMTypeRef StructAggStatePerGroupData; |
| 80 | LLVMTypeRef StructAggStatePerTransData; |
| 81 | |
| 82 | LLVMValueRef AttributeTemplate; |
| 83 | LLVMValueRef FuncStrlen; |
| 84 | LLVMValueRef FuncVarsizeAny; |
| 85 | LLVMValueRef FuncSlotGetsomeattrsInt; |
| 86 | LLVMValueRef FuncSlotGetmissingattrs; |
| 87 | LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal; |
| 88 | LLVMValueRef FuncExecEvalSubscriptingRef; |
| 89 | LLVMValueRef FuncExecEvalSysVar; |
| 90 | LLVMValueRef FuncExecAggTransReparent; |
| 91 | LLVMValueRef FuncExecAggInitGroup; |
| 92 | |
| 93 | |
| 94 | static bool llvm_session_initialized = false; |
| 95 | static size_t llvm_generation = 0; |
| 96 | static const char *llvm_triple = NULL; |
| 97 | static const char *llvm_layout = NULL; |
| 98 | |
| 99 | |
| 100 | static LLVMTargetMachineRef llvm_opt0_targetmachine; |
| 101 | static LLVMTargetMachineRef llvm_opt3_targetmachine; |
| 102 | |
| 103 | static LLVMTargetRef llvm_targetref; |
| 104 | static LLVMOrcJITStackRef llvm_opt0_orc; |
| 105 | static LLVMOrcJITStackRef llvm_opt3_orc; |
| 106 | |
| 107 | |
| 108 | static void llvm_release_context(JitContext *context); |
| 109 | static void llvm_session_initialize(void); |
| 110 | static void llvm_shutdown(int code, Datum arg); |
| 111 | static void llvm_compile_module(LLVMJitContext *context); |
| 112 | static void llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module); |
| 113 | |
| 114 | static void llvm_create_types(void); |
| 115 | static uint64_t llvm_resolve_symbol(const char *name, void *ctx); |
| 116 | |
| 117 | |
| 118 | PG_MODULE_MAGIC; |
| 119 | |
| 120 | |
| 121 | /* |
| 122 | * Initialize LLVM JIT provider. |
| 123 | */ |
| 124 | void |
| 125 | _PG_jit_provider_init(JitProviderCallbacks *cb) |
| 126 | { |
| 127 | cb->reset_after_error = llvm_reset_after_error; |
| 128 | cb->release_context = llvm_release_context; |
| 129 | cb->compile_expr = llvm_compile_expr; |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | * Create a context for JITing work. |
| 134 | * |
| 135 | * The context, including subsidiary resources, will be cleaned up either when |
| 136 | * the context is explicitly released, or when the lifetime of |
| 137 | * CurrentResourceOwner ends (usually the end of the current [sub]xact). |
| 138 | */ |
| 139 | LLVMJitContext * |
| 140 | llvm_create_context(int jitFlags) |
| 141 | { |
| 142 | LLVMJitContext *context; |
| 143 | |
| 144 | llvm_assert_in_fatal_section(); |
| 145 | |
| 146 | llvm_session_initialize(); |
| 147 | |
| 148 | ResourceOwnerEnlargeJIT(CurrentResourceOwner); |
| 149 | |
| 150 | context = MemoryContextAllocZero(TopMemoryContext, |
| 151 | sizeof(LLVMJitContext)); |
| 152 | context->base.flags = jitFlags; |
| 153 | |
| 154 | /* ensure cleanup */ |
| 155 | context->base.resowner = CurrentResourceOwner; |
| 156 | ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(context)); |
| 157 | |
| 158 | return context; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | * Release resources required by one llvm context. |
| 163 | */ |
| 164 | static void |
| 165 | llvm_release_context(JitContext *context) |
| 166 | { |
| 167 | LLVMJitContext *llvm_context = (LLVMJitContext *) context; |
| 168 | |
| 169 | llvm_enter_fatal_on_oom(); |
| 170 | |
| 171 | /* |
| 172 | * When this backend is exiting, don't clean up LLVM. As an error might |
| 173 | * have occurred from within LLVM, we do not want to risk reentering. All |
| 174 | * resource cleanup is going to happen through process exit. |
| 175 | */ |
| 176 | if (!proc_exit_inprogress) |
| 177 | { |
| 178 | if (llvm_context->module) |
| 179 | { |
| 180 | LLVMDisposeModule(llvm_context->module); |
| 181 | llvm_context->module = NULL; |
| 182 | } |
| 183 | |
| 184 | while (llvm_context->handles != NIL) |
| 185 | { |
| 186 | LLVMJitHandle *jit_handle; |
| 187 | |
| 188 | jit_handle = (LLVMJitHandle *) linitial(llvm_context->handles); |
| 189 | llvm_context->handles = list_delete_first(llvm_context->handles); |
| 190 | |
| 191 | LLVMOrcRemoveModule(jit_handle->stack, jit_handle->orc_handle); |
| 192 | pfree(jit_handle); |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | /* |
| 198 | * Return module which may be modified, e.g. by creating new functions. |
| 199 | */ |
| 200 | LLVMModuleRef |
| 201 | llvm_mutable_module(LLVMJitContext *context) |
| 202 | { |
| 203 | llvm_assert_in_fatal_section(); |
| 204 | |
| 205 | /* |
| 206 | * If there's no in-progress module, create a new one. |
| 207 | */ |
| 208 | if (!context->module) |
| 209 | { |
| 210 | context->compiled = false; |
| 211 | context->module_generation = llvm_generation++; |
| 212 | context->module = LLVMModuleCreateWithName("pg" ); |
| 213 | LLVMSetTarget(context->module, llvm_triple); |
| 214 | LLVMSetDataLayout(context->module, llvm_layout); |
| 215 | } |
| 216 | |
| 217 | return context->module; |
| 218 | } |
| 219 | |
| 220 | /* |
| 221 | * Expand function name to be non-conflicting. This should be used by code |
| 222 | * generating code, when adding new externally visible function definitions to |
| 223 | * a Module. |
| 224 | */ |
| 225 | char * |
| 226 | llvm_expand_funcname(struct LLVMJitContext *context, const char *basename) |
| 227 | { |
| 228 | Assert(context->module != NULL); |
| 229 | |
| 230 | context->base.instr.created_functions++; |
| 231 | |
| 232 | /* |
| 233 | * Previously we used dots to separate, but turns out some tools, e.g. |
| 234 | * GDB, don't like that and truncate name. |
| 235 | */ |
| 236 | return psprintf("%s_%zu_%d" , |
| 237 | basename, |
| 238 | context->module_generation, |
| 239 | context->counter++); |
| 240 | } |
| 241 | |
| 242 | /* |
| 243 | * Return pointer to function funcname, which has to exist. If there's pending |
| 244 | * code to be optimized and emitted, do so first. |
| 245 | */ |
| 246 | void * |
| 247 | llvm_get_function(LLVMJitContext *context, const char *funcname) |
| 248 | { |
| 249 | LLVMOrcTargetAddress addr = 0; |
| 250 | #if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN |
| 251 | ListCell *lc; |
| 252 | #endif |
| 253 | |
| 254 | llvm_assert_in_fatal_section(); |
| 255 | |
| 256 | /* |
| 257 | * If there is a pending / not emitted module, compile and emit now. |
| 258 | * Otherwise we might not find the [correct] function. |
| 259 | */ |
| 260 | if (!context->compiled) |
| 261 | { |
| 262 | llvm_compile_module(context); |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | * ORC's symbol table is of *unmangled* symbols. Therefore we don't need |
| 267 | * to mangle here. |
| 268 | */ |
| 269 | |
| 270 | #if defined(HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN) && HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN |
| 271 | foreach(lc, context->handles) |
| 272 | { |
| 273 | LLVMJitHandle *handle = (LLVMJitHandle *) lfirst(lc); |
| 274 | |
| 275 | addr = 0; |
| 276 | if (LLVMOrcGetSymbolAddressIn(handle->stack, &addr, handle->orc_handle, funcname)) |
| 277 | elog(ERROR, "failed to look up symbol \"%s\"" , funcname); |
| 278 | if (addr) |
| 279 | return (void *) (uintptr_t) addr; |
| 280 | } |
| 281 | |
| 282 | #else |
| 283 | |
| 284 | #if LLVM_VERSION_MAJOR < 5 |
| 285 | if ((addr = LLVMOrcGetSymbolAddress(llvm_opt0_orc, funcname))) |
| 286 | return (void *) (uintptr_t) addr; |
| 287 | if ((addr = LLVMOrcGetSymbolAddress(llvm_opt3_orc, funcname))) |
| 288 | return (void *) (uintptr_t) addr; |
| 289 | #else |
| 290 | if (LLVMOrcGetSymbolAddress(llvm_opt0_orc, &addr, funcname)) |
| 291 | elog(ERROR, "failed to look up symbol \"%s\"" , funcname); |
| 292 | if (addr) |
| 293 | return (void *) (uintptr_t) addr; |
| 294 | if (LLVMOrcGetSymbolAddress(llvm_opt3_orc, &addr, funcname)) |
| 295 | elog(ERROR, "failed to look up symbol \"%s\"" , funcname); |
| 296 | if (addr) |
| 297 | return (void *) (uintptr_t) addr; |
| 298 | #endif /* LLVM_VERSION_MAJOR */ |
| 299 | |
| 300 | #endif /* HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN */ |
| 301 | |
| 302 | elog(ERROR, "failed to JIT: %s" , funcname); |
| 303 | |
| 304 | return NULL; |
| 305 | } |
| 306 | |
| 307 | /* |
| 308 | * Return declaration for passed function, adding it to the module if |
| 309 | * necessary. |
| 310 | * |
| 311 | * This is used to make functions imported by llvm_create_types() known to the |
| 312 | * module that's currently being worked on. |
| 313 | */ |
| 314 | LLVMValueRef |
| 315 | llvm_get_decl(LLVMModuleRef mod, LLVMValueRef v_src) |
| 316 | { |
| 317 | LLVMValueRef v_fn; |
| 318 | |
| 319 | /* don't repeatedly add function */ |
| 320 | v_fn = LLVMGetNamedFunction(mod, LLVMGetValueName(v_src)); |
| 321 | if (v_fn) |
| 322 | return v_fn; |
| 323 | |
| 324 | v_fn = LLVMAddFunction(mod, |
| 325 | LLVMGetValueName(v_src), |
| 326 | LLVMGetElementType(LLVMTypeOf(v_src))); |
| 327 | llvm_copy_attributes(v_src, v_fn); |
| 328 | |
| 329 | return v_fn; |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | * Copy attributes from one function to another. |
| 334 | */ |
| 335 | void |
| 336 | llvm_copy_attributes(LLVMValueRef v_from, LLVMValueRef v_to) |
| 337 | { |
| 338 | int num_attributes; |
| 339 | int attno; |
| 340 | LLVMAttributeRef *attrs; |
| 341 | |
| 342 | num_attributes = |
| 343 | LLVMGetAttributeCountAtIndex(v_from, LLVMAttributeFunctionIndex); |
| 344 | |
| 345 | attrs = palloc(sizeof(LLVMAttributeRef) * num_attributes); |
| 346 | LLVMGetAttributesAtIndex(v_from, LLVMAttributeFunctionIndex, attrs); |
| 347 | |
| 348 | for (attno = 0; attno < num_attributes; attno++) |
| 349 | { |
| 350 | LLVMAddAttributeAtIndex(v_to, LLVMAttributeFunctionIndex, |
| 351 | attrs[attno]); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * Return a callable LLVMValueRef for fcinfo. |
| 357 | */ |
| 358 | LLVMValueRef |
| 359 | llvm_function_reference(LLVMJitContext *context, |
| 360 | LLVMBuilderRef builder, |
| 361 | LLVMModuleRef mod, |
| 362 | FunctionCallInfo fcinfo) |
| 363 | { |
| 364 | char *modname; |
| 365 | char *basename; |
| 366 | char *funcname; |
| 367 | |
| 368 | LLVMValueRef v_fn; |
| 369 | |
| 370 | fmgr_symbol(fcinfo->flinfo->fn_oid, &modname, &basename); |
| 371 | |
| 372 | if (modname != NULL && basename != NULL) |
| 373 | { |
| 374 | /* external function in loadable library */ |
| 375 | funcname = psprintf("pgextern.%s.%s" , modname, basename); |
| 376 | } |
| 377 | else if (basename != NULL) |
| 378 | { |
| 379 | /* internal function */ |
| 380 | funcname = psprintf("%s" , basename); |
| 381 | } |
| 382 | else |
| 383 | { |
| 384 | /* |
| 385 | * Function we don't know to handle, return pointer. We do so by |
| 386 | * creating a global constant containing a pointer to the function. |
| 387 | * Makes IR more readable. |
| 388 | */ |
| 389 | LLVMValueRef v_fn_addr; |
| 390 | |
| 391 | funcname = psprintf("pgoidextern.%u" , |
| 392 | fcinfo->flinfo->fn_oid); |
| 393 | v_fn = LLVMGetNamedGlobal(mod, funcname); |
| 394 | if (v_fn != 0) |
| 395 | return LLVMBuildLoad(builder, v_fn, "" ); |
| 396 | |
| 397 | v_fn_addr = l_ptr_const(fcinfo->flinfo->fn_addr, TypePGFunction); |
| 398 | |
| 399 | v_fn = LLVMAddGlobal(mod, TypePGFunction, funcname); |
| 400 | LLVMSetInitializer(v_fn, v_fn_addr); |
| 401 | LLVMSetGlobalConstant(v_fn, true); |
| 402 | |
| 403 | return LLVMBuildLoad(builder, v_fn, "" ); |
| 404 | } |
| 405 | |
| 406 | /* check if function already has been added */ |
| 407 | v_fn = LLVMGetNamedFunction(mod, funcname); |
| 408 | if (v_fn != 0) |
| 409 | return v_fn; |
| 410 | |
| 411 | v_fn = LLVMAddFunction(mod, funcname, LLVMGetElementType(TypePGFunction)); |
| 412 | |
| 413 | return v_fn; |
| 414 | } |
| 415 | |
| 416 | /* |
| 417 | * Optimize code in module using the flags set in context. |
| 418 | */ |
| 419 | static void |
| 420 | llvm_optimize_module(LLVMJitContext *context, LLVMModuleRef module) |
| 421 | { |
| 422 | LLVMPassManagerBuilderRef llvm_pmb; |
| 423 | LLVMPassManagerRef llvm_mpm; |
| 424 | LLVMPassManagerRef llvm_fpm; |
| 425 | LLVMValueRef func; |
| 426 | int compile_optlevel; |
| 427 | |
| 428 | if (context->base.flags & PGJIT_OPT3) |
| 429 | compile_optlevel = 3; |
| 430 | else |
| 431 | compile_optlevel = 0; |
| 432 | |
| 433 | /* |
| 434 | * Have to create a new pass manager builder every pass through, as the |
| 435 | * inliner has some per-builder state. Otherwise one ends up only inlining |
| 436 | * a function the first time though. |
| 437 | */ |
| 438 | llvm_pmb = LLVMPassManagerBuilderCreate(); |
| 439 | LLVMPassManagerBuilderSetOptLevel(llvm_pmb, compile_optlevel); |
| 440 | llvm_fpm = LLVMCreateFunctionPassManagerForModule(module); |
| 441 | |
| 442 | if (context->base.flags & PGJIT_OPT3) |
| 443 | { |
| 444 | /* TODO: Unscientifically determined threshold */ |
| 445 | LLVMPassManagerBuilderUseInlinerWithThreshold(llvm_pmb, 512); |
| 446 | } |
| 447 | else |
| 448 | { |
| 449 | /* we rely on mem2reg heavily, so emit even in the O0 case */ |
| 450 | LLVMAddPromoteMemoryToRegisterPass(llvm_fpm); |
| 451 | } |
| 452 | |
| 453 | LLVMPassManagerBuilderPopulateFunctionPassManager(llvm_pmb, llvm_fpm); |
| 454 | |
| 455 | /* |
| 456 | * Do function level optimization. This could be moved to the point where |
| 457 | * functions are emitted, to reduce memory usage a bit. |
| 458 | */ |
| 459 | LLVMInitializeFunctionPassManager(llvm_fpm); |
| 460 | for (func = LLVMGetFirstFunction(context->module); |
| 461 | func != NULL; |
| 462 | func = LLVMGetNextFunction(func)) |
| 463 | LLVMRunFunctionPassManager(llvm_fpm, func); |
| 464 | LLVMFinalizeFunctionPassManager(llvm_fpm); |
| 465 | LLVMDisposePassManager(llvm_fpm); |
| 466 | |
| 467 | /* |
| 468 | * Perform module level optimization. We do so even in the non-optimized |
| 469 | * case, so always-inline functions etc get inlined. It's cheap enough. |
| 470 | */ |
| 471 | llvm_mpm = LLVMCreatePassManager(); |
| 472 | LLVMPassManagerBuilderPopulateModulePassManager(llvm_pmb, |
| 473 | llvm_mpm); |
| 474 | /* always use always-inliner pass */ |
| 475 | if (!(context->base.flags & PGJIT_OPT3)) |
| 476 | LLVMAddAlwaysInlinerPass(llvm_mpm); |
| 477 | /* if doing inlining, but no expensive optimization, add inlining pass */ |
| 478 | if (context->base.flags & PGJIT_INLINE |
| 479 | && !(context->base.flags & PGJIT_OPT3)) |
| 480 | LLVMAddFunctionInliningPass(llvm_mpm); |
| 481 | LLVMRunPassManager(llvm_mpm, context->module); |
| 482 | LLVMDisposePassManager(llvm_mpm); |
| 483 | |
| 484 | LLVMPassManagerBuilderDispose(llvm_pmb); |
| 485 | } |
| 486 | |
| 487 | /* |
| 488 | * Emit code for the currently pending module. |
| 489 | */ |
| 490 | static void |
| 491 | llvm_compile_module(LLVMJitContext *context) |
| 492 | { |
| 493 | LLVMOrcModuleHandle orc_handle; |
| 494 | MemoryContext oldcontext; |
| 495 | static LLVMOrcJITStackRef compile_orc; |
| 496 | instr_time starttime; |
| 497 | instr_time endtime; |
| 498 | |
| 499 | if (context->base.flags & PGJIT_OPT3) |
| 500 | compile_orc = llvm_opt3_orc; |
| 501 | else |
| 502 | compile_orc = llvm_opt0_orc; |
| 503 | |
| 504 | /* perform inlining */ |
| 505 | if (context->base.flags & PGJIT_INLINE) |
| 506 | { |
| 507 | INSTR_TIME_SET_CURRENT(starttime); |
| 508 | llvm_inline(context->module); |
| 509 | INSTR_TIME_SET_CURRENT(endtime); |
| 510 | INSTR_TIME_ACCUM_DIFF(context->base.instr.inlining_counter, |
| 511 | endtime, starttime); |
| 512 | } |
| 513 | |
| 514 | if (jit_dump_bitcode) |
| 515 | { |
| 516 | char *filename; |
| 517 | |
| 518 | filename = psprintf("%u.%zu.bc" , |
| 519 | MyProcPid, |
| 520 | context->module_generation); |
| 521 | LLVMWriteBitcodeToFile(context->module, filename); |
| 522 | pfree(filename); |
| 523 | } |
| 524 | |
| 525 | |
| 526 | /* optimize according to the chosen optimization settings */ |
| 527 | INSTR_TIME_SET_CURRENT(starttime); |
| 528 | llvm_optimize_module(context, context->module); |
| 529 | INSTR_TIME_SET_CURRENT(endtime); |
| 530 | INSTR_TIME_ACCUM_DIFF(context->base.instr.optimization_counter, |
| 531 | endtime, starttime); |
| 532 | |
| 533 | if (jit_dump_bitcode) |
| 534 | { |
| 535 | char *filename; |
| 536 | |
| 537 | filename = psprintf("%u.%zu.optimized.bc" , |
| 538 | MyProcPid, |
| 539 | context->module_generation); |
| 540 | LLVMWriteBitcodeToFile(context->module, filename); |
| 541 | pfree(filename); |
| 542 | } |
| 543 | |
| 544 | /* |
| 545 | * Emit the code. Note that this can, depending on the optimization |
| 546 | * settings, take noticeable resources as code emission executes low-level |
| 547 | * instruction combining/selection passes etc. Without optimization a |
| 548 | * faster instruction selection mechanism is used. |
| 549 | */ |
| 550 | INSTR_TIME_SET_CURRENT(starttime); |
| 551 | #if LLVM_VERSION_MAJOR > 6 |
| 552 | { |
| 553 | if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &orc_handle, context->module, |
| 554 | llvm_resolve_symbol, NULL)) |
| 555 | { |
| 556 | elog(ERROR, "failed to JIT module" ); |
| 557 | } |
| 558 | |
| 559 | /* LLVMOrcAddEagerlyCompiledIR takes ownership of the module */ |
| 560 | } |
| 561 | #elif LLVM_VERSION_MAJOR > 4 |
| 562 | { |
| 563 | LLVMSharedModuleRef smod; |
| 564 | |
| 565 | smod = LLVMOrcMakeSharedModule(context->module); |
| 566 | if (LLVMOrcAddEagerlyCompiledIR(compile_orc, &orc_handle, smod, |
| 567 | llvm_resolve_symbol, NULL)) |
| 568 | { |
| 569 | elog(ERROR, "failed to JIT module" ); |
| 570 | } |
| 571 | LLVMOrcDisposeSharedModuleRef(smod); |
| 572 | } |
| 573 | #else /* LLVM 4.0 and 3.9 */ |
| 574 | { |
| 575 | orc_handle = LLVMOrcAddEagerlyCompiledIR(compile_orc, context->module, |
| 576 | llvm_resolve_symbol, NULL); |
| 577 | LLVMDisposeModule(context->module); |
| 578 | } |
| 579 | #endif |
| 580 | INSTR_TIME_SET_CURRENT(endtime); |
| 581 | INSTR_TIME_ACCUM_DIFF(context->base.instr.emission_counter, |
| 582 | endtime, starttime); |
| 583 | |
| 584 | context->module = NULL; |
| 585 | context->compiled = true; |
| 586 | |
| 587 | /* remember emitted code for cleanup and lookups */ |
| 588 | oldcontext = MemoryContextSwitchTo(TopMemoryContext); |
| 589 | { |
| 590 | LLVMJitHandle *handle; |
| 591 | |
| 592 | handle = (LLVMJitHandle *) palloc(sizeof(LLVMJitHandle)); |
| 593 | handle->stack = compile_orc; |
| 594 | handle->orc_handle = orc_handle; |
| 595 | |
| 596 | context->handles = lappend(context->handles, handle); |
| 597 | } |
| 598 | MemoryContextSwitchTo(oldcontext); |
| 599 | |
| 600 | ereport(DEBUG1, |
| 601 | (errmsg("time to inline: %.3fs, opt: %.3fs, emit: %.3fs" , |
| 602 | INSTR_TIME_GET_DOUBLE(context->base.instr.inlining_counter), |
| 603 | INSTR_TIME_GET_DOUBLE(context->base.instr.optimization_counter), |
| 604 | INSTR_TIME_GET_DOUBLE(context->base.instr.emission_counter)), |
| 605 | errhidestmt(true), |
| 606 | errhidecontext(true))); |
| 607 | } |
| 608 | |
| 609 | /* |
| 610 | * Per session initialization. |
| 611 | */ |
| 612 | static void |
| 613 | llvm_session_initialize(void) |
| 614 | { |
| 615 | MemoryContext oldcontext; |
| 616 | char *error = NULL; |
| 617 | char *cpu = NULL; |
| 618 | char *features = NULL; |
| 619 | |
| 620 | if (llvm_session_initialized) |
| 621 | return; |
| 622 | |
| 623 | oldcontext = MemoryContextSwitchTo(TopMemoryContext); |
| 624 | |
| 625 | LLVMInitializeNativeTarget(); |
| 626 | LLVMInitializeNativeAsmPrinter(); |
| 627 | LLVMInitializeNativeAsmParser(); |
| 628 | |
| 629 | /* |
| 630 | * Synchronize types early, as that also includes inferring the target |
| 631 | * triple. |
| 632 | */ |
| 633 | llvm_create_types(); |
| 634 | |
| 635 | if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0) |
| 636 | { |
| 637 | elog(FATAL, "failed to query triple %s\n" , error); |
| 638 | } |
| 639 | |
| 640 | /* |
| 641 | * We want the generated code to use all available features. Therefore |
| 642 | * grab the host CPU string and detect features of the current CPU. The |
| 643 | * latter is needed because some CPU architectures default to enabling |
| 644 | * features not all CPUs have (weird, huh). |
| 645 | */ |
| 646 | cpu = LLVMGetHostCPUName(); |
| 647 | features = LLVMGetHostCPUFeatures(); |
| 648 | elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"" , |
| 649 | cpu, features); |
| 650 | |
| 651 | llvm_opt0_targetmachine = |
| 652 | LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features, |
| 653 | LLVMCodeGenLevelNone, |
| 654 | LLVMRelocDefault, |
| 655 | LLVMCodeModelJITDefault); |
| 656 | llvm_opt3_targetmachine = |
| 657 | LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features, |
| 658 | LLVMCodeGenLevelAggressive, |
| 659 | LLVMRelocDefault, |
| 660 | LLVMCodeModelJITDefault); |
| 661 | |
| 662 | LLVMDisposeMessage(cpu); |
| 663 | cpu = NULL; |
| 664 | LLVMDisposeMessage(features); |
| 665 | features = NULL; |
| 666 | |
| 667 | /* force symbols in main binary to be loaded */ |
| 668 | LLVMLoadLibraryPermanently(NULL); |
| 669 | |
| 670 | llvm_opt0_orc = LLVMOrcCreateInstance(llvm_opt0_targetmachine); |
| 671 | llvm_opt3_orc = LLVMOrcCreateInstance(llvm_opt3_targetmachine); |
| 672 | |
| 673 | #if defined(HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER) && HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER |
| 674 | if (jit_debugging_support) |
| 675 | { |
| 676 | LLVMJITEventListenerRef l = LLVMCreateGDBRegistrationListener(); |
| 677 | |
| 678 | LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l); |
| 679 | LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l); |
| 680 | } |
| 681 | #endif |
| 682 | #if defined(HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER) && HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER |
| 683 | if (jit_profiling_support) |
| 684 | { |
| 685 | LLVMJITEventListenerRef l = LLVMCreatePerfJITEventListener(); |
| 686 | |
| 687 | LLVMOrcRegisterJITEventListener(llvm_opt0_orc, l); |
| 688 | LLVMOrcRegisterJITEventListener(llvm_opt3_orc, l); |
| 689 | } |
| 690 | #endif |
| 691 | |
| 692 | before_shmem_exit(llvm_shutdown, 0); |
| 693 | |
| 694 | llvm_session_initialized = true; |
| 695 | |
| 696 | MemoryContextSwitchTo(oldcontext); |
| 697 | } |
| 698 | |
| 699 | static void |
| 700 | llvm_shutdown(int code, Datum arg) |
| 701 | { |
| 702 | /* unregister profiling support, needs to be flushed to be useful */ |
| 703 | |
| 704 | if (llvm_opt3_orc) |
| 705 | { |
| 706 | #if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF |
| 707 | if (jit_profiling_support) |
| 708 | LLVMOrcUnregisterPerf(llvm_opt3_orc); |
| 709 | #endif |
| 710 | LLVMOrcDisposeInstance(llvm_opt3_orc); |
| 711 | llvm_opt3_orc = NULL; |
| 712 | } |
| 713 | |
| 714 | if (llvm_opt0_orc) |
| 715 | { |
| 716 | #if defined(HAVE_DECL_LLVMORCREGISTERPERF) && HAVE_DECL_LLVMORCREGISTERPERF |
| 717 | if (jit_profiling_support) |
| 718 | LLVMOrcUnregisterPerf(llvm_opt0_orc); |
| 719 | #endif |
| 720 | LLVMOrcDisposeInstance(llvm_opt0_orc); |
| 721 | llvm_opt0_orc = NULL; |
| 722 | } |
| 723 | } |
| 724 | |
| 725 | /* helper for llvm_create_types, returning a global var's type */ |
| 726 | static LLVMTypeRef |
| 727 | load_type(LLVMModuleRef mod, const char *name) |
| 728 | { |
| 729 | LLVMValueRef value; |
| 730 | LLVMTypeRef typ; |
| 731 | |
| 732 | /* this'll return a *pointer* to the global */ |
| 733 | value = LLVMGetNamedGlobal(mod, name); |
| 734 | if (!value) |
| 735 | elog(ERROR, "type %s is unknown" , name); |
| 736 | |
| 737 | /* therefore look at the contained type and return that */ |
| 738 | typ = LLVMTypeOf(value); |
| 739 | Assert(typ != NULL); |
| 740 | typ = LLVMGetElementType(typ); |
| 741 | Assert(typ != NULL); |
| 742 | return typ; |
| 743 | } |
| 744 | |
| 745 | /* helper for llvm_create_types, returning a function's return type */ |
| 746 | static LLVMTypeRef |
| 747 | load_return_type(LLVMModuleRef mod, const char *name) |
| 748 | { |
| 749 | LLVMValueRef value; |
| 750 | LLVMTypeRef typ; |
| 751 | |
| 752 | /* this'll return a *pointer* to the function */ |
| 753 | value = LLVMGetNamedFunction(mod, name); |
| 754 | if (!value) |
| 755 | elog(ERROR, "function %s is unknown" , name); |
| 756 | |
| 757 | /* get type of function pointer */ |
| 758 | typ = LLVMTypeOf(value); |
| 759 | Assert(typ != NULL); |
| 760 | /* dereference pointer */ |
| 761 | typ = LLVMGetElementType(typ); |
| 762 | Assert(typ != NULL); |
| 763 | /* and look at return type */ |
| 764 | typ = LLVMGetReturnType(typ); |
| 765 | Assert(typ != NULL); |
| 766 | |
| 767 | return typ; |
| 768 | } |
| 769 | |
| 770 | /* |
| 771 | * Load required information, types, function signatures from llvmjit_types.c |
| 772 | * and make them available in global variables. |
| 773 | * |
| 774 | * Those global variables are then used while emitting code. |
| 775 | */ |
| 776 | static void |
| 777 | llvm_create_types(void) |
| 778 | { |
| 779 | char path[MAXPGPATH]; |
| 780 | LLVMMemoryBufferRef buf; |
| 781 | char *msg; |
| 782 | LLVMModuleRef mod = NULL; |
| 783 | |
| 784 | snprintf(path, MAXPGPATH, "%s/%s" , pkglib_path, "llvmjit_types.bc" ); |
| 785 | |
| 786 | /* open file */ |
| 787 | if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &msg)) |
| 788 | { |
| 789 | elog(ERROR, "LLVMCreateMemoryBufferWithContentsOfFile(%s) failed: %s" , |
| 790 | path, msg); |
| 791 | } |
| 792 | |
| 793 | /* eagerly load contents, going to need it all */ |
| 794 | if (LLVMParseBitcode2(buf, &mod)) |
| 795 | { |
| 796 | elog(ERROR, "LLVMParseBitcode2 of %s failed" , path); |
| 797 | } |
| 798 | LLVMDisposeMemoryBuffer(buf); |
| 799 | |
| 800 | /* |
| 801 | * Load triple & layout from clang emitted file so we're guaranteed to be |
| 802 | * compatible. |
| 803 | */ |
| 804 | llvm_triple = pstrdup(LLVMGetTarget(mod)); |
| 805 | llvm_layout = pstrdup(LLVMGetDataLayoutStr(mod)); |
| 806 | |
| 807 | TypeSizeT = load_type(mod, "TypeSizeT" ); |
| 808 | TypeParamBool = load_return_type(mod, "FunctionReturningBool" ); |
| 809 | TypeStorageBool = load_type(mod, "TypeStorageBool" ); |
| 810 | TypePGFunction = load_type(mod, "TypePGFunction" ); |
| 811 | StructNullableDatum = load_type(mod, "StructNullableDatum" ); |
| 812 | StructExprContext = load_type(mod, "StructExprContext" ); |
| 813 | StructExprEvalStep = load_type(mod, "StructExprEvalStep" ); |
| 814 | StructExprState = load_type(mod, "StructExprState" ); |
| 815 | StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData" ); |
| 816 | StructMemoryContextData = load_type(mod, "StructMemoryContextData" ); |
| 817 | StructTupleTableSlot = load_type(mod, "StructTupleTableSlot" ); |
| 818 | StructHeapTupleTableSlot = load_type(mod, "StructHeapTupleTableSlot" ); |
| 819 | StructMinimalTupleTableSlot = load_type(mod, "StructMinimalTupleTableSlot" ); |
| 820 | StructHeapTupleData = load_type(mod, "StructHeapTupleData" ); |
| 821 | StructTupleDescData = load_type(mod, "StructTupleDescData" ); |
| 822 | StructAggState = load_type(mod, "StructAggState" ); |
| 823 | StructAggStatePerGroupData = load_type(mod, "StructAggStatePerGroupData" ); |
| 824 | StructAggStatePerTransData = load_type(mod, "StructAggStatePerTransData" ); |
| 825 | |
| 826 | AttributeTemplate = LLVMGetNamedFunction(mod, "AttributeTemplate" ); |
| 827 | FuncStrlen = LLVMGetNamedFunction(mod, "strlen" ); |
| 828 | FuncVarsizeAny = LLVMGetNamedFunction(mod, "varsize_any" ); |
| 829 | FuncSlotGetsomeattrsInt = LLVMGetNamedFunction(mod, "slot_getsomeattrs_int" ); |
| 830 | FuncSlotGetmissingattrs = LLVMGetNamedFunction(mod, "slot_getmissingattrs" ); |
| 831 | FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal" ); |
| 832 | FuncExecEvalSubscriptingRef = LLVMGetNamedFunction(mod, "ExecEvalSubscriptingRef" ); |
| 833 | FuncExecEvalSysVar = LLVMGetNamedFunction(mod, "ExecEvalSysVar" ); |
| 834 | FuncExecAggTransReparent = LLVMGetNamedFunction(mod, "ExecAggTransReparent" ); |
| 835 | FuncExecAggInitGroup = LLVMGetNamedFunction(mod, "ExecAggInitGroup" ); |
| 836 | |
| 837 | /* |
| 838 | * Leave the module alive, otherwise references to function would be |
| 839 | * dangling. |
| 840 | */ |
| 841 | |
| 842 | return; |
| 843 | } |
| 844 | |
| 845 | /* |
| 846 | * Split a symbol into module / function parts. If the function is in the |
| 847 | * main binary (or an external library) *modname will be NULL. |
| 848 | */ |
| 849 | void |
| 850 | llvm_split_symbol_name(const char *name, char **modname, char **funcname) |
| 851 | { |
| 852 | *modname = NULL; |
| 853 | *funcname = NULL; |
| 854 | |
| 855 | /* |
| 856 | * Module function names are pgextern.$module.$funcname |
| 857 | */ |
| 858 | if (strncmp(name, "pgextern." , strlen("pgextern." )) == 0) |
| 859 | { |
| 860 | /* |
| 861 | * Symbol names cannot contain a ., therefore we can split based on |
| 862 | * first and last occurrence of one. |
| 863 | */ |
| 864 | *funcname = rindex(name, '.'); |
| 865 | (*funcname)++; /* jump over . */ |
| 866 | |
| 867 | *modname = pnstrdup(name + strlen("pgextern." ), |
| 868 | *funcname - name - strlen("pgextern." ) - 1); |
| 869 | Assert(funcname); |
| 870 | |
| 871 | *funcname = pstrdup(*funcname); |
| 872 | } |
| 873 | else |
| 874 | { |
| 875 | *modname = NULL; |
| 876 | *funcname = pstrdup(name); |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | /* |
| 881 | * Attempt to resolve symbol, so LLVM can emit a reference to it. |
| 882 | */ |
| 883 | static uint64_t |
| 884 | llvm_resolve_symbol(const char *symname, void *ctx) |
| 885 | { |
| 886 | uintptr_t addr; |
| 887 | char *funcname; |
| 888 | char *modname; |
| 889 | |
| 890 | /* |
| 891 | * macOS prefixes all object level symbols with an underscore. But neither |
| 892 | * dlsym() nor PG's inliner expect that. So undo. |
| 893 | */ |
| 894 | #if defined(__darwin__) |
| 895 | if (symname[0] != '_') |
| 896 | elog(ERROR, "expected prefixed symbol name, but got \"%s\"" , symname); |
| 897 | symname++; |
| 898 | #endif |
| 899 | |
| 900 | llvm_split_symbol_name(symname, &modname, &funcname); |
| 901 | |
| 902 | /* functions that aren't resolved to names shouldn't ever get here */ |
| 903 | Assert(funcname); |
| 904 | |
| 905 | if (modname) |
| 906 | addr = (uintptr_t) load_external_function(modname, funcname, |
| 907 | true, NULL); |
| 908 | else |
| 909 | addr = (uintptr_t) LLVMSearchForAddressOfSymbol(symname); |
| 910 | |
| 911 | pfree(funcname); |
| 912 | if (modname) |
| 913 | pfree(modname); |
| 914 | |
| 915 | /* let LLVM will error out - should never happen */ |
| 916 | if (!addr) |
| 917 | elog(WARNING, "failed to resolve name %s" , symname); |
| 918 | |
| 919 | return (uint64_t) addr; |
| 920 | } |
| 921 | |