Skip to content

Commit 3c24984

Browse files
committed
Add strength reduction optimizations to peephole
This implements power-of-2 strength reduction patterns: - Division by 2^n → right shift by n - Modulo by 2^n → bitwise AND with (2^n - 1) - Multiplication by 2^n → left shift by n This optimization is unique to peephole optimizer since SSA works on virtual registers before actual constants are loaded.
1 parent f7cfbc0 commit 3c24984

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

src/peephole.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,82 @@ bool algebraic_simplification(ph2_ir_t *ph2_ir)
601601
return false;
602602
}
603603

604+
/* Division/modulo strength reduction: Optimize division and modulo by
605+
* power-of-2
606+
*
607+
* This pattern is unique to peephole optimizer.
608+
* SSA cannot perform this optimization because it works on virtual registers
609+
* before actual constant values are loaded.
610+
*
611+
* Returns true if optimization was applied
612+
*/
613+
bool strength_reduction(ph2_ir_t *ph2_ir)
614+
{
615+
if (!ph2_ir || !ph2_ir->next)
616+
return false;
617+
618+
ph2_ir_t *next = ph2_ir->next;
619+
620+
/* Check for constant load followed by division or modulo */
621+
if (ph2_ir->op != OP_load_constant)
622+
return false;
623+
624+
int value = ph2_ir->src0;
625+
626+
/* Check if value is a power of 2 */
627+
if (value <= 0 || (value & (value - 1)) != 0)
628+
return false;
629+
630+
/* Calculate shift amount for power of 2 */
631+
int shift = 0;
632+
int tmp = value;
633+
while (tmp > 1) {
634+
shift++;
635+
tmp >>= 1;
636+
}
637+
638+
/* Pattern 1: Division by power of 2 → right shift
639+
* x / 2^n = x >> n (for unsigned)
640+
*/
641+
if (next->op == OP_div && next->src1 == ph2_ir->dest) {
642+
/* Convert division to right shift */
643+
ph2_ir->src0 = shift; /* Load shift amount instead */
644+
next->op = OP_rshift;
645+
return true;
646+
}
647+
648+
/* Pattern 2: Modulo by power of 2 → bitwise AND
649+
* x % 2^n = x & (2^n - 1)
650+
*/
651+
if (next->op == OP_mod && next->src1 == ph2_ir->dest) {
652+
/* Convert modulo to bitwise AND */
653+
ph2_ir->src0 = value - 1; /* Load mask (2^n - 1) */
654+
next->op = OP_bit_and;
655+
return true;
656+
}
657+
658+
/* Pattern 3: Multiplication by power of 2 → left shift
659+
* x * 2^n = x << n
660+
*/
661+
if (next->op == OP_mul) {
662+
if (next->src0 == ph2_ir->dest) {
663+
/* 2^n * x = x << n */
664+
ph2_ir->src0 = shift; /* Load shift amount */
665+
next->op = OP_lshift;
666+
next->src0 = next->src1; /* Move x to src0 */
667+
next->src1 = ph2_ir->dest; /* Shift amount in src1 */
668+
return true;
669+
} else if (next->src1 == ph2_ir->dest) {
670+
/* x * 2^n = x << n */
671+
ph2_ir->src0 = shift; /* Load shift amount */
672+
next->op = OP_lshift;
673+
return true;
674+
}
675+
}
676+
677+
return false;
678+
}
679+
604680
/* Main peephole optimization driver.
605681
* It iterates through all functions, basic blocks, and IR instructions to apply
606682
* local optimizations on adjacent instruction pairs.

0 commit comments

Comments
 (0)