Commit b96d550e authored by Andres Freund's avatar Andres Freund

Support for optimizing and emitting code in LLVM JIT provider.

This commit introduces the ability to actually generate code using
LLVM. In particular, this adds:

- Ability to emit code both in heavily optimized and largely
  unoptimized fashion
- Batching facility to allow functions to be defined in small
  increments, but optimized and emitted in executable form in larger
  batches (for performance and memory efficiency)
- Type and function declaration synchronization between runtime
  generated code and normal postgres code. This is critical to be able
  to access struct fields etc.
- Developer oriented jit_dump_bitcode GUC, for inspecting / debugging
  the generated code.
- per JitContext statistics of number of functions, time spent
  generating code, optimizing, and emitting it.  This will later be
  employed for EXPLAIN support.

This commit doesn't yet contain any code actually generating
functions. That'll follow in later commits.

Documentation for GUCs added, and for JIT in general, will be added in
later commits.

Author: Andres Freund, with contributions by Pierre Ducroquet
Testing-By: Thomas Munro, Peter Eisentraut
Discussion: https://postgr.es/m/20170901064131.tazjxwus3k2w3ybh@alap3.anarazel.de
parent 2fe6336e
# Global excludes across all subdirectories # Global excludes across all subdirectories
*.o *.o
*.obj *.obj
*.bc
*.so *.so
*.so.[0-9] *.so.[0-9]
*.so.[0-9].[0-9] *.so.[0-9].[0-9]
......
...@@ -951,3 +951,24 @@ coverage-clean: ...@@ -951,3 +951,24 @@ coverage-clean:
rm -f `find . -name '*.gcda' -print` rm -f `find . -name '*.gcda' -print`
endif # enable_coverage endif # enable_coverage
##########################################################################
#
# LLVM support
#
ifndef COMPILE.c.bc
# -Wno-ignored-attributes added so gnu_printf doesn't trigger
# warnings, when the main binary is compiled with C.
COMPILE.c.bc = $(CLANG) -Wno-ignored-attributes $(BITCODE_CFLAGS) $(CPPFLAGS) -flto=thin -emit-llvm -c
endif
ifndef COMPILE.cxx.bc
COMPILE.cxx.bc = $(CLANG) -xc++ -Wno-ignored-attributes $(BITCODE_CXXFLAGS) $(CPPFLAGS) -flto=thin -emit-llvm -c
endif
%.bc : %.c
$(COMPILE.c.bc) -o $@ $<
%.bc : %.cpp
$(COMPILE.cxx.bc) -o $@ $<
...@@ -46,3 +46,4 @@ clean-local: ...@@ -46,3 +46,4 @@ clean-local:
rm -f $(subsysfilename) $(OBJS) rm -f $(subsysfilename) $(OBJS)
$(call recurse,coverage) $(call recurse,coverage)
$(call recurse,install)
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
/* GUCs */ /* GUCs */
bool jit_enabled = true; bool jit_enabled = true;
char *jit_provider = "llvmjit"; char *jit_provider = "llvmjit";
bool jit_dump_bitcode = false;
static JitProviderCallbacks provider; static JitProviderCallbacks provider;
static bool provider_successfully_loaded = false; static bool provider_successfully_loaded = false;
......
...@@ -41,15 +41,23 @@ OBJS += llvmjit.o llvmjit_error.o llvmjit_wrap.o ...@@ -41,15 +41,23 @@ OBJS += llvmjit.o llvmjit_error.o llvmjit_wrap.o
# Code generation # Code generation
OBJS += OBJS +=
all: all-shared-lib all: all-shared-lib llvmjit_types.bc
install: all installdirs install-lib install: all installdirs install-lib install-types
installdirs: installdirs-lib installdirs: installdirs-lib
uninstall: uninstall-lib uninstall: uninstall-lib uninstall-types
# Note this is intentionally not in bitcodedir, as it's not for inlining */
install-types: llvmjit_types.bc
$(INSTALL_DATA) llvmjit_types.bc '$(DESTDIR)$(pkglibdir)'
uninstall-types:
rm -f '$(DESTDIR)$(pkglibdir)/llvmjit_types.bc'
include $(top_srcdir)/src/Makefile.shlib include $(top_srcdir)/src/Makefile.shlib
clean distclean maintainer-clean: clean-lib clean distclean maintainer-clean: clean-lib
rm -f $(OBJS) rm -f $(OBJS)
rm -f llvmjit_types.bc
This diff is collapsed.
/*-------------------------------------------------------------------------
*
* llvmjit_types.c
* List of types needed by JIT emitting code.
*
* JIT emitting code often needs to access struct elements, create functions
* with the correct signature etc. To allow synchronizing these types with a
* low chance of definitions getting out of sync, this file lists types and
* functions that directly need to be accessed from LLVM.
*
* When LlVM is first used in a backend, a bitcode version of this file, will
* be loaded. The needed types and signatures will be stored into Struct*,
* Type*, Func* variables.
*
* NB: This file will not be linked into the server, it's just converted to
* bitcode.
*
*
* Copyright (c) 2016-2018, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/lib/llvmjit_types.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "fmgr.h"
/*
* List of types needed for JITing. These have to be non-static, otherwise
* clang/LLVM will omit them. As this file will never be linked into
* anything, that's harmless.
*/
size_t TypeSizeT;
/*
* To determine which attributes functions need to have (depends e.g. on
* compiler version and settings) to be compatible for inlining, we simply
* copy the attributes of this function.
*/
extern Datum AttributeTemplate(PG_FUNCTION_ARGS);
Datum
AttributeTemplate(PG_FUNCTION_ARGS)
{
PG_RETURN_NULL();
}
/*
* To force signatures of functions used during JITing to be present,
* reference the functions required. This again has to be non-static, to avoid
* being removed as unnecessary.
*/
void *referenced_functions[] =
{
strlen
};
...@@ -1734,6 +1734,17 @@ static struct config_bool ConfigureNamesBool[] = ...@@ -1734,6 +1734,17 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL NULL, NULL, NULL
}, },
{
{"jit_dump_bitcode", PGC_SUSET, DEVELOPER_OPTIONS,
gettext_noop("Write out LLVM bitcode to facilitate JIT debugging."),
NULL,
GUC_NOT_IN_SAMPLE
},
&jit_dump_bitcode,
false,
NULL, NULL, NULL
},
/* End-of-list marker */ /* End-of-list marker */
{ {
{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
......
...@@ -11,14 +11,34 @@ ...@@ -11,14 +11,34 @@
#ifndef JIT_H #ifndef JIT_H
#define JIT_H #define JIT_H
#include "executor/instrument.h"
#include "utils/resowner.h" #include "utils/resowner.h"
/* Flags deterimining what kind of JIT operations to perform */
#define PGJIT_NONE 0
#define PGJIT_PERFORM 1 << 0
#define PGJIT_OPT3 1 << 1
typedef struct JitContext typedef struct JitContext
{ {
/* see PGJIT_* above */
int flags; int flags;
ResourceOwner resowner; ResourceOwner resowner;
/* number of emitted functions */
size_t created_functions;
/* accumulated time to generate code */
instr_time generation_counter;
/* accumulated time for optimization */
instr_time optimization_counter;
/* accumulated time for code emission */
instr_time emission_counter;
} JitContext; } JitContext;
typedef struct JitProviderCallbacks JitProviderCallbacks; typedef struct JitProviderCallbacks JitProviderCallbacks;
...@@ -38,6 +58,7 @@ struct JitProviderCallbacks ...@@ -38,6 +58,7 @@ struct JitProviderCallbacks
/* GUCs */ /* GUCs */
extern bool jit_enabled; extern bool jit_enabled;
extern char *jit_provider; extern char *jit_provider;
extern bool jit_dump_bitcode;
extern void jit_reset_after_error(void); extern void jit_reset_after_error(void);
......
...@@ -30,19 +30,49 @@ extern "C" ...@@ -30,19 +30,49 @@ extern "C"
#include "jit/jit.h" #include "jit/jit.h"
#include "nodes/pg_list.h"
typedef struct LLVMJitContext typedef struct LLVMJitContext
{ {
JitContext base; JitContext base;
/* number of modules created */
size_t module_generation;
/* current, "open for write", module */
LLVMModuleRef module;
/* is there any pending code that needs to be emitted */
bool compiled;
/* # of objects emitted, used to generate non-conflicting names */
int counter;
/* list of handles for code emitted via Orc */
List *handles;
} LLVMJitContext; } LLVMJitContext;
/* type and struct definitions */
extern LLVMTypeRef TypeSizeT;
extern LLVMValueRef AttributeTemplate;
extern LLVMValueRef FuncStrlen;
extern void llvm_enter_fatal_on_oom(void); extern void llvm_enter_fatal_on_oom(void);
extern void llvm_leave_fatal_on_oom(void); extern void llvm_leave_fatal_on_oom(void);
extern void llvm_reset_after_error(void); extern void llvm_reset_after_error(void);
extern void llvm_assert_in_fatal_section(void); extern void llvm_assert_in_fatal_section(void);
extern LLVMJitContext *llvm_create_context(int jitFlags); extern LLVMJitContext *llvm_create_context(int jitFlags);
extern LLVMModuleRef llvm_mutable_module(LLVMJitContext *context);
extern char *llvm_expand_funcname(LLVMJitContext *context, const char *basename);
extern void *llvm_get_function(LLVMJitContext *context, const char *funcname);
extern void llvm_split_symbol_name(const char *name, char **modname, char **funcname);
extern LLVMValueRef llvm_get_decl(LLVMModuleRef mod, LLVMValueRef f);
extern void llvm_copy_attributes(LLVMValueRef from, LLVMValueRef to);
/* /*
......
...@@ -1103,6 +1103,9 @@ LDAPURLDesc ...@@ -1103,6 +1103,9 @@ LDAPURLDesc
LDAP_TIMEVAL LDAP_TIMEVAL
LINE LINE
LLVMJitContext LLVMJitContext
LLVMJitHandle
LLVMTypeRef
LLVMValueRef
LOCALLOCK LOCALLOCK
LOCALLOCKOWNER LOCALLOCKOWNER
LOCALLOCKTAG LOCALLOCKTAG
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment