@@ -6,7 +6,7 @@ package dev.rdh.bf
66 * This IR has explicit block semantics:
77 * - offsets are normalized relative to a block base shift
88 * - writes are grouped into batches with entry-state references
9- * - [BFAffinePrint ]/[BFAffineInput] act as ordering barriers between write batches
9+ * - [BFAffineOutput ]/[BFAffineInput] act as ordering barriers between write batches
1010 */
1111sealed interface BFAffineOp
1212
@@ -48,7 +48,7 @@ sealed interface BFAffineSegment
4848data class BFAffineWriteBatch (val writes : List <BFAffineWrite >) : BFAffineSegment
4949
5050/* * Print the byte at [offset] relative to the block-shifted pointer. */
51- data class BFAffinePrint (val offset : Int ) : BFAffineSegment
51+ data class BFAffineOutput (val offset : Int ) : BFAffineSegment
5252
5353/* * Read one byte into [offset] relative to the block-shifted pointer. */
5454data class BFAffineInput (val offset : Int ) : BFAffineSegment
@@ -62,7 +62,7 @@ data class BFAffineWrite(
6262/* *
6363 * Affine expression over referenced cell values.
6464 *
65- * `constant + sum(terms[i].coefficient * ref( terms[i].offset) )`
65+ * `constant + sum(terms[i].coefficient * tape[ptr + terms[i].offset] )`
6666 */
6767data class BFAffineExpr (
6868 val constant : Int = 0 ,
@@ -82,6 +82,36 @@ private data class MutableExpr(
8282 terms = terms.toMutableMap(),
8383 constant = constant,
8484 )
85+
86+ operator fun plus (other : MutableExpr ): MutableExpr {
87+ val out = copyExpr()
88+ out .constant + = other.constant
89+ for ((ref, coeff) in other.terms) {
90+ val next = (out .terms[ref] ? : 0 ) + coeff
91+ if (next == 0 ) {
92+ out .terms.remove(ref)
93+ } else {
94+ out .terms[ref] = next
95+ }
96+ }
97+ return out
98+ }
99+
100+ operator fun times (multiplier : Int ): MutableExpr {
101+ if (multiplier == 0 ) return constExpr(0 )
102+ val out = copyExpr()
103+ out .constant * = multiplier
104+ val refs = out .terms.keys.toList()
105+ for (ref in refs) {
106+ val next = (out .terms[ref] ? : 0 ) * multiplier
107+ if (next == 0 ) {
108+ out .terms.remove(ref)
109+ } else {
110+ out .terms[ref] = next
111+ }
112+ }
113+ return out
114+ }
85115}
86116
87117private sealed interface LoweringStep
@@ -94,36 +124,6 @@ private data class StepCopy(val sourceOffset: Int, val targetOffset: Int, val mu
94124private fun refExpr (offset : Int ): MutableExpr = MutableExpr (terms = mutableMapOf (offset to 1 ))
95125private fun constExpr (value : Int ): MutableExpr = MutableExpr (constant = value)
96126
97- private operator fun MutableExpr.plus (other : MutableExpr ): MutableExpr {
98- val out = copyExpr()
99- out .constant + = other.constant
100- for ((ref, coeff) in other.terms) {
101- val next = (out .terms[ref] ? : 0 ) + coeff
102- if (next == 0 ) {
103- out .terms.remove(ref)
104- } else {
105- out .terms[ref] = next
106- }
107- }
108- return out
109- }
110-
111- private operator fun MutableExpr.times (multiplier : Int ): MutableExpr {
112- if (multiplier == 0 ) return constExpr(0 )
113- val out = copyExpr()
114- out .constant * = multiplier
115- val refs = out .terms.keys.toList()
116- for (ref in refs) {
117- val next = (out .terms[ref] ? : 0 ) * multiplier
118- if (next == 0 ) {
119- out .terms.remove(ref)
120- } else {
121- out .terms[ref] = next
122- }
123- }
124- return out
125- }
126-
127127/* *
128128 * Lowers a loop-free basic block to affine form.
129129 *
@@ -222,7 +222,7 @@ private fun lowerLinearBlock(block: List<BFOperation>): BFAffineBlock? {
222222 }
223223 is StepPrint -> {
224224 flushState()
225- segments + = BFAffinePrint (offset = eff(step.offset))
225+ segments + = BFAffineOutput (offset = eff(step.offset))
226226 }
227227 is StepInput -> {
228228 flushState()
0 commit comments