Skip to content

Commit e6f86f8

Browse files
committed
jit: Remove redundancies in expression evaluation code generation.
This merges the code emission for a number of opcodes by handling the behavioural difference more locally. This reduces code, and also improves the generated code a bit in some cases, by removing redundant constants. Author: Andres Freund Discussion: https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de
1 parent 8c27694 commit e6f86f8

File tree

1 file changed

+124
-153
lines changed

1 file changed

+124
-153
lines changed

src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 124 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ llvm_compile_expr(ExprState *state)
471471
}
472472

473473
case EEOP_ASSIGN_TMP:
474+
case EEOP_ASSIGN_TMP_MAKE_RO:
474475
{
475476
LLVMValueRef v_value,
476477
v_isnull;
@@ -490,59 +491,40 @@ llvm_compile_expr(ExprState *state)
490491
v_risnullp =
491492
LLVMBuildGEP(b, v_resultnulls, &v_resultnum, 1, "");
492493

493-
/* and store */
494-
LLVMBuildStore(b, v_value, v_rvaluep);
494+
/* store nullness */
495495
LLVMBuildStore(b, v_isnull, v_risnullp);
496496

497-
LLVMBuildBr(b, opblocks[opno + 1]);
498-
break;
499-
}
500-
501-
case EEOP_ASSIGN_TMP_MAKE_RO:
502-
{
503-
LLVMBasicBlockRef b_notnull;
504-
LLVMValueRef v_params[1];
505-
LLVMValueRef v_ret;
506-
LLVMValueRef v_value,
507-
v_isnull;
508-
LLVMValueRef v_rvaluep,
509-
v_risnullp;
510-
LLVMValueRef v_resultnum;
511-
size_t resultnum = op->d.assign_tmp.resultnum;
512-
513-
b_notnull = l_bb_before_v(opblocks[opno + 1],
514-
"op.%d.assign_tmp.notnull", opno);
515-
516-
/* load data */
517-
v_value = LLVMBuildLoad(b, v_tmpvaluep, "");
518-
v_isnull = LLVMBuildLoad(b, v_tmpisnullp, "");
519-
520-
/* compute addresses of targets */
521-
v_resultnum = l_int32_const(resultnum);
522-
v_rvaluep = LLVMBuildGEP(b, v_resultvalues,
523-
&v_resultnum, 1, "");
524-
v_risnullp = LLVMBuildGEP(b, v_resultnulls,
525-
&v_resultnum, 1, "");
497+
/* make value readonly if necessary */
498+
if (opcode == EEOP_ASSIGN_TMP_MAKE_RO)
499+
{
500+
LLVMBasicBlockRef b_notnull;
501+
LLVMValueRef v_params[1];
526502

527-
/* store nullness */
528-
LLVMBuildStore(b, v_isnull, v_risnullp);
503+
b_notnull = l_bb_before_v(opblocks[opno + 1],
504+
"op.%d.assign_tmp.notnull", opno);
529505

530-
/* check if value is NULL */
531-
LLVMBuildCondBr(b,
532-
LLVMBuildICmp(b, LLVMIntEQ, v_isnull,
533-
l_sbool_const(0), ""),
534-
b_notnull, opblocks[opno + 1]);
506+
/* check if value is NULL */
507+
LLVMBuildCondBr(b,
508+
LLVMBuildICmp(b, LLVMIntEQ, v_isnull,
509+
l_sbool_const(0), ""),
510+
b_notnull, opblocks[opno + 1]);
511+
512+
/* if value is not null, convert to RO datum */
513+
LLVMPositionBuilderAtEnd(b, b_notnull);
514+
v_params[0] = v_value;
515+
v_value =
516+
LLVMBuildCall(b,
517+
llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal),
518+
v_params, lengthof(v_params), "");
535519

536-
/* if value is not null, convert to RO datum */
537-
LLVMPositionBuilderAtEnd(b, b_notnull);
538-
v_params[0] = v_value;
539-
v_ret =
540-
LLVMBuildCall(b,
541-
llvm_get_decl(mod, FuncMakeExpandedObjectReadOnlyInternal),
542-
v_params, lengthof(v_params), "");
520+
/*
521+
* Falling out of the if () with builder in b_notnull,
522+
* which is fine - the null is already stored above.
523+
*/
524+
}
543525

544-
/* store value */
545-
LLVMBuildStore(b, v_ret, v_rvaluep);
526+
/* and finally store result */
527+
LLVMBuildStore(b, v_value, v_rvaluep);
546528

547529
LLVMBuildBr(b, opblocks[opno + 1]);
548530
break;
@@ -563,78 +545,81 @@ llvm_compile_expr(ExprState *state)
563545
break;
564546
}
565547

548+
case EEOP_FUNCEXPR:
566549
case EEOP_FUNCEXPR_STRICT:
567550
{
568551
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
569-
LLVMBasicBlockRef b_nonull;
570-
LLVMValueRef v_fcinfo;
571-
LLVMBasicBlockRef *b_checkargnulls;
572-
573-
/*
574-
* Block for the actual function call, if args are
575-
* non-NULL.
576-
*/
577-
b_nonull = l_bb_before_v(opblocks[opno + 1],
578-
"b.%d.no-null-args", opno);
552+
LLVMValueRef v_fcinfo_isnull;
553+
LLVMValueRef v_retval;
579554

580-
/* should make sure they're optimized beforehand */
581-
if (op->d.func.nargs == 0)
582-
elog(ERROR, "argumentless strict functions are pointless");
555+
if (opcode == EEOP_FUNCEXPR_STRICT)
556+
{
557+
LLVMBasicBlockRef b_nonull;
558+
LLVMBasicBlockRef *b_checkargnulls;
559+
LLVMValueRef v_fcinfo;
583560

584-
v_fcinfo =
585-
l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
561+
/*
562+
* Block for the actual function call, if args are
563+
* non-NULL.
564+
*/
565+
b_nonull = l_bb_before_v(opblocks[opno + 1],
566+
"b.%d.no-null-args", opno);
586567

587-
/*
588-
* set resnull to true, if the function is actually
589-
* called, it'll be reset
590-
*/
591-
LLVMBuildStore(b, l_sbool_const(1), v_resnullp);
568+
/* should make sure they're optimized beforehand */
569+
if (op->d.func.nargs == 0)
570+
elog(ERROR, "argumentless strict functions are pointless");
592571

593-
/* create blocks for checking args, one for each */
594-
b_checkargnulls =
595-
palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
596-
for (int argno = 0; argno < op->d.func.nargs; argno++)
597-
b_checkargnulls[argno] =
598-
l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno, argno);
572+
v_fcinfo =
573+
l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
599574

600-
/* jump to check of first argument */
601-
LLVMBuildBr(b, b_checkargnulls[0]);
575+
/*
576+
* set resnull to true, if the function is actually
577+
* called, it'll be reset
578+
*/
579+
LLVMBuildStore(b, l_sbool_const(1), v_resnullp);
602580

603-
/* check each arg for NULLness */
604-
for (int argno = 0; argno < op->d.func.nargs; argno++)
605-
{
606-
LLVMValueRef v_argisnull;
607-
LLVMBasicBlockRef b_argnotnull;
581+
/* create blocks for checking args, one for each */
582+
b_checkargnulls =
583+
palloc(sizeof(LLVMBasicBlockRef *) * op->d.func.nargs);
584+
for (int argno = 0; argno < op->d.func.nargs; argno++)
585+
b_checkargnulls[argno] =
586+
l_bb_before_v(b_nonull, "b.%d.isnull.%d", opno,
587+
argno);
608588

609-
LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]);
589+
/* jump to check of first argument */
590+
LLVMBuildBr(b, b_checkargnulls[0]);
610591

611-
/* compute block to jump to if argument is not null */
612-
if (argno + 1 == op->d.func.nargs)
613-
b_argnotnull = b_nonull;
614-
else
615-
b_argnotnull = b_checkargnulls[argno + 1];
592+
/* check each arg for NULLness */
593+
for (int argno = 0; argno < op->d.func.nargs; argno++)
594+
{
595+
LLVMValueRef v_argisnull;
596+
LLVMBasicBlockRef b_argnotnull;
597+
598+
LLVMPositionBuilderAtEnd(b, b_checkargnulls[argno]);
599+
600+
/*
601+
* Compute block to jump to if argument is not
602+
* null.
603+
*/
604+
if (argno + 1 == op->d.func.nargs)
605+
b_argnotnull = b_nonull;
606+
else
607+
b_argnotnull = b_checkargnulls[argno + 1];
608+
609+
/* and finally load & check NULLness of arg */
610+
v_argisnull = l_funcnull(b, v_fcinfo, argno);
611+
LLVMBuildCondBr(b,
612+
LLVMBuildICmp(b, LLVMIntEQ,
613+
v_argisnull,
614+
l_sbool_const(1),
615+
""),
616+
opblocks[opno + 1],
617+
b_argnotnull);
618+
}
616619

617-
/* and finally load & check NULLness of arg */
618-
v_argisnull = l_funcnull(b, v_fcinfo, argno);
619-
LLVMBuildCondBr(b,
620-
LLVMBuildICmp(b, LLVMIntEQ,
621-
v_argisnull,
622-
l_sbool_const(1),
623-
""),
624-
opblocks[opno + 1],
625-
b_argnotnull);
620+
LLVMPositionBuilderAtEnd(b, b_nonull);
626621
}
627622

628-
LLVMPositionBuilderAtEnd(b, b_nonull);
629-
}
630-
/* FALLTHROUGH */
631-
632-
case EEOP_FUNCEXPR:
633-
{
634-
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
635-
LLVMValueRef v_fcinfo_isnull;
636-
LLVMValueRef v_retval;
637-
638623
v_retval = BuildV1Call(context, b, mod, fcinfo,
639624
&v_fcinfo_isnull);
640625
LLVMBuildStore(b, v_retval, v_resvaluep);
@@ -657,24 +642,14 @@ llvm_compile_expr(ExprState *state)
657642
LLVMBuildBr(b, opblocks[opno + 1]);
658643
break;
659644

660-
case EEOP_BOOL_AND_STEP_FIRST:
661-
{
662-
LLVMValueRef v_boolanynullp;
663-
664-
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
665-
l_ptr(TypeStorageBool));
666-
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
667-
668-
}
669-
/* FALLTHROUGH */
670-
671645
/*
672646
* Treat them the same for now, optimizer can remove
673647
* redundancy. Could be worthwhile to optimize during emission
674648
* though.
675649
*/
676-
case EEOP_BOOL_AND_STEP_LAST:
650+
case EEOP_BOOL_AND_STEP_FIRST:
677651
case EEOP_BOOL_AND_STEP:
652+
case EEOP_BOOL_AND_STEP_LAST:
678653
{
679654
LLVMValueRef v_boolvalue;
680655
LLVMValueRef v_boolnull;
@@ -700,6 +675,9 @@ llvm_compile_expr(ExprState *state)
700675
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
701676
l_ptr(TypeStorageBool));
702677

678+
if (opcode == EEOP_BOOL_AND_STEP_FIRST)
679+
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
680+
703681
v_boolnull = LLVMBuildLoad(b, v_resnullp, "");
704682
v_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
705683

@@ -759,23 +737,15 @@ llvm_compile_expr(ExprState *state)
759737
LLVMBuildBr(b, opblocks[opno + 1]);
760738
break;
761739
}
762-
case EEOP_BOOL_OR_STEP_FIRST:
763-
{
764-
LLVMValueRef v_boolanynullp;
765-
766-
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
767-
l_ptr(TypeStorageBool));
768-
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
769-
}
770-
/* FALLTHROUGH */
771740

772741
/*
773742
* Treat them the same for now, optimizer can remove
774743
* redundancy. Could be worthwhile to optimize during emission
775744
* though.
776745
*/
777-
case EEOP_BOOL_OR_STEP_LAST:
746+
case EEOP_BOOL_OR_STEP_FIRST:
778747
case EEOP_BOOL_OR_STEP:
748+
case EEOP_BOOL_OR_STEP_LAST:
779749
{
780750
LLVMValueRef v_boolvalue;
781751
LLVMValueRef v_boolnull;
@@ -802,6 +772,8 @@ llvm_compile_expr(ExprState *state)
802772
v_boolanynullp = l_ptr_const(op->d.boolexpr.anynull,
803773
l_ptr(TypeStorageBool));
804774

775+
if (opcode == EEOP_BOOL_OR_STEP_FIRST)
776+
LLVMBuildStore(b, l_sbool_const(0), v_boolanynullp);
805777
v_boolnull = LLVMBuildLoad(b, v_resnullp, "");
806778
v_boolvalue = LLVMBuildLoad(b, v_resvaluep, "");
807779

@@ -1958,41 +1930,40 @@ llvm_compile_expr(ExprState *state)
19581930
break;
19591931

19601932
case EEOP_AGG_STRICT_DESERIALIZE:
1961-
{
1962-
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
1963-
LLVMValueRef v_fcinfo;
1964-
LLVMValueRef v_argnull0;
1965-
LLVMBasicBlockRef b_deserialize;
1966-
1967-
b_deserialize = l_bb_before_v(opblocks[opno + 1],
1968-
"op.%d.deserialize", opno);
1969-
1970-
v_fcinfo = l_ptr_const(fcinfo,
1971-
l_ptr(StructFunctionCallInfoData));
1972-
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
1973-
1974-
LLVMBuildCondBr(b,
1975-
LLVMBuildICmp(b,
1976-
LLVMIntEQ,
1977-
v_argnull0,
1978-
l_sbool_const(1),
1979-
""),
1980-
opblocks[op->d.agg_deserialize.jumpnull],
1981-
b_deserialize);
1982-
LLVMPositionBuilderAtEnd(b, b_deserialize);
1983-
}
1984-
/* FALLTHROUGH */
1985-
19861933
case EEOP_AGG_DESERIALIZE:
19871934
{
19881935
AggState *aggstate;
1989-
FunctionCallInfo fcinfo;
1936+
FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
19901937

19911938
LLVMValueRef v_retval;
19921939
LLVMValueRef v_fcinfo_isnull;
19931940
LLVMValueRef v_tmpcontext;
19941941
LLVMValueRef v_oldcontext;
19951942

1943+
if (opcode == EEOP_AGG_STRICT_DESERIALIZE)
1944+
{
1945+
LLVMValueRef v_fcinfo;
1946+
LLVMValueRef v_argnull0;
1947+
LLVMBasicBlockRef b_deserialize;
1948+
1949+
b_deserialize = l_bb_before_v(opblocks[opno + 1],
1950+
"op.%d.deserialize", opno);
1951+
1952+
v_fcinfo = l_ptr_const(fcinfo,
1953+
l_ptr(StructFunctionCallInfoData));
1954+
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
1955+
1956+
LLVMBuildCondBr(b,
1957+
LLVMBuildICmp(b,
1958+
LLVMIntEQ,
1959+
v_argnull0,
1960+
l_sbool_const(1),
1961+
""),
1962+
opblocks[op->d.agg_deserialize.jumpnull],
1963+
b_deserialize);
1964+
LLVMPositionBuilderAtEnd(b, b_deserialize);
1965+
}
1966+
19961967
aggstate = castNode(AggState, state->parent);
19971968
fcinfo = op->d.agg_deserialize.fcinfo_data;
19981969

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy