Skip to content

Commit 8c2ce3a

Browse files
committed
split binop fusion into commutative and non commutative
1 parent cf3f44d commit 8c2ce3a

3 files changed

Lines changed: 107 additions & 37 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package io.github.charlietap.chasm.optimiser.passes.fusion
2+
3+
import io.github.charlietap.chasm.ir.instruction.FusedDestination
4+
import io.github.charlietap.chasm.ir.instruction.FusedOperand
5+
import io.github.charlietap.chasm.ir.instruction.Instruction
6+
7+
internal fun CommutativeBinopFuser(
8+
index: Int,
9+
instruction: Instruction,
10+
input: List<Instruction>,
11+
output: MutableList<Instruction>,
12+
fusedInstructionFactory: BinopFusedInstructionFactory,
13+
): Int = CommutativeBinopFuser(
14+
index = index,
15+
instruction = instruction,
16+
input = input,
17+
output = output,
18+
fusedInstructionFactory = fusedInstructionFactory,
19+
operandFactory = ::FusedOperandFactory,
20+
destinationFactory = ::FusedDestinationFactory,
21+
)
22+
23+
internal inline fun CommutativeBinopFuser(
24+
index: Int,
25+
instruction: Instruction,
26+
input: List<Instruction>,
27+
output: MutableList<Instruction>,
28+
fusedInstructionFactory: BinopFusedInstructionFactory,
29+
operandFactory: FusedOperandFactory,
30+
destinationFactory: FusedDestinationFactory,
31+
): Int {
32+
33+
var nextIndex = index
34+
35+
val right = input.getOrNull(index - 1)?.let(operandFactory)
36+
val left = input.getOrNull(index - 2)?.let(operandFactory)
37+
val destination = input.getOrNull(index + 1).let(destinationFactory)
38+
39+
val instruction = when {
40+
right == null && destination == FusedDestination.ValueStack -> instruction
41+
right == null -> fusedInstructionFactory(
42+
FusedOperand.ValueStack,
43+
FusedOperand.ValueStack,
44+
destination,
45+
)
46+
left == null -> {
47+
output.removeLast()
48+
fusedInstructionFactory(
49+
FusedOperand.ValueStack,
50+
right,
51+
destination,
52+
)
53+
}
54+
else -> {
55+
output.removeLast()
56+
output.removeLast()
57+
fusedInstructionFactory(left, right, destination)
58+
}
59+
}
60+
61+
output.add(instruction)
62+
63+
if (right != null && destination != FusedDestination.ValueStack) {
64+
nextIndex++
65+
}
66+
67+
return nextIndex
68+
}

optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/NumericBinopFuser.kt renamed to optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/NonCommutativeBinopFuser.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ internal typealias BinopFuser = (Int, Instruction, List<Instruction>, MutableLis
1919
* this reason this specialised fuser exists which omits fusions where
2020
* both operands are missing but the destination is present.
2121
*/
22-
internal fun NumericBinopFuser(
22+
internal fun NonCommutativeBinopFuser(
2323
index: Int,
2424
instruction: Instruction,
2525
input: List<Instruction>,
2626
output: MutableList<Instruction>,
2727
fusedInstructionFactory: BinopFusedInstructionFactory,
28-
): Int = NumericBinopFuser(
28+
): Int = NonCommutativeBinopFuser(
2929
index = index,
3030
instruction = instruction,
3131
input = input,
@@ -35,7 +35,7 @@ internal fun NumericBinopFuser(
3535
destinationFactory = ::FusedDestinationFactory,
3636
)
3737

38-
internal inline fun NumericBinopFuser(
38+
internal inline fun NonCommutativeBinopFuser(
3939
index: Int,
4040
instruction: Instruction,
4141
input: List<Instruction>,

optimiser/src/commonMain/kotlin/io/github/charlietap/chasm/optimiser/passes/fusion/NumericInstructionFuser.kt

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ internal fun NumericInstructionFuser(
5353
input = input,
5454
output = output,
5555
unop = ::UnopFuser,
56-
binop = ::NumericBinopFuser,
56+
commutativeBinop = ::CommutativeBinopFuser,
57+
nonCommutativeBinop = ::NonCommutativeBinopFuser,
5758
)
5859

5960
internal inline fun NumericInstructionFuser(
@@ -63,43 +64,44 @@ internal inline fun NumericInstructionFuser(
6364
input: List<Instruction>,
6465
output: MutableList<Instruction>,
6566
unop: UnopFuser,
66-
binop: BinopFuser,
67+
commutativeBinop: BinopFuser,
68+
nonCommutativeBinop: BinopFuser,
6769
): Int = when (instruction) {
68-
is NumericInstruction.I32Add -> binop(index, instruction, input, output, ::I32Add)
69-
is NumericInstruction.I32Sub -> binop(index, instruction, input, output, ::I32Sub)
70-
is NumericInstruction.I32Mul -> binop(index, instruction, input, output, ::I32Mul)
71-
is NumericInstruction.I32DivS -> binop(index, instruction, input, output, ::I32DivS)
72-
is NumericInstruction.I32DivU -> binop(index, instruction, input, output, ::I32DivU)
73-
is NumericInstruction.I32And -> binop(index, instruction, input, output, ::I32And)
74-
is NumericInstruction.I32Or -> binop(index, instruction, input, output, ::I32Or)
75-
is NumericInstruction.I32Xor -> binop(index, instruction, input, output, ::I32Xor)
76-
is NumericInstruction.I32Shl -> binop(index, instruction, input, output, ::I32Shl)
77-
is NumericInstruction.I32ShrS -> binop(index, instruction, input, output, ::I32ShrS)
78-
is NumericInstruction.I32ShrU -> binop(index, instruction, input, output, ::I32ShrU)
79-
is NumericInstruction.I32LtS -> binop(index, instruction, input, output, ::I32LtS)
80-
is NumericInstruction.I32LtU -> binop(index, instruction, input, output, ::I32LtU)
81-
is NumericInstruction.I32GtS -> binop(index, instruction, input, output, ::I32GtS)
82-
is NumericInstruction.I32GtU -> binop(index, instruction, input, output, ::I32GtU)
83-
is NumericInstruction.I32LeS -> binop(index, instruction, input, output, ::I32LeS)
84-
is NumericInstruction.I32LeU -> binop(index, instruction, input, output, ::I32LeU)
85-
is NumericInstruction.I32GeS -> binop(index, instruction, input, output, ::I32GeS)
86-
is NumericInstruction.I32GeU -> binop(index, instruction, input, output, ::I32GeU)
70+
is NumericInstruction.I32Add -> nonCommutativeBinop(index, instruction, input, output, ::I32Add)
71+
is NumericInstruction.I32Sub -> nonCommutativeBinop(index, instruction, input, output, ::I32Sub)
72+
is NumericInstruction.I32Mul -> commutativeBinop(index, instruction, input, output, ::I32Mul)
73+
is NumericInstruction.I32DivS -> nonCommutativeBinop(index, instruction, input, output, ::I32DivS)
74+
is NumericInstruction.I32DivU -> nonCommutativeBinop(index, instruction, input, output, ::I32DivU)
75+
is NumericInstruction.I32And -> commutativeBinop(index, instruction, input, output, ::I32And)
76+
is NumericInstruction.I32Or -> commutativeBinop(index, instruction, input, output, ::I32Or)
77+
is NumericInstruction.I32Xor -> commutativeBinop(index, instruction, input, output, ::I32Xor)
78+
is NumericInstruction.I32Shl -> nonCommutativeBinop(index, instruction, input, output, ::I32Shl)
79+
is NumericInstruction.I32ShrS -> nonCommutativeBinop(index, instruction, input, output, ::I32ShrS)
80+
is NumericInstruction.I32ShrU -> nonCommutativeBinop(index, instruction, input, output, ::I32ShrU)
81+
is NumericInstruction.I32LtS -> nonCommutativeBinop(index, instruction, input, output, ::I32LtS)
82+
is NumericInstruction.I32LtU -> nonCommutativeBinop(index, instruction, input, output, ::I32LtU)
83+
is NumericInstruction.I32GtS -> nonCommutativeBinop(index, instruction, input, output, ::I32GtS)
84+
is NumericInstruction.I32GtU -> nonCommutativeBinop(index, instruction, input, output, ::I32GtU)
85+
is NumericInstruction.I32LeS -> nonCommutativeBinop(index, instruction, input, output, ::I32LeS)
86+
is NumericInstruction.I32LeU -> nonCommutativeBinop(index, instruction, input, output, ::I32LeU)
87+
is NumericInstruction.I32GeS -> nonCommutativeBinop(index, instruction, input, output, ::I32GeS)
88+
is NumericInstruction.I32GeU -> nonCommutativeBinop(index, instruction, input, output, ::I32GeU)
8789
is NumericInstruction.I32Eqz -> unop(index, instruction, input, output, ::I32Eqz)
8890
is NumericInstruction.I64Eqz -> unop(index, instruction, input, output, ::I64Eqz)
89-
is NumericInstruction.I64Add -> binop(index, instruction, input, output, ::I64Add)
90-
is NumericInstruction.I64Sub -> binop(index, instruction, input, output, ::I64Sub)
91-
is NumericInstruction.I64Mul -> binop(index, instruction, input, output, ::I64Mul)
92-
is NumericInstruction.I64DivS -> binop(index, instruction, input, output, ::I64DivS)
93-
is NumericInstruction.I64DivU -> binop(index, instruction, input, output, ::I64DivU)
91+
is NumericInstruction.I64Add -> nonCommutativeBinop(index, instruction, input, output, ::I64Add)
92+
is NumericInstruction.I64Sub -> nonCommutativeBinop(index, instruction, input, output, ::I64Sub)
93+
is NumericInstruction.I64Mul -> commutativeBinop(index, instruction, input, output, ::I64Mul)
94+
is NumericInstruction.I64DivS -> nonCommutativeBinop(index, instruction, input, output, ::I64DivS)
95+
is NumericInstruction.I64DivU -> nonCommutativeBinop(index, instruction, input, output, ::I64DivU)
9496
is NumericInstruction.F32Abs -> unop(index, instruction, input, output, ::F32Abs)
95-
is NumericInstruction.F32Add -> binop(index, instruction, input, output, ::F32Add)
96-
is NumericInstruction.F32Sub -> binop(index, instruction, input, output, ::F32Sub)
97-
is NumericInstruction.F32Mul -> binop(index, instruction, input, output, ::F32Mul)
98-
is NumericInstruction.F32Div -> binop(index, instruction, input, output, ::F32Div)
99-
is NumericInstruction.F64Add -> binop(index, instruction, input, output, ::F64Add)
100-
is NumericInstruction.F64Sub -> binop(index, instruction, input, output, ::F64Sub)
101-
is NumericInstruction.F64Mul -> binop(index, instruction, input, output, ::F64Mul)
102-
is NumericInstruction.F64Div -> binop(index, instruction, input, output, ::F64Div)
97+
is NumericInstruction.F32Add -> commutativeBinop(index, instruction, input, output, ::F32Add)
98+
is NumericInstruction.F32Sub -> nonCommutativeBinop(index, instruction, input, output, ::F32Sub)
99+
is NumericInstruction.F32Mul -> commutativeBinop(index, instruction, input, output, ::F32Mul)
100+
is NumericInstruction.F32Div -> nonCommutativeBinop(index, instruction, input, output, ::F32Div)
101+
is NumericInstruction.F64Add -> nonCommutativeBinop(index, instruction, input, output, ::F64Add)
102+
is NumericInstruction.F64Sub -> nonCommutativeBinop(index, instruction, input, output, ::F64Sub)
103+
is NumericInstruction.F64Mul -> commutativeBinop(index, instruction, input, output, ::F64Mul)
104+
is NumericInstruction.F64Div -> nonCommutativeBinop(index, instruction, input, output, ::F64Div)
103105
else -> {
104106
output.add(instruction)
105107
index

0 commit comments

Comments
 (0)