llvmjit_types文件分三部分
v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
PGFunction TypePGFunction;
size_t TypeSizeT;
bool TypeStorageBool;
...
...
==========================
extern Datum AttributeTemplate(PG_FUNCTION_ARGS);
Datum
AttributeTemplate(PG_FUNCTION_ARGS)
{
AssertVariableIsOfType(&AttributeTemplate, PGFunction);
PG_RETURN_NULL();
}
...
...
==========================
void *referenced_functions[] =
{
ExecAggInitGroup,
ExecAggCopyTransValue,
ExecEvalPreOrderedDistinctSingle,
ExecEvalPreOrderedDistinctMulti,
ExecEvalAggOrderedTransDatum,
ExecEvalAggOrderedTransTuple,
ExecEvalArrayCoerce,
...
}
llvmjit_types.c:
*/
PGFunction TypePGFunction;
size_t TypeSizeT;
bool TypeStorageBool;
ExecEvalSubroutine TypeExecEvalSubroutine;
ExecEvalBoolSubroutine TypeExecEvalBoolSubroutine;
NullableDatum StructNullableDatum;
AggState StructAggState;
AggStatePerGroupData StructAggStatePerGroupData;
AggStatePerTransData StructAggStatePerTransData;
ExprContext StructExprContext;
ExprEvalStep StructExprEvalStep;
ExprState StructExprState;
FunctionCallInfoBaseData StructFunctionCallInfoData;
HeapTupleData StructHeapTupleData;
HeapTupleHeaderData StructHeapTupleHeaderData;
MemoryContextData StructMemoryContextData;
TupleTableSlot StructTupleTableSlot;
HeapTupleTableSlot StructHeapTupleTableSlot;
MinimalTupleTableSlot StructMinimalTupleTableSlot;
TupleDescData StructTupleDescData;
PlanState StructPlanState;
MinimalTupleData StructMinimalTupleData;
llvmjit_types.c里面定义了一些类型的变量,这些变量的bitcode在初始化时(llvm_create_types),会加载到module中(llvm_types_module)。然后再通过llvm_pg_var_type函数,把类型读取出来保存到全局变量中:
static void
llvm_create_types(void)
{
...
snprintf(path, MAXPGPATH, "%s/%s", pkglib_path, "llvmjit_types.bc");
if (LLVMCreateMemoryBufferWithContentsOfFile(path, &buf, &msg))
...
if (LLVMParseBitcodeInContext2(llvm_context, buf, &llvm_types_module))
...
LLVMDisposeMemoryBuffer(buf);
TypeSizeT = llvm_pg_var_type("TypeSizeT");
TypeParamBool = load_return_type(llvm_types_module, "FunctionReturningBool");
TypeStorageBool = llvm_pg_var_type("TypeStorageBool");
TypePGFunction = llvm_pg_var_type("TypePGFunction");
StructNullableDatum = llvm_pg_var_type("StructNullableDatum");
StructExprContext = llvm_pg_var_type("StructExprContext");
StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
StructExprState = llvm_pg_var_type("StructExprState");
StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
StructMinimalTupleTableSlot = llvm_pg_var_type("StructMinimalTupleTableSlot");
StructHeapTupleData = llvm_pg_var_type("StructHeapTupleData");
StructHeapTupleHeaderData = llvm_pg_var_type("StructHeapTupleHeaderData");
StructTupleDescData = llvm_pg_var_type("StructTupleDescData");
StructAggState = llvm_pg_var_type("StructAggState");
StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
StructPlanState = llvm_pg_var_type("StructPlanState");
StructMinimalTupleData = llvm_pg_var_type("StructMinimalTupleData");
AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
ExecEvalSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalSubroutineTemplate");
ExecEvalBoolSubroutineTemplate = LLVMGetNamedFunction(llvm_types_module, "ExecEvalBoolSubroutineTemplate");
}
这样做可以很方便的同步类型定义,但这样无法同步结构体内变量的偏移量,只能把偏移量维护在结构体中了,所以我们会看到结构体中多了一些宏来表示成员变量的位置:
typedef struct TupleTableSlot
{
NodeTag type;
#define FIELDNO_TUPLETABLESLOT_FLAGS 1
uint16 tts_flags; /* Boolean states */
#define FIELDNO_TUPLETABLESLOT_NVALID 2
AttrNumber tts_nvalid; /* # of valid values in tts_values */
const TupleTableSlotOps *const tts_ops; /* implementation of slot */
#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
#define FIELDNO_TUPLETABLESLOT_VALUES 5
Datum *tts_values; /* current per-attribute values */
#define FIELDNO_TUPLETABLESLOT_ISNULL 6
bool *tts_isnull; /* current per-attribute isnull flags */
MemoryContext tts_mcxt; /* slot itself is in this context */
ItemPointerData tts_tid; /* stored tuple's tid */
Oid tts_tableOid; /* table oid of tuple */
} TupleTableSlot;
非JIT表达式计算EEOP_SCAN_FETCHSOME流程:
ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
TupleTableSlot *scanslot;
...
scanslot = econtext->ecxt_scantuple;
...
EEO_SWITCH()
{
...
EEO_CASE(EEOP_SCAN_FETCHSOME)
{
CheckOpSlotCompatibility(op, scanslot);
slot_getsomeattrs(scanslot, op->d.fetch.last_var);
EEO_NEXT();
}
...
}
JIT表达式计算EEOP_SCAN_FETCHSOME流程:
eval_fn = LLVMAddFunction(mod, funcname,
llvm_pg_var_func_type("ExecInterpExprStillValid"));
v_econtext = LLVMGetParam(eval_fn, 1);
LLVMValueRef v_scanslot;
scanslot = econtext->ecxt_scantuple;
从结构体中拿一个成员变量的值。
IR中的结构体是不会记录成员名称的,所以需要告知llvm成员变量在结构体中的偏移位置FIELDNO_EXPRCONTEXT_SCANTUPLE = 1。 /*
* l_load_struct_gep =
*
* LLVMBuildLoad(b,
* LLVMStructGetTypeAtIndex(StructExprContext, 1),
* LLVMBuildStructGEP(b, StructExprContext, v_econtext, 1, "")
* "v_scanslot")
*/
v_scanslot = l_load_struct_gep(b,
StructExprContext,
v_econtext,
FIELDNO_EXPRCONTEXT_SCANTUPLE,
"v_scanslot");
...
case EEOP_SCAN_FETCHSOME:
{
TupleDesc desc = NULL;
LLVMValueRef v_slot;
LLVMBasicBlockRef b_fetch;
LLVMValueRef v_nvalid;
LLVMValueRef l_jit_deform = NULL;
const TupleTableSlotOps *tts_ops = NULL;
if (v_nvalid >= op->d.fetch.last_var) // 跳转到下一个case的Block:opblocks[opno + 1]
else // 继续执行 当前Block 中的代码
b_fetch = l_bb_before_v(opblocks[opno + 1],
"op.%d.fetch", opno);
v_slot = v_scanslot;
v_nvalid =
l_load_struct_gep(b,
StructTupleTableSlot,
v_slot,
FIELDNO_TUPLETABLESLOT_NVALID,
"");
LLVMBuildCondBr(b,
LLVMBuildICmp(b, LLVMIntUGE, v_nvalid,
l_int16_const(lc, op->d.fetch.last_var),
""),
opblocks[opno + 1], b_fetch);
LLVMPositionBuilderAtEnd(b, b_fetch);
{
LLVMValueRef params[2];
params[0] = v_slot;
params[1] = l_int32_const(lc, op->d.fetch.last_var);
slot_getsomeattrs(scanslot, op->d.fetch.last_var);
/*
* API调用:
* LLVMBuildCall2(
* b,
* LLVMGetFunctionType(LLVMGetNamedFunction(llvm_types_module, "slot_getsomeattrs_int")),
* LLVMAddFunction(mod, "slot_getsomeattrs_int", LLVMGetFunctionType(LLVMGetNamedFunction(llvm_types_module, "slot_getsomeattrs_int"))),
* params,
* 2,
* "");
*/
l_call(b,
llvm_pg_var_func_type("slot_getsomeattrs_int"),
llvm_pg_func(mod, "slot_getsomeattrs_int"),
params, lengthof(params), "");
}
LLVMBuildBr(b, opblocks[opno + 1]);
break;
}
v_fn = LLVMAddFunction(mod, funcname, LLVMGetFunctionType(AttributeTemplate));
下面看下AttributeTemplate有哪些属性:(llvmjit_types.ll)
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable
define dso_local i64 @AttributeTemplate(ptr nocapture noundef writeonly %0) local_unnamed_addr #0 {
%2 = getelementptr inbounds %struct.FunctionCallInfoBaseData, ptr %0, i64 0, i32 4
store i8 1, ptr %2, align 4
ret i64 0
}
可以看到函数的属性:
函数参数的属性:
在构造表达式计算函数时,使用llvm_copy_attributes将AttributeTemplate函数的属性拷贝到了表达式计算函数上面:【AttributeTemplate属性】 → 【evalexpr_3_0属性】
llvm_compile_expr
/* create function */
eval_fn = LLVMAddFunction(mod, funcname,
llvm_pg_var_func_type("ExecInterpExprStillValid"));
...
...
llvm_copy_attributes(AttributeTemplate, eval_fn);
拷贝后的evalexpr_3_0函数,可以看到函数属性和参数属性都已经和AttributeTemplate一致的:
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable
define i64 @evalexpr_3_0(ptr nocapture noundef writeonly %0, ptr %1, ptr %2) #0 {
entry:
void *referenced_functions[] =
{
ExecAggInitGroup,
ExecAggCopyTransValue,
...
ExecEvalJsonCoercionFinish,
ExecEvalJsonExprPath,
MakeExpandedObjectReadOnlyInternal,
slot_getmissingattrs,
slot_getsomeattrs_int,
strlen,
varsize_any,
ExecInterpExprStillValid,
};
这些函数是所有llvmjit会用到的函数,这里用数组引用后,会在llvmjit_types.bc文件中生成引用信息:
^45 = gv: (name: "ExecEvalSubPlan") ; guid = 11106370218607637427
^46 = gv: (name: "ExecEvalCurrentOfExpr") ; guid = 11138569114739303931
^47 = gv: (name: "slot_getsomeattrs_int") ; guid = 11630412520694092271
^48 = gv: (name: "MakeExpandedObjectReadOnlyInternal") ; guid = 11922486409292019551
^49 = gv: (name: "ExecEvalFieldStoreDeForm") ; guid = 11938814657973506909
在使用llvm调用函数时,可以从这里找到函数类型,用LLVMAddFunction增加函数声明到mod中。
LLVMValueRef
llvm_pg_func(LLVMModuleRef mod, const char *funcname)
...
v_srcfn = LLVMGetNamedFunction(llvm_types_module, funcname);
...
v_fn = LLVMAddFunction(mod,
funcname,
LLVMGetFunctionType(v_srcfn));
...
return v_fn;
}