mirror of
https://github.com/zebrajr/postgres.git
synced 2025-12-06 12:20:15 +01:00
LLVM's opaque pointer change began in LLVM 14, but remained optional
until LLVM 16. When commit 37d5babb added opaque pointer support, we
didn't turn it on for LLVM 14 and 15 yet because we didn't want to risk
weird bitcode incompatibility problems in released branches of
PostgreSQL. (That might have been overly cautious, I don't know.)
Now that PostgreSQL 18 has dropped support for LLVM versions < 14, and
since it hasn't been released yet and no extensions or bitcode have been
built against it in the wild yet, we can be more aggressive. We can rip
out the support code and build system clutter that made opaque pointer
use optional.
Author: Thomas Munro <thomas.munro@gmail.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussions: https://postgr.es/m/CA%2BhUKGLhNs5geZaVNj2EJ79Dx9W8fyWUU3HxcpZy55sMGcY%3DiA%40mail.gmail.com
321 lines
7.1 KiB
C
321 lines
7.1 KiB
C
/*
|
|
* llvmjit_emit.h
|
|
* Helpers to make emitting LLVM IR a bit more concise and pgindent proof.
|
|
*
|
|
* Copyright (c) 2018-2024, PostgreSQL Global Development Group
|
|
*
|
|
* src/include/jit/llvmjit_emit.h
|
|
*/
|
|
#ifndef LLVMJIT_EMIT_H
|
|
#define LLVMJIT_EMIT_H
|
|
|
|
/*
|
|
* To avoid breaking cpluspluscheck, allow including the file even when LLVM
|
|
* is not available.
|
|
*/
|
|
#ifdef USE_LLVM
|
|
|
|
#include <llvm-c/Core.h>
|
|
#include <llvm-c/Target.h>
|
|
|
|
#include "jit/llvmjit.h"
|
|
|
|
|
|
/*
|
|
* Emit a non-LLVM pointer as an LLVM constant.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_ptr_const(void *ptr, LLVMTypeRef type)
|
|
{
|
|
LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false);
|
|
|
|
return LLVMConstIntToPtr(c, type);
|
|
}
|
|
|
|
/*
|
|
* Emit pointer.
|
|
*/
|
|
static inline LLVMTypeRef
|
|
l_ptr(LLVMTypeRef t)
|
|
{
|
|
return LLVMPointerType(t, 0);
|
|
}
|
|
|
|
/*
|
|
* Emit constant integer.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_int8_const(LLVMContextRef lc, int8 i)
|
|
{
|
|
return LLVMConstInt(LLVMInt8TypeInContext(lc), i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant integer.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_int16_const(LLVMContextRef lc, int16 i)
|
|
{
|
|
return LLVMConstInt(LLVMInt16TypeInContext(lc), i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant integer.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_int32_const(LLVMContextRef lc, int32 i)
|
|
{
|
|
return LLVMConstInt(LLVMInt32TypeInContext(lc), i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant integer.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_int64_const(LLVMContextRef lc, int64 i)
|
|
{
|
|
return LLVMConstInt(LLVMInt64TypeInContext(lc), i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant integer.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_sizet_const(size_t i)
|
|
{
|
|
return LLVMConstInt(TypeSizeT, i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant boolean, as used for storage (e.g. global vars, structs).
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_sbool_const(bool i)
|
|
{
|
|
return LLVMConstInt(TypeStorageBool, (int) i, false);
|
|
}
|
|
|
|
/*
|
|
* Emit constant boolean, as used for parameters (e.g. function parameters).
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_pbool_const(bool i)
|
|
{
|
|
return LLVMConstInt(TypeParamBool, (int) i, false);
|
|
}
|
|
|
|
static inline LLVMValueRef
|
|
l_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
|
|
{
|
|
return LLVMBuildStructGEP2(b, t, v, idx, "");
|
|
}
|
|
|
|
static inline LLVMValueRef
|
|
l_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef *indices, int32 nindices, const char *name)
|
|
{
|
|
return LLVMBuildGEP2(b, t, v, indices, nindices, name);
|
|
}
|
|
|
|
static inline LLVMValueRef
|
|
l_load(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, const char *name)
|
|
{
|
|
return LLVMBuildLoad2(b, t, v, name);
|
|
}
|
|
|
|
static inline LLVMValueRef
|
|
l_call(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef fn, LLVMValueRef *args, int32 nargs, const char *name)
|
|
{
|
|
return LLVMBuildCall2(b, t, fn, args, nargs, name);
|
|
}
|
|
|
|
/*
|
|
* Load a pointer member idx from a struct.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_load_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name)
|
|
{
|
|
return l_load(b,
|
|
LLVMStructGetTypeAtIndex(t, idx),
|
|
l_struct_gep(b, t, v, idx, ""),
|
|
name);
|
|
}
|
|
|
|
/*
|
|
* Load value of a pointer, after applying one index operation.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_load_gep1(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef idx, const char *name)
|
|
{
|
|
return l_load(b, t, l_gep(b, t, v, &idx, 1, ""), name);
|
|
}
|
|
|
|
/* separate, because pg_attribute_printf(2, 3) can't appear in definition */
|
|
static inline LLVMBasicBlockRef l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...) pg_attribute_printf(2, 3);
|
|
|
|
/*
|
|
* Insert a new basic block, just before r, the name being determined by fmt
|
|
* and arguments.
|
|
*/
|
|
static inline LLVMBasicBlockRef
|
|
l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...)
|
|
{
|
|
char buf[512];
|
|
va_list args;
|
|
LLVMContextRef lc;
|
|
|
|
va_start(args, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
va_end(args);
|
|
|
|
lc = LLVMGetTypeContext(LLVMTypeOf(LLVMGetBasicBlockParent(r)));
|
|
|
|
return LLVMInsertBasicBlockInContext(lc, r, buf);
|
|
}
|
|
|
|
/* separate, because pg_attribute_printf(2, 3) can't appear in definition */
|
|
static inline LLVMBasicBlockRef l_bb_append_v(LLVMValueRef f, const char *fmt,...) pg_attribute_printf(2, 3);
|
|
|
|
/*
|
|
* Insert a new basic block after previous basic blocks, the name being
|
|
* determined by fmt and arguments.
|
|
*/
|
|
static inline LLVMBasicBlockRef
|
|
l_bb_append_v(LLVMValueRef f, const char *fmt,...)
|
|
{
|
|
char buf[512];
|
|
va_list args;
|
|
LLVMContextRef lc;
|
|
|
|
va_start(args, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
va_end(args);
|
|
|
|
lc = LLVMGetTypeContext(LLVMTypeOf(f));
|
|
|
|
return LLVMAppendBasicBlockInContext(lc, f, buf);
|
|
}
|
|
|
|
/*
|
|
* Mark a callsite as readonly.
|
|
*/
|
|
static inline void
|
|
l_callsite_ro(LLVMValueRef f)
|
|
{
|
|
const char argname[] = "readonly";
|
|
LLVMAttributeRef ref;
|
|
|
|
ref = LLVMCreateStringAttribute(LLVMGetTypeContext(LLVMTypeOf(f)),
|
|
argname,
|
|
sizeof(argname) - 1,
|
|
NULL, 0);
|
|
|
|
LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref);
|
|
}
|
|
|
|
/*
|
|
* Mark a callsite as alwaysinline.
|
|
*/
|
|
static inline void
|
|
l_callsite_alwaysinline(LLVMValueRef f)
|
|
{
|
|
const char argname[] = "alwaysinline";
|
|
int id;
|
|
LLVMAttributeRef attr;
|
|
|
|
id = LLVMGetEnumAttributeKindForName(argname,
|
|
sizeof(argname) - 1);
|
|
attr = LLVMCreateEnumAttribute(LLVMGetTypeContext(LLVMTypeOf(f)), id, 0);
|
|
LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr);
|
|
}
|
|
|
|
/*
|
|
* Emit code to switch memory context.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc)
|
|
{
|
|
const char *cmc = "CurrentMemoryContext";
|
|
LLVMValueRef cur;
|
|
LLVMValueRef ret;
|
|
|
|
if (!(cur = LLVMGetNamedGlobal(mod, cmc)))
|
|
cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc);
|
|
ret = l_load(b, l_ptr(StructMemoryContextData), cur, cmc);
|
|
LLVMBuildStore(b, nc, cur);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Return pointer to the argno'th argument nullness.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
|
{
|
|
LLVMValueRef v_args;
|
|
LLVMValueRef v_argn;
|
|
|
|
v_args = l_struct_gep(b,
|
|
StructFunctionCallInfoData,
|
|
v_fcinfo,
|
|
FIELDNO_FUNCTIONCALLINFODATA_ARGS,
|
|
"");
|
|
v_argn = l_struct_gep(b,
|
|
LLVMArrayType(StructNullableDatum, 0),
|
|
v_args,
|
|
argno,
|
|
"");
|
|
return l_struct_gep(b,
|
|
StructNullableDatum,
|
|
v_argn,
|
|
FIELDNO_NULLABLE_DATUM_ISNULL,
|
|
"");
|
|
}
|
|
|
|
/*
|
|
* Return pointer to the argno'th argument datum.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
|
{
|
|
LLVMValueRef v_args;
|
|
LLVMValueRef v_argn;
|
|
|
|
v_args = l_struct_gep(b,
|
|
StructFunctionCallInfoData,
|
|
v_fcinfo,
|
|
FIELDNO_FUNCTIONCALLINFODATA_ARGS,
|
|
"");
|
|
v_argn = l_struct_gep(b,
|
|
LLVMArrayType(StructNullableDatum, 0),
|
|
v_args,
|
|
argno,
|
|
"");
|
|
return l_struct_gep(b,
|
|
StructNullableDatum,
|
|
v_argn,
|
|
FIELDNO_NULLABLE_DATUM_DATUM,
|
|
"");
|
|
}
|
|
|
|
/*
|
|
* Return argno'th argument nullness.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
|
{
|
|
return l_load(b, TypeStorageBool, l_funcnullp(b, v_fcinfo, argno), "");
|
|
}
|
|
|
|
/*
|
|
* Return argno'th argument datum.
|
|
*/
|
|
static inline LLVMValueRef
|
|
l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno)
|
|
{
|
|
return l_load(b, TypeSizeT, l_funcvaluep(b, v_fcinfo, argno), "");
|
|
}
|
|
|
|
#endif /* USE_LLVM */
|
|
#endif
|