Skip to content

Commit 136ab7c

Browse files
committed
Marginal improvement for generated code in execExprInterp.c.
Avoid the coding pattern "*op->resvalue = f();", as some compilers think that requires them to evaluate "op->resvalue" before the function call. Unless there are lots of free registers, this can lead to a useless register spill and reload across the call. I changed all the cases like this in ExecInterpExpr(), but didn't bother in the out-of-line opcode eval subroutines, since those are presumably not as performance-critical. Discussion: https://postgr.es/m/2508.1506630094@sss.pgh.pa.us
1 parent 5373bc2 commit 136ab7c

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -501,47 +501,53 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
501501
EEO_CASE(EEOP_INNER_SYSVAR)
502502
{
503503
int attnum = op->d.var.attnum;
504+
Datum d;
504505

505506
/* these asserts must match defenses in slot_getattr */
506507
Assert(innerslot->tts_tuple != NULL);
507508
Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr));
508-
/* heap_getsysattr has sufficient defenses against bad attnums */
509509

510-
*op->resvalue = heap_getsysattr(innerslot->tts_tuple, attnum,
511-
innerslot->tts_tupleDescriptor,
512-
op->resnull);
510+
/* heap_getsysattr has sufficient defenses against bad attnums */
511+
d = heap_getsysattr(innerslot->tts_tuple, attnum,
512+
innerslot->tts_tupleDescriptor,
513+
op->resnull);
514+
*op->resvalue = d;
513515

514516
EEO_NEXT();
515517
}
516518

517519
EEO_CASE(EEOP_OUTER_SYSVAR)
518520
{
519521
int attnum = op->d.var.attnum;
522+
Datum d;
520523

521524
/* these asserts must match defenses in slot_getattr */
522525
Assert(outerslot->tts_tuple != NULL);
523526
Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr));
524527

525528
/* heap_getsysattr has sufficient defenses against bad attnums */
526-
*op->resvalue = heap_getsysattr(outerslot->tts_tuple, attnum,
527-
outerslot->tts_tupleDescriptor,
528-
op->resnull);
529+
d = heap_getsysattr(outerslot->tts_tuple, attnum,
530+
outerslot->tts_tupleDescriptor,
531+
op->resnull);
532+
*op->resvalue = d;
529533

530534
EEO_NEXT();
531535
}
532536

533537
EEO_CASE(EEOP_SCAN_SYSVAR)
534538
{
535539
int attnum = op->d.var.attnum;
540+
Datum d;
536541

537542
/* these asserts must match defenses in slot_getattr */
538543
Assert(scanslot->tts_tuple != NULL);
539544
Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr));
540-
/* heap_getsysattr has sufficient defenses against bad attnums */
541545

542-
*op->resvalue = heap_getsysattr(scanslot->tts_tuple, attnum,
543-
scanslot->tts_tupleDescriptor,
544-
op->resnull);
546+
/* heap_getsysattr has sufficient defenses against bad attnums */
547+
d = heap_getsysattr(scanslot->tts_tuple, attnum,
548+
scanslot->tts_tupleDescriptor,
549+
op->resnull);
550+
*op->resvalue = d;
545551

546552
EEO_NEXT();
547553
}
@@ -641,13 +647,22 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
641647
* As both STRICT checks and function-usage are noticeable performance
642648
* wise, and function calls are a very hot-path (they also back
643649
* operators!), it's worth having so many separate opcodes.
650+
*
651+
* Note: the reason for using a temporary variable "d", here and in
652+
* other places, is that some compilers think "*op->resvalue = f();"
653+
* requires them to evaluate op->resvalue into a register before
654+
* calling f(), just in case f() is able to modify op->resvalue
655+
* somehow. The extra line of code can save a useless register spill
656+
* and reload across the function call.
644657
*/
645658
EEO_CASE(EEOP_FUNCEXPR)
646659
{
647660
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
661+
Datum d;
648662

649663
fcinfo->isnull = false;
650-
*op->resvalue = op->d.func.fn_addr(fcinfo);
664+
d = op->d.func.fn_addr(fcinfo);
665+
*op->resvalue = d;
651666
*op->resnull = fcinfo->isnull;
652667

653668
EEO_NEXT();
@@ -658,6 +673,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
658673
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
659674
bool *argnull = fcinfo->argnull;
660675
int argno;
676+
Datum d;
661677

662678
/* strict function, so check for NULL args */
663679
for (argno = 0; argno < op->d.func.nargs; argno++)
@@ -669,7 +685,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
669685
}
670686
}
671687
fcinfo->isnull = false;
672-
*op->resvalue = op->d.func.fn_addr(fcinfo);
688+
d = op->d.func.fn_addr(fcinfo);
689+
*op->resvalue = d;
673690
*op->resnull = fcinfo->isnull;
674691

675692
strictfail:
@@ -680,11 +697,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
680697
{
681698
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
682699
PgStat_FunctionCallUsage fcusage;
700+
Datum d;
683701

684702
pgstat_init_function_usage(fcinfo, &fcusage);
685703

686704
fcinfo->isnull = false;
687-
*op->resvalue = op->d.func.fn_addr(fcinfo);
705+
d = op->d.func.fn_addr(fcinfo);
706+
*op->resvalue = d;
688707
*op->resnull = fcinfo->isnull;
689708

690709
pgstat_end_function_usage(&fcusage, true);
@@ -698,6 +717,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
698717
PgStat_FunctionCallUsage fcusage;
699718
bool *argnull = fcinfo->argnull;
700719
int argno;
720+
Datum d;
701721

702722
/* strict function, so check for NULL args */
703723
for (argno = 0; argno < op->d.func.nargs; argno++)
@@ -712,7 +732,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
712732
pgstat_init_function_usage(fcinfo, &fcusage);
713733

714734
fcinfo->isnull = false;
715-
*op->resvalue = op->d.func.fn_addr(fcinfo);
735+
d = op->d.func.fn_addr(fcinfo);
736+
*op->resvalue = d;
716737
*op->resnull = fcinfo->isnull;
717738

718739
pgstat_end_function_usage(&fcusage, true);
@@ -1113,14 +1134,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
11131134
if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
11141135
{
11151136
FunctionCallInfo fcinfo_in;
1137+
Datum d;
11161138

11171139
fcinfo_in = op->d.iocoerce.fcinfo_data_in;
11181140
fcinfo_in->arg[0] = PointerGetDatum(str);
11191141
fcinfo_in->argnull[0] = *op->resnull;
11201142
/* second and third arguments are already set up */
11211143

11221144
fcinfo_in->isnull = false;
1123-
*op->resvalue = FunctionCallInvoke(fcinfo_in);
1145+
d = FunctionCallInvoke(fcinfo_in);
1146+
*op->resvalue = d;
11241147

11251148
/* Should get null result if and only if str is NULL */
11261149
if (str == NULL)
@@ -1268,6 +1291,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
12681291
EEO_CASE(EEOP_ROWCOMPARE_STEP)
12691292
{
12701293
FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
1294+
Datum d;
12711295

12721296
/* force NULL result if strict fn and NULL input */
12731297
if (op->d.rowcompare_step.finfo->fn_strict &&
@@ -1279,7 +1303,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
12791303

12801304
/* Apply comparison function */
12811305
fcinfo->isnull = false;
1282-
*op->resvalue = op->d.rowcompare_step.fn_addr(fcinfo);
1306+
d = op->d.rowcompare_step.fn_addr(fcinfo);
1307+
*op->resvalue = d;
12831308

12841309
/* force NULL result if NULL function result */
12851310
if (fcinfo->isnull)

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