Skip to content

Commit f7cfbc0

Browse files
committed
Add algebraic simplification to peephole optimizer
This implements mathematical identity patterns on register operands: - Self-subtraction: x - x → 0 - Self-XOR: x ^ x → 0 - Self-OR: x | x → x (identity) - Self-AND: x & x → x (identity) These patterns emerge after register allocation when different variables are assigned to the same register. SSA handles constant folding, peephole handles register-based patterns.
1 parent 7c7d34d commit f7cfbc0

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

src/peephole.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,77 @@ bool eliminate_load_store_pairs(ph2_ir_t *ph2_ir)
530530
return false;
531531
}
532532

533+
/* Algebraic simplification: Apply mathematical identities to simplify
534+
* expressions
535+
*
536+
* This function handles patterns that SSA cannot see:
537+
* - Self-operations on registers (x-x, x^x, x|x, x&x)
538+
* - These patterns emerge after register allocation when different
539+
* variables are assigned to the same register
540+
*
541+
* SSA handles: Constant folding with known values (5+3 → 8)
542+
* Peephole handles: Register-based patterns (r1-r1 → 0)
543+
*
544+
* Returns true if optimization was applied
545+
*/
546+
bool algebraic_simplification(ph2_ir_t *ph2_ir)
547+
{
548+
if (!ph2_ir)
549+
return false;
550+
551+
/* NOTE: SSA's const_folding handles constant operations with known values.
552+
* We focus on register-based patterns that appear after register
553+
* allocation.
554+
*/
555+
556+
/* Pattern 1: Self-subtraction → 0
557+
* x - x = 0 (for register operands)
558+
*/
559+
if (ph2_ir->op == OP_sub && ph2_ir->src0 == ph2_ir->src1) {
560+
ph2_ir->op = OP_load_constant;
561+
ph2_ir->src0 = 0; /* result is 0 */
562+
ph2_ir->src1 = 0; /* clear unused field */
563+
return true;
564+
}
565+
566+
/* Pattern 2: Self-XOR → 0
567+
* x ^ x = 0 (for register operands)
568+
*/
569+
if (ph2_ir->op == OP_bit_xor && ph2_ir->src0 == ph2_ir->src1) {
570+
ph2_ir->op = OP_load_constant;
571+
ph2_ir->src0 = 0; /* result is 0 */
572+
ph2_ir->src1 = 0; /* clear unused field */
573+
return true;
574+
}
575+
576+
/* Pattern 3: Self-OR → x
577+
* x | x = x (identity operation for register operands)
578+
*/
579+
if (ph2_ir->op == OP_bit_or && ph2_ir->src0 == ph2_ir->src1) {
580+
ph2_ir->op = OP_assign;
581+
/* src0 already contains x, just need to move it */
582+
ph2_ir->src1 = 0; /* clear unused field */
583+
return true;
584+
}
585+
586+
/* Pattern 4: Self-AND → x
587+
* x & x = x (identity operation for register operands)
588+
*/
589+
if (ph2_ir->op == OP_bit_and && ph2_ir->src0 == ph2_ir->src1) {
590+
ph2_ir->op = OP_assign;
591+
/* src0 already contains x, just need to move it */
592+
ph2_ir->src1 = 0; /* clear unused field */
593+
return true;
594+
}
595+
596+
/* NOTE: Arithmetic identity patterns (x+0, x*1, x*0, x-0) are already
597+
* handled by SSA's const_folding() function and insn_fusion().
598+
* We focus on register-level patterns that SSA cannot see.
599+
*/
600+
601+
return false;
602+
}
603+
533604
/* Main peephole optimization driver.
534605
* It iterates through all functions, basic blocks, and IR instructions to apply
535606
* local optimizations on adjacent instruction pairs.

0 commit comments

Comments
 (0)