मुख्य कंटेंट तक स्किप करें

अल्जेब्रिक सिम्प्लिफ़िकेशन पैटर्न

Morok का symbolic simplifier UOp computation graphs को 140+ अल्जेब्रिक पैटर्न से रीराइट करता है, जो schedule/src/symbolic/patterns.rs में डिफ़ाइन हैं। ये पैटर्न पाइपलाइन में कई जगह फ़ायर होते हैं:

कहाँMatcherContext
Pre-optimizationsymbolic()Rangeify + range splitting के बाद, कर्नेल ऑप्टिमाइज़ेशन से पहले
Post-opt (Stage 8)symbolic()ऑप्टिमाइज़ेशन actions के बाद, expansion से पहले
Post-index (Stage 16)symbolic()Index dtype lowering के बाद, फ़ाइनल cleanup
Decomp+Render (Stage 18-19)symbolic_simple()Late rewrites और render पैटर्न के साथ combined

symbolic() = symbolic_simple() + GEP pushing पैटर्न। फ़ाइनल decomp+render पास के अलावा सभी stages फ़ुल symbolic() सेट चलाते हैं।

Range analysis: हर UOp अपनी runtime minimum (vmin) और maximum (vmax) वैल्यूज़ ट्रैक करता है, जो नोड construction के दौरान inputs के bounds से eagerly कम्प्यूट होती हैं। कई पैटर्न इन bounds का इस्तेमाल करते हैं compile time पर conditions prove करने के लिए (जैसे, "x हमेशा non-negative है" या "x < n सभी values के लिए")।

Notation: OP[a, b] commutative पैटर्न है (दोनों operand orderings ट्राई होती हैं)। OP(a, b) ordered है। @zero/@one/@const constant values मैच करते हैं। जब एक ही variable name दो बार आए (जैसे, Idiv(x, x)), दोनों operands एक ही नोड होने चाहिए (Arc::ptr_eq — यानी hash consing से structurally deduplicated)।

Tinygrad reference: tinygrad/uop/symbolic.py, tinygrad/uop/divandmod.py


Worked Example: ऑप्टिमाइज़ेशन कैस्केड

एक सिम्पल एक्सप्रेशन जो दिखाता है कि पैटर्न कैसे compose होते हैं:

Before:
ADD
├── MUL
│ ├── ADD
│ │ ├── x
│ │ └── CONST(0) <- identity
│ └── CONST(1) <- identity
└── ADD
├── CONST(3)
└── CONST(4) <- constant fold

Step 1 (identity): ADD(x, 0) -> x
Step 2 (identity): MUL(x, 1) -> x
Step 3 (const fold): ADD(3, 4) -> CONST(7)
Step 4 (result): ADD(x, 7)

After:
ADD
├── x
└── CONST(7)

रीराइट इंजन पैटर्न bottom-up अप्लाई करता है: पहले children सिम्प्लिफ़ाई होते हैं, फिर parent री-मैच करता है। यह सिंगल traversal में मल्टी-स्टेप cascades सक्षम करता है।


पैटर्न ऑर्डरिंग

symbolic_simple() matcher पैटर्न ग्रुप्स को एक स्पेसिफ़िक ऑर्डर में compose करता है। एक ग्रुप के अंदर, पैटर्न sequentially ट्राई होते हैं जब तक कोई मैच न हो। ग्रुप्स + ऑपरेटर से concatenate होते हैं:

propagate_invalid -- MUST be first (before x*0=0)
fold_invalid_load_store
constant_folding_dsl_patterns
vconst_folding_patterns
identity_and_zero_patterns
commutative_canonicalization
self_folding_dsl_patterns
zero_folding_dsl_patterns
division_dsl_patterns
cast_dsl_patterns
cast_where_dsl_patterns
term_combining_dsl_patterns
alu_folding_dsl_patterns
advanced_division_dsl_patterns
div_mod_recombine_dsl_patterns
comparison_dsl_patterns
boolean_dsl_patterns
minmax_dsl_patterns
where_bound_patterns
power_dsl_patterns
negation_dsl_patterns
range_based_mod_div_patterns
dce_dsl_patterns
dead_loop_patterns
after_simplification_patterns
pm_move_where_on_load -- WHERE->INDEX embedding for masked loads

1. Constant Folding

Compile-time constants पर ऑपरेशन evaluate करता है dtype-aware arithmetic से। Results type boundaries respect करते हैं (जैसे, Int32 32 bits पर wrap करता है)।

Tinygrad: symbolic.py:40-118

Scalar Constants

कैटेगरीOpsपैटर्न
Unary (7)Neg, Sqrt, Exp2, Log2, Sin, Reciprocal, Truncop(CONST(c)) -> CONST(eval(op, c))
Binary (13)Add, Mul, Sub, Mod, Max, Pow, Idiv, Fdiv, And, Or, Xor, Shl, Shrop(CONST(a), CONST(b)) -> CONST(eval(op, a, b))
Ternary (2)Where, MulAccop(CONST(a), CONST(b), CONST(c)) -> CONST(eval(op, a, b, c))

Vector Constants

पैटर्नरिज़ल्ट
op(VCONST(a), VCONST(b))VCONST(eval(op, a, b)) element-wise
op(CONST(a), VCONST(b))VCONST(eval(op, broadcast(a), b))
op(VCONST(a), CONST(b))VCONST(eval(op, a, broadcast(b)))
unary_op(VCONST(v))VCONST(eval(op, v)) element-wise

VConst folding 11 binary ops कवर करता है (Pow और Fdiv exclude) और सभी 7 unary ops।


2. Identity और Zero Propagation

पैटर्नरिज़ल्टनोट्स
ADD[x, 0]xCommutative
MUL[x, 1]xCommutative
OR[x, 0]xCommutative
XOR[x, 0]xCommutative
SUB(x, 0)xOrdered
IDIV(x, 1)xOrdered
FDIV(x, 1)xOrdered
MOD(x, 1)0कुछ भी mod 1 ज़ीरो है
Floor/Ceil/Trunc/Round(x)xसिर्फ़ जब x integer हो (rounding no-op है)
MUL[x, 0]0सिर्फ़ जब float NOT हो
AND[_, 0]0Commutative

:::caution IEEE 754: MUL by zero MUL[x, 0] floats के लिए सिम्प्लिफ़ाई नहीं होता क्योंकि IEEE 754 require करता है:

  • NaN * 0 = NaN
  • Inf * 0 = NaN

गार्ड !x.dtype().is_float() floating-point types के लिए यह ऑप्टिमाइज़ेशन रोकता है। :::


3. Self-Folding

ऐसे पैटर्न जहाँ एक ही operand दोनों तरफ़ दिखता है। Arc::ptr_eq चेक इस्तेमाल करते हैं (hash consing गारंटी देता है कि structurally equal subexpressions एक ही pointer शेयर करते हैं)।

पैटर्नरिज़ल्टनोट्स
IDIV(x, x)1
IDIV(x, -1)NEG(x)RHS पर constant चेक
MOD(MOD(x, y), y)MOD(x, y)Idempotent mod
AND(x, x)x
OR(x, x)x

4. Zero Folding

पैटर्नरिज़ल्टनोट्स
MOD(x, x)0
LT(x, x)falseFloats के लिए NOT (NaN < NaN false है, लेकिन soundness के लिए गार्ड ज़रूरी)
NE(x, x)falseसिर्फ़ ints — IEEE 754 में NaN != NaN true है

5. Division सिम्प्लिफ़िकेशन

पैटर्नरिज़ल्टनोट्स
FDIV(0.0, 0.0)NaNIEEE 754 indeterminate form
FDIV(MUL[_, 0], 0)NaNकोई भी zero-expression / zero
FDIV(x, x)1.0Float self-division
FDIV(MUL(x, y), y)xCancellation (float)
IDIV(MUL(x, y), y)xCancellation (integer)

:::caution पैटर्न प्रायोरिटी FDIV(0, 0) -> NaN matcher में FDIV(x, x) -> 1 से पहले होना ज़रूरी ताकि priority ले सके। division_dsl_patterns() के अंदर ऑर्डरिंग यह ensure करता है। :::


6. Cast ऑप्टिमाइज़ेशन

पैटर्नरिज़ल्टनोट्स
CAST(CONST(c), dtype)CONST(c.cast(dtype))Compile-time cast folding
CAST(x, dtype)xजब x.dtype() == dtype (noop)
CAST(CAST(x, a), b)xजब x.dtype() == b और a b की सभी values preserve करे
CAST(CAST(x, a), b)CAST(x, b)जब a x को narrow न करे (widening chain)
CAST(WHERE(s, a, b), dtype)WHERE(s, CAST(a, dtype), CAST(b, dtype))Cast को branches से push करे

can_safe_cast(to, from) फ़ंक्शन determine करता है कि intermediate type सभी values hold कर सकता है या नहीं। यह bit widths, signedness, और float/int categories चेक करता है।

:::caution Truncation kills round-trips CAST(CAST(x, i8), i64) जब x i64 हो तो x में collapse नहीं होता। Intermediate i8 values truncate करता है — can_safe_cast(i64, i8) false रिटर्न करता है क्योंकि i8 सभी i64 values hold नहीं कर सकता।

सेफ़ example: CAST(CAST(x, i32), bool) -> CAST(x, bool) जब x bool हो, क्योंकि i32 true और false दोनों represent कर सकता है। :::


7. Term Combining

पैटर्नरिज़ल्ट
ADD(x, x)MUL(2, x)
ADD(MUL(c1, x), MUL(c2, x))MUL(c1+c2, x)
ADD(MUL(x, c1), MUL(x, c2))MUL(x, c1+c2)

दोनों ordered variants मैच होते हैं (MUL में constant left या right पर)।


8. ALU Chain Folding

Associative ऑपरेशन chains में constants fold करता है और canonical form के लिए constants बाहर push करता है।

Constant Folding

पैटर्नरिज़ल्टनोट्स
ADD[ADD[x, c1], c2]ADD(x, c1+c2)Commutative outer Add
MUL[MUL[x, c1], c2]MUL(x, c1*c2)Commutative outer Mul
ADD[SUB(x, c1), c2]ADD(x, c2-c1) या SUB(x, c1-c2)Sign-normalized
SUB(ADD(x, c1), c2)ADD(x, c1-c2) या SUB(x, c2-c1)Sign-normalized
SUB(SUB(x, c1), c2)SUB(x, c1+c2)

Constant Pushing

पैटर्नरिज़ल्टनोट्स
ADD[ADD[x, c], y]ADD(ADD(x, y), c)Constant बाहर push करे; y const नहीं होना चाहिए

Constant pushing index extraction के लिए ज़रूरी है। यह ensure करता है कि constants outermost level पर bubble हों, जिससे downstream पैटर्न (जैसे div-mod simplification) clean variable + offset forms देख सकें।

Sub Canonicalization

पैटर्नरिज़ल्टनोट्स
SUB(a, SUB(b, x))ADD(x, SUB(a, b))Inner variable expose करे

Morok SUB को first-class IR op रखता है (Tinygrad से अलग जो a-b को ADD(a, NEG(b)) में canonicalize करता है)। यह पैटर्न ensure करता है कि nested SUB आगे की simplification ब्लॉक न करें।


9. Boolean Logic

पैटर्नरिज़ल्टनोट्स
NOT(NOT(x))xDouble negation elimination
XOR(x, x)0Self-cancellation
OR[x, NOT(x)]trueTautology (सिर्फ़ bool)
AND[x, NOT(x)]falseContradiction (सिर्फ़ bool)
OR[true, x]trueAbsorbing element
AND[false, x]falseAbsorbing element
AND[true, x]xIdentity
OR[false, x]xIdentity
AND[NOT(x), NOT(y)]NOT(OR(x, y))De Morgan
OR[NOT(x), NOT(y)]NOT(AND(x, y))De Morgan

[] वाले सभी पैटर्न commutative हैं (दोनों operand orderings ट्राई होती हैं)।


10. Comparison सिम्प्लिफ़िकेशन

Self-Comparison (non-float, ptr_eq)

Opरिज़ल्ट
LT(x, x), GT(x, x), NE(x, x)false
LE(x, x), GE(x, x), EQ(x, x)true

:::caution Float self-comparison Self-comparison पैटर्न !x.dtype().is_float() से guarded हैं। Floats में, NaN != NaN true है और NaN == NaN false है, तो ये identities hold नहीं करतीं। :::

Constant और Range-Based

पैटर्नरिज़ल्टनोट्स
op(CONST(a), CONST(b))CONST(eval(op, a, b))Direct constant fold
op(x, y) जब bounds prove करेंtrue या falseComparisonAnalyzer vmin/vmax इस्तेमाल करता है

ComparisonAnalyzer चेक करता है: अगर x.vmax < y.vmin तो LT(x, y) provably true है।

Algebraic Transforms

पैटर्नरिज़ल्टनोट्स
LT(ADD[c0, x], c1)LT(x, c1-c0)Offset elimination
LT(NEG(x), NEG(y))LT(y, x)Negation flip
LT(IDIV(x, d), c)LT(x, c*d)Division lift (d > 0)

LT(x//d, c) के लिए division lifting positive और non-positive c दोनों handle करता है:

  • c > 0: equivalent to x < c*d
  • c <= 0: equivalent to x < c*d - (d-1)

11. Min/Max Elimination

पैटर्नरिज़ल्टनोट्स
MAX(x, x)xSelf-max identity है
MAX(x, y)xजब x.vmin >= y.vmax (bounds dominance prove करते हैं)
MAX(x, y)yजब y.vmin >= x.vmax

Range analysis के लिए VminVmaxProperty इस्तेमाल करता है। अलग MIN पैटर्न नहीं — Morok MIN(a,b) को NEG(MAX(NEG(a), NEG(b))) में lower करता है इन पैटर्न से पहले।


12. WHERE ऑप्टिमाइज़ेशन

Condition Elimination

पैटर्नरिज़ल्टनोट्स
WHERE(cond, t, f)tजब cond.vmin == cond.vmax == true
WHERE(cond, t, f)fजब cond.vmin == cond.vmax == false
WHERE(LT(x, c), t, f)tजब x.vmax < c.vmin (हमेशा true)
WHERE(LT(x, c), t, f)fजब x.vmin >= c.vmax (हमेशा false)

Branch सिम्प्लिफ़िकेशन

पैटर्नरिज़ल्टनोट्स
WHERE(_, t, t)tSame branches
WHERE(x, true, false)xBool identity
WHERE(x, false, true)NOT(x)Bool negation
WHERE(NOT(cond), t, f)WHERE(cond, f, t)Condition flip
WHERE(a, WHERE(b, c, d), d)WHERE(AND(a, b), c, d)Branch merging (d पर ptr_eq)

:::caution Condition flip पर Invalid गार्ड WHERE(NOT(cond), t, f) -> WHERE(cond, f, t) जब f में Invalid हो तब अप्लाई नहीं होता। Padding WHERE(valid, idx, Invalid) structures बनाता है, और swap करने से Invalid true branch में चला जाएगा जहाँ downstream पैटर्न उसे मैच नहीं कर सकते। Scalar Invalid और vectorized VECTORIZE(Invalid, ...) दोनों चेक होते हैं।

Tinygrad में भी यही गार्ड है: symbolic.py:201-202। :::


13. Invalid Propagation

Invalid Morok का sentinel है out-of-bounds tensor regions के लिए जो padding operations बनाती हैं। ये पैटर्न identity पैटर्न जैसे x*0=0 से पहले चलने चाहिए, वरना validity markers destroy हो जाते हैं।

पैटर्न प्रायोरिटी Example

Without ordering: MUL(0, WHERE(cond, x, Invalid)) -> 0 (x*0=0 fires, loses Invalid)
With ordering: MUL(0, WHERE(cond, x, Invalid))
-> WHERE(cond, MUL(0, x), Invalid) (Invalid propagation fires first)
-> WHERE(cond, 0, Invalid) (then x*0=0 is safe)

WHERE-Invalid Merging

पैटर्नरिज़ल्ट
WHERE(c1, WHERE(c2, x, Inv), Inv)WHERE(AND(c1, c2), x, Inv)
WHERE(c1, WHERE(c2, x, Inv), y)WHERE(AND(c1, c2), x, y)

Multi-dimensional padding linearized index arithmetic से propagation के बाद nested WHERE-Invalid बनाता है। Single level में merge करने से pm_lower_index_dtype एक step में consume कर सकता है।

WHERE-Invalid से ऑपरेशन Push करना

पैटर्नरिज़ल्टOps
CAST(WHERE(c, x, Inv))WHERE(c, CAST(x), Inv)
op(WHERE(c, x, Inv), y)WHERE(c, op(x, y), Inv)13 binary ops (non-comparison)
op(y, WHERE(c, x, Inv))WHERE(c, op(y, x), Inv)13 binary ops (non-comparison)
cmp(WHERE(c, x, Inv), y)cmp(x, y)Lt, Le, Eq, Ne, Gt, Ge
cmp(y, WHERE(c, x, Inv))cmp(y, x)Lt, Le, Eq, Ne, Gt, Ge

Comparisons के लिए, WHERE-Invalid strip होता है — Invalid region पहले से downstream gated है।

Bare Invalid Propagation

पैटर्नरिज़ल्टगार्ड
op(Invalid, y)Invalidy.dtype() == DType::Index, सिर्फ़ left position

Tinygrad alignment: symbolic.py:37। Right-position bare Invalid propagate नहीं होता ताकि non-index computations contaminate न हों।

Invalid Indices से Dead Loads/Stores

पैटर्नरिज़ल्ट
LOAD(INDEX(buf, Invalid))CONST(0)
LOAD(CAST(INDEX(buf, Invalid)))CONST(0)
STORE(INDEX(buf, Invalid), val)NOOP
STORE(CAST(INDEX(buf, Invalid)), val)NOOP

14. Dead Code Elimination

Dead Ranges

पैटर्नरिज़ल्टनोट्स
RANGE(end) जहाँ vmax < 0CONST(0)Empty range (कभी execute नहीं होती)
RANGE(CONST) जहाँ vmin == vmaxCONST(vmin)Trivial range (single value)
END(computation, ranges)END(computation, live_ranges)Dead ranges END से filter
END(computation, [])computationसभी ranges dead — unwrap

Dead Reduces

Reduce OpIdentity Element
Add0
Mul1
Max-inf (dtype minimum)
Min+inf (dtype maximum)

जब REDUCE की सभी ranges dead (empty) हों, REDUCE अपने identity element से replace होता है।

Dependency सिम्प्लिफ़िकेशन

पैटर्नरिज़ल्ट
AFTER(x, [])x

कोई dependencies नहीं मतलब कोई ordering constraint नहीं।


15. Power और Negation

पैटर्नरिज़ल्ट
POW(x, 0)1
POW(x, 1)x
NEG(NEG(x))x

16. GEP Pushing

GEP (Get Element Pointer) vectors से elements extract करता है। ये पैटर्न GEP को दूसरे operations से push करके vector source तक पहुँचाते हैं, जिससे devectorization के बाद scalar simplification संभव होता है।

सिर्फ़ symbolic() (Stage 4) में include, symbolic_simple() (Stages 8, 16) में नहीं।

Composition और Extraction

पैटर्नरिज़ल्टनोट्स
GEP(GEP(x, inner), outer)GEP(x, inner[outer])Nested compose
GEP(VECTORIZE(x,x,x,x), [i])xBroadcast से (सभी ptr_eq)
GEP(VECTORIZE(elems), [i])elems[i]VECTORIZE से
GEP(scalar, [i])scalarScalar identity (vcount == 1)
GEP(VCONST(vals), [i])CONST(vals[i])VConst से
GEP(x, [0,1,...,n-1])xIdentity removal

Operations से Push करना

पैटर्नरिज़ल्टगार्ड
GEP(op(a, b), idx)op(GEP(a, idx), GEP(b, idx))Binary, सिर्फ़ Index dtype
GEP(unary(x), idx)unary(GEP(x, idx))Unary, सिर्फ़ Index dtype
GEP(WHERE(c, t, f), idx)WHERE(GEP(c, idx), GEP(t, idx), GEP(f, idx))सिर्फ़ Index dtype
GEP(MULACC(a, b, c), idx)MULACC(GEP(a, idx), GEP(b, idx), GEP(c, idx))सिर्फ़ Index dtype

:::caution Index dtype गार्ड graph explosion रोकता है ALU ops से GEP pushing सिर्फ़ Index dtype तक restricted है (Tinygrad: symbolic.py:167)। इस गार्ड के बिना, GEP pushing और no_vectorized_alu मिलकर high-dimensional kernels पर exponential graph blowup पैदा करते हैं। :::

Structural Ops से Push करना

पैटर्नरिज़ल्ट
GEP(CAT([a<4>, b<4>]), [5])GEP(b, [1])
GEP(PTRCAT([a, b, c]), [1, 2])PTRCAT([b, c])
GEP(CAST(x, dtype), idx)CAST(GEP(x, idx), scalar_dtype)
GEP(BITCAST(x, dtype), idx)BITCAST(GEP(x, idx), scalar_dtype)
GEP(WMMA(a, b, c), idx)WMMA(GEP(a, ...), GEP(b, ...), GEP(c, ...))
GEP(UNROLL(x, ...), idx)GEP(x, idx)
GEP(void_node, _)void_node

WMMA पैटर्न tile indices को upcast axes से मैप करता है ताकि corresponding input subgroups extract हों।

Re-collection

पैटर्नरिज़ल्ट
VECTORIZE(GEP(x,[0]), GEP(x,[1]), ..., GEP(x,[N-1]))GEP(x, [0,1,...,N-1])

यह no_vectorized_alu से बनी VECTORIZE structures को वापस single GEP में collapse करता है, जिसे फिर identity पैटर्न remove कर देता है।


17. WHERE on LOAD (सिर्फ़ Stage 8)

Function: pm_move_where_on_load()

Masked loads को transform करता है condition को INDEX ऑपरेशन में embed करके:

Before: WHERE(cond, INDEX(buf, idx), 0)
After: INDEX(buf, WHERE(combined_cond, idx, Invalid))

यह hardware predication सक्षम करता है masked loads के लिए और WHERE overhead eliminate करता है।

कैसे काम करता है

  1. Condition को AND clauses में split करें
  2. Clauses को moveable vs. remaining में partition करें:
    • Moveable: सभी RANGE dependencies INDEX scope में, कोई external INDEX dependencies नहीं
    • Remaining: बाकी सब
  3. Moveable clauses को WHERE(cond, idx, Invalid) के रूप में indices[0] में embed करें
  4. Remaining clauses हों तो outer WHERE में wrap करें

Partial clause movement सपोर्ट करता है — सिर्फ़ वो clauses move होते हैं जिनकी ranges index scope में हैं। indices[0] में existing validity clauses deduplicate होते हैं।

Inverted पैटर्न WHERE(cond, 0, INDEX(buf, idx)) भी condition negate करके handle होता है।


18. Commutative Canonicalization

Commutative binary ops पर Index dtype के लिए, operands UOp id से sort होते हैं (smaller id left पर):

Opsगार्ड
Add, Mul, Max, Eq, Ne, And, Or, Xordtype == DType::Index && b.id < a.id

इसके बिना, mathematically equivalent expressions जैसे R1*8000 + R2*16 और R2*16 + R1*8000 hash consing से deduplicate नहीं होते, जो expand_vector_index में grouping तोड़ता है।

सिर्फ़ Index dtype पर apply ताकि vector math merging न टूटे। Tinygrad: symbolic.py:178-182


19. Div-Mod सिम्प्लिफ़िकेशन

Range-Based Fast Paths

पैटर्नरिज़ल्टCondition
MOD(x, n)x0 <= vmin(x) और vmax(x) < n
IDIV(x, n)kRange में सभी values एक ही k को divide करती हैं
MOD(ADD[MUL[a, m], b], n)MOD(b, n)m == n (multiples factor out)
IDIV(ADD[MUL[a, m], b], n)a + IDIV(b, n)m == n
IDIV(ADD[MUL[a, m], b], n)am == n और 0 <= b < n

Unified Div-Mod Engine (fold_divmod_general)

Index dtype पर IDIV और MOD के लिए, एक unified engine priority order में simplification rules ट्राई करता है। Tinygrad के fold_divmod_general (divandmod.py:8-93) पर based।

प्रायोरिटीRuleDescription
1cancel_divmodRange single denominator interval में
2remove_nested_mod(a%4 + b)%2 -> (a+b)%2 जब `2
3fold_binary_numeratorSingle term range 2 के साथ
4fold_divmod_congruenceFactor congruence modular arithmetic
5gcd_with_remainderNumerator से common GCD factor out
6divide_by_gcdVariable denominator GCD factoring
7factor_remainder(d*x+y)//d -> x + y//d (last resort)

Div-Mod Recombination

Separated div और mod operations को वापस original expression में recombine करने वाले पैटर्न:

पैटर्नरिज़ल्टगार्ड
ADD[MOD(x, n), MUL[IDIV(x, n), n]]xx, n पर ptr_eq
ADD[MOD(IDIV(x, a), c), MUL[IDIV(x, b), c]]IDIV(x, a)a * c == b
ADD[MUL[MOD(x, c1), c2], MUL[IDIV(x, c1), c3]]MUL(x, c2)c1 * c2 == c3
ADD[ADD[y, MOD(x, n)], MUL[IDIV(x, n), n]]ADD(y, x)x, n पर ptr_eq
IDIV(ADD[IDIV(a, c1), c2], c3)IDIV(ADD(a, c1*c2), c1*c3)Nested division

Advanced Division

पैटर्नरिज़ल्टनोट्स
IDIV(IDIV(a, b), c)IDIV(a, b*c)Nested division compose
IDIV(expr, d)expr.divides(d)Generic exact division
IDIV(ADD(a, b), c)IDIV(a, c) + IDIV(b, c)जब दोनों evenly divide हों
IDIV(SUB(a, b), c)IDIV(a, c) - IDIV(b, c)जब दोनों evenly divide हों
MUL(c, ADD(a, b))ADD(MUL(c, a), MUL(c, b))Multiplication distribute

Cross-References

  • Execution Pipeline -- stages जहाँ ये पैटर्न चलते हैं
  • Pattern Engine — पैटर्न मैचिंग इंजन कैसे काम करता है
  • Rangeify -- Stage 4 context (movement op lowering के बाद पैटर्न चलते हैं)
  • Expander -- Stage 8 context (optimization actions के बाद पैटर्न चलते हैं)
  • Linearizer -- Stage 16 context (फ़ाइनल cleanup)