-
Notifications
You must be signed in to change notification settings - Fork 0
Exploration
To benchmark the code, we took the Fast Fourier Transform example from Rosetta code and used it as the benchmarking target: https://github.com/miniboxing/staging-plugin/blob/master/tests/correctness/src/stagium/testcases/fft.scala
Complex class:
case class Complex(re: Double, im: Double) {
def +(x: Complex): Complex = Complex(re + x.re, im + x.im)
def -(x: Complex): Complex = Complex(re - x.re, im - x.im)
def **(x: Double): Complex = Complex(re * x, im * x)
def *(x: Complex): Complex = Complex(re * x.re - im * x.im, re * x.im + im * x.re)
def /(x: Double): Complex = Complex(re / x, im / x)
override def toString(): String = s"stagium.examples.fft.Complex($re, $im)"
def exp: Complex = Complex.exp(this)
}
object Complex {
def exp(c: Complex) : Complex = {
val r = (cosh(c.re) + sinh(c.re))
Complex(cos(c.im), sin(c.im)) ** r
}
}
FFT:
// annotations need to be added since the type inference does not kick in properly when annotations are present
// see https://groups.google.com/forum/#!topic/scala-internals/-hp79CrjQPo for more details
object FFT {
def _fft(cSeq: Seq[Complex @staged], direction: Complex @staged, scalar: Int @staged): Seq[Complex @staged] = {
if (cSeq.length == 1) {
cSeq
} else {
val n = cSeq.length
assume(n % 2 == 0, "The Cooley-Tukey FFT algorithm only works when the length of the input is a power of two.")
val evenOddPairs = cSeq.grouped(2).toSeq
val evens = _fft(evenOddPairs map[Complex @staged, Seq[Complex @staged]] (_(0)), direction, scalar)
val odds = _fft(evenOddPairs map[Complex @staged, Seq[Complex @staged]] (_(1)), direction, scalar)
def leftRightPair(k: Int): (Complex @staged, Complex @staged) = {
val base: Complex @staged = evens(k) / scalar
val offset: Complex @staged = odds(k) * ((direction ** (Pi * k / n)).exp / scalar)
Tuple2[Complex @staged, Complex @staged](base + offset, base - offset)
}
val pairs = (0 until n/2) map leftRightPair
val left = pairs map[Complex @staged, Seq[Complex @staged]] (_._1)
val right = pairs map[Complex @staged, Seq[Complex @staged]] (_._2)
left ++ right
}
}
def fft(cSeq: Seq[Complex @staged]): Seq[Complex @staged] = _fft(cSeq, Complex(0, 2), 1)
def rfft(cSeq: Seq[Complex @staged]): Seq[Complex @staged] = _fft(cSeq, Complex(0, -2), 2)
}
As before, we define a __staged
object which defines the infix methods required for staging the example. We also add the following test for staging:
// Test for staging
object Test {
def main(args: Array[String]): Unit = {
import FFT._
val fun = function8((e1: Complex @staged, e2: Complex @staged, e3: Complex @staged, e4: Complex @staged, e5: Complex @staged, e6: Complex @staged, e7: Complex @staged, e8: Complex @staged) =>
rfft(fft(Seq[Complex @staged](e1, e2, e3, e4, e5, e6, e7, e8)))(0))
val c = Complex(1.0, 1.0)
fun(c,c,c,c,c,c,c,c)
}
}
Running the program returns:
$ st-scalac fft.scala && st-scala stagium.examples.fft.Test
Need to compile and run:
*********************************
{
val x216: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex =
(a1: stagium.examples.fft.Complex, a2: stagium.examples.fft.Complex, a3: stagium.examples.fft.Complex, a4: stagium.examples.fft.Complex, a5: stagium.examples.fft.Complex, a6: stagium.examples.fft.Complex, a7: stagium.examples.fft.Complex, a8: stagium.examples.fft.Complex) => {
val x184: Double = 2.toDouble
val x112: Double = 2.toDouble
val x0: Double = 1.toDouble
val x146: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x47: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x4: Double = 1.toDouble
val x81: Double = 1.toDouble
val x162: Double = 2.toDouble
val x119: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x20: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x121: Double = 2.toDouble
val x27: Double = 1.toDouble
val x13: Double = 1.toDouble
val x56: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x101: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 1.1780972450961724
val x144: Double = 2.toDouble
val x45: Double = 1.toDouble
val x85: Double = 1.toDouble
val x11: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x67: Double = 1.toDouble
val x58: Double = 1.toDouble
val x126: Double = 2.toDouble
val x103: Double = 1.toDouble
val x99: Double = 1.toDouble
val x180: Double = 2.toDouble
val x63: Double = 1.toDouble
val x83: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.39269908169872414
val x153: Double = 2.toDouble
val x166: Double = 2.toDouble
val x38: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x40: Double = 1.toDouble
val x148: Double = 2.toDouble
val x117: Double = 2.toDouble
val x65: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.7853981633974483
val x94: Double = 1.toDouble
val x76: Double = 1.toDouble
val x9: Double = 1.toDouble
val x130: Double = 2.toDouble
val x164: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x182: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x108: Double = 2.toDouble
val x72: Double = 1.toDouble
val x36: Double = 1.toDouble
val x74: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x157: Double = 2.toDouble
val x18: Double = 1.toDouble
val x110: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x155: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x31: Double = 1.toDouble
val x49: Double = 1.toDouble
val x2: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.0
val x54: Double = 1.toDouble
val x29: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.7853981633974483
val x92: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, 2.0) * 0.7853981633974483
val x22: Double = 1.toDouble
val x128: stagium.examples.fft.Complex = stagium.examples.fft.Complex(0.0, -2.0) * 0.0
val x90: Double = 1.toDouble
val x120: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x119)
val x93: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x92)
val x10: stagium.examples.fft.Complex = a3 / x9
val x46: stagium.examples.fft.Complex = a4 / x45
val x39: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x38)
val x1: stagium.examples.fft.Complex = a1 / x0
val x66: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x65)
val x12: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x11)
val x3: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x2)
val x165: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x164)
val x156: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x155)
val x84: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x83)
val x48: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x47)
val x57: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x56)
val x21: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x20)
val x37: stagium.examples.fft.Complex = a2 / x36
val x129: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x128)
val x147: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x146)
val x102: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x101)
val x75: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x74)
val x111: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x110)
val x30: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x29)
val x183: stagium.examples.fft.Complex = stagium.bench.complex.fft.Complex.exp(x182)
val x14: stagium.examples.fft.Complex = x12 / x13
val x131: stagium.examples.fft.Complex = x129 / x130
val x167: stagium.examples.fft.Complex = x165 / x166
val x32: stagium.examples.fft.Complex = x30 / x31
val x113: stagium.examples.fft.Complex = x111 / x112
val x77: stagium.examples.fft.Complex = x75 / x76
val x149: stagium.examples.fft.Complex = x147 / x148
val x104: stagium.examples.fft.Complex = x102 / x103
val x95: stagium.examples.fft.Complex = x93 / x94
val x59: stagium.examples.fft.Complex = x57 / x58
val x5: stagium.examples.fft.Complex = x3 / x4
val x185: stagium.examples.fft.Complex = x183 / x184
val x86: stagium.examples.fft.Complex = x84 / x85
val x23: stagium.examples.fft.Complex = x21 / x22
val x158: stagium.examples.fft.Complex = x156 / x157
val x122: stagium.examples.fft.Complex = x120 / x121
val x41: stagium.examples.fft.Complex = x39 / x40
val x68: stagium.examples.fft.Complex = x66 / x67
val x50: stagium.examples.fft.Complex = x48 / x49
val x42: stagium.examples.fft.Complex = a6 * x41
val x6: stagium.examples.fft.Complex = a5 * x5
val x51: stagium.examples.fft.Complex = a8 * x50
val x15: stagium.examples.fft.Complex = a7 * x14
val x17: stagium.examples.fft.Complex = x10 - x15
val x7: stagium.examples.fft.Complex = x1 + x6
val x52: stagium.examples.fft.Complex = x46 + x51
val x53: stagium.examples.fft.Complex = x46 - x51
val x8: stagium.examples.fft.Complex = x1 - x6
val x44: stagium.examples.fft.Complex = x37 - x42
val x16: stagium.examples.fft.Complex = x10 + x15
val x43: stagium.examples.fft.Complex = x37 + x42
val x60: stagium.examples.fft.Complex = x52 * x59
val x24: stagium.examples.fft.Complex = x16 * x23
val x55: stagium.examples.fft.Complex = x43 / x54
val x69: stagium.examples.fft.Complex = x53 * x68
val x33: stagium.examples.fft.Complex = x17 * x32
val x19: stagium.examples.fft.Complex = x7 / x18
val x64: stagium.examples.fft.Complex = x44 / x63
val x28: stagium.examples.fft.Complex = x8 / x27
val x61: stagium.examples.fft.Complex = x55 + x60
val x35: stagium.examples.fft.Complex = x28 - x33
val x62: stagium.examples.fft.Complex = x55 - x60
val x71: stagium.examples.fft.Complex = x64 - x69
val x70: stagium.examples.fft.Complex = x64 + x69
val x26: stagium.examples.fft.Complex = x19 - x24
val x34: stagium.examples.fft.Complex = x28 + x33
val x25: stagium.examples.fft.Complex = x19 + x24
val x105: stagium.examples.fft.Complex = x71 * x104
val x73: stagium.examples.fft.Complex = x25 / x72
val x96: stagium.examples.fft.Complex = x62 * x95
val x100: stagium.examples.fft.Complex = x35 / x99
val x87: stagium.examples.fft.Complex = x70 * x86
val x91: stagium.examples.fft.Complex = x26 / x90
val x82: stagium.examples.fft.Complex = x34 / x81
val x78: stagium.examples.fft.Complex = x61 * x77
val x97: stagium.examples.fft.Complex = x91 + x96
val x106: stagium.examples.fft.Complex = x100 + x105
val x107: stagium.examples.fft.Complex = x100 - x105
val x89: stagium.examples.fft.Complex = x82 - x87
val x98: stagium.examples.fft.Complex = x91 - x96
val x88: stagium.examples.fft.Complex = x82 + x87
val x79: stagium.examples.fft.Complex = x73 + x78
val x80: stagium.examples.fft.Complex = x73 - x78
val x118: stagium.examples.fft.Complex = x97 / x117
val x159: stagium.examples.fft.Complex = x107 * x158
val x150: stagium.examples.fft.Complex = x89 * x149
val x145: stagium.examples.fft.Complex = x88 / x144
val x123: stagium.examples.fft.Complex = x98 * x122
val x114: stagium.examples.fft.Complex = x80 * x113
val x109: stagium.examples.fft.Complex = x79 / x108
val x154: stagium.examples.fft.Complex = x106 / x153
val x115: stagium.examples.fft.Complex = x109 + x114
val x160: stagium.examples.fft.Complex = x154 + x159
val x151: stagium.examples.fft.Complex = x145 + x150
val x124: stagium.examples.fft.Complex = x118 + x123
val x163: stagium.examples.fft.Complex = x151 / x162
val x127: stagium.examples.fft.Complex = x115 / x126
val x168: stagium.examples.fft.Complex = x160 * x167
val x132: stagium.examples.fft.Complex = x124 * x131
val x169: stagium.examples.fft.Complex = x163 + x168
val x133: stagium.examples.fft.Complex = x127 + x132
val x186: stagium.examples.fft.Complex = x169 * x185
val x181: stagium.examples.fft.Complex = x133 / x180
val x187: stagium.examples.fft.Complex = x181 + x186
x187: stagium.examples.fft.Complex
} // end of code block of 164 instructions
x216: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
} // end of function x216: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
*********************************
<function8 called>
We consider it an interesting challenge to reduce the number of instructions in the staged code. Let us start by looking at the signature of fft:
def _fft(cSeq: Seq[Complex @staged], direction: Complex @staged, scalar: Int @staged): Seq[Complex @staged]
Actually, since we know the scalar
and the direction
, they need not be staged:
def _fft(cSeq: Seq[Complex @staged], direction: Complex, scalar: Int): Seq[Complex @staged]
Running again, we get:
$ st-scalac fft.scala && st-scala stagium.examples.fft.Test
Need to compile and run:
*********************************
{
val x96: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex =
(a1: stagium.examples.fft.Complex, a2: stagium.examples.fft.Complex, a3: stagium.examples.fft.Complex, a4: stagium.examples.fft.Complex, a5: stagium.examples.fft.Complex, a6: stagium.examples.fft.Complex, a7: stagium.examples.fft.Complex, a8: stagium.examples.fft.Complex) => {
val x17: stagium.examples.fft.Complex = a6 * stagium.examples.fft.Complex(1.0, 0.0)
val x0: stagium.examples.fft.Complex = a1 / 1.0
val x4: stagium.examples.fft.Complex = a3 / 1.0
val x20: stagium.examples.fft.Complex = a4 / 1.0
val x1: stagium.examples.fft.Complex = a5 * stagium.examples.fft.Complex(1.0, 0.0)
val x5: stagium.examples.fft.Complex = a7 * stagium.examples.fft.Complex(1.0, 0.0)
val x21: stagium.examples.fft.Complex = a8 * stagium.examples.fft.Complex(1.0, 0.0)
val x16: stagium.examples.fft.Complex = a2 / 1.0
val x6: stagium.examples.fft.Complex = x4 + x5
val x7: stagium.examples.fft.Complex = x4 - x5
val x3: stagium.examples.fft.Complex = x0 - x1
val x19: stagium.examples.fft.Complex = x16 - x17
val x23: stagium.examples.fft.Complex = x20 - x21
val x18: stagium.examples.fft.Complex = x16 + x17
val x2: stagium.examples.fft.Complex = x0 + x1
val x22: stagium.examples.fft.Complex = x20 + x21
val x24: stagium.examples.fft.Complex = x18 / 1.0
val x13: stagium.examples.fft.Complex = x7 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x12: stagium.examples.fft.Complex = x3 / 1.0
val x8: stagium.examples.fft.Complex = x2 / 1.0
val x9: stagium.examples.fft.Complex = x6 * stagium.examples.fft.Complex(1.0, 0.0)
val x28: stagium.examples.fft.Complex = x19 / 1.0
val x29: stagium.examples.fft.Complex = x23 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x25: stagium.examples.fft.Complex = x22 * stagium.examples.fft.Complex(1.0, 0.0)
val x14: stagium.examples.fft.Complex = x12 + x13
val x10: stagium.examples.fft.Complex = x8 + x9
val x27: stagium.examples.fft.Complex = x24 - x25
val x11: stagium.examples.fft.Complex = x8 - x9
val x15: stagium.examples.fft.Complex = x12 - x13
val x26: stagium.examples.fft.Complex = x24 + x25
val x31: stagium.examples.fft.Complex = x28 - x29
val x30: stagium.examples.fft.Complex = x28 + x29
val x32: stagium.examples.fft.Complex = x10 / 1.0
val x45: stagium.examples.fft.Complex = x31 * stagium.examples.fft.Complex(-0.7071067811865475, 0.7071067811865476)
val x33: stagium.examples.fft.Complex = x26 * stagium.examples.fft.Complex(1.0, 0.0)
val x40: stagium.examples.fft.Complex = x11 / 1.0
val x44: stagium.examples.fft.Complex = x15 / 1.0
val x37: stagium.examples.fft.Complex = x30 * stagium.examples.fft.Complex(0.7071067811865476, 0.7071067811865475)
val x41: stagium.examples.fft.Complex = x27 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x36: stagium.examples.fft.Complex = x14 / 1.0
val x47: stagium.examples.fft.Complex = x44 - x45
val x42: stagium.examples.fft.Complex = x40 + x41
val x46: stagium.examples.fft.Complex = x44 + x45
val x39: stagium.examples.fft.Complex = x36 - x37
val x35: stagium.examples.fft.Complex = x32 - x33
val x38: stagium.examples.fft.Complex = x36 + x37
val x34: stagium.examples.fft.Complex = x32 + x33
val x43: stagium.examples.fft.Complex = x40 - x41
val x52: stagium.examples.fft.Complex = x42 / 2.0
val x69: stagium.examples.fft.Complex = x47 * stagium.examples.fft.Complex(0.5, -0.0)
val x48: stagium.examples.fft.Complex = x34 / 2.0
val x53: stagium.examples.fft.Complex = x43 * stagium.examples.fft.Complex(0.5, -0.0)
val x64: stagium.examples.fft.Complex = x38 / 2.0
val x65: stagium.examples.fft.Complex = x39 * stagium.examples.fft.Complex(0.5, -0.0)
val x68: stagium.examples.fft.Complex = x46 / 2.0
val x49: stagium.examples.fft.Complex = x35 * stagium.examples.fft.Complex(0.5, -0.0)
val x66: stagium.examples.fft.Complex = x64 + x65
val x70: stagium.examples.fft.Complex = x68 + x69
val x54: stagium.examples.fft.Complex = x52 + x53
val x50: stagium.examples.fft.Complex = x48 + x49
val x73: stagium.examples.fft.Complex = x70 * stagium.examples.fft.Complex(0.5, -0.0)
val x56: stagium.examples.fft.Complex = x50 / 2.0
val x57: stagium.examples.fft.Complex = x54 * stagium.examples.fft.Complex(0.5, -0.0)
val x72: stagium.examples.fft.Complex = x66 / 2.0
val x58: stagium.examples.fft.Complex = x56 + x57
val x74: stagium.examples.fft.Complex = x72 + x73
val x81: stagium.examples.fft.Complex = x74 * stagium.examples.fft.Complex(0.5, -0.0)
val x80: stagium.examples.fft.Complex = x58 / 2.0
val x82: stagium.examples.fft.Complex = x80 + x81
x82: stagium.examples.fft.Complex
} // end of code block of 69 instructions
x96: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
} // end of function x96: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
*********************************
<function8 called>
Wow, just by un-staging two parameters we reduced the example from 164 instructions to just 69! Cool. But looking at the code, we see many divisions by 1.0. Let us take care of those:
def infix_/(t1: Exp[Complex], t2: Exp[Double]): Exp[Complex] =
(t1, t2) match {
case (t1, Con(1.0)) => t1
case _ => Div(t1, t2)
}
Running again, we get:
$ st-scalac fft.scala && st-scala stagium.examples.fft.Test
Need to compile and run:
*********************************
{
val x84: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex =
(a1: stagium.examples.fft.Complex, a2: stagium.examples.fft.Complex, a3: stagium.examples.fft.Complex, a4: stagium.examples.fft.Complex, a5: stagium.examples.fft.Complex, a6: stagium.examples.fft.Complex, a7: stagium.examples.fft.Complex, a8: stagium.examples.fft.Complex) => {
val x0: stagium.examples.fft.Complex = a5 * stagium.examples.fft.Complex(1.0, 0.0)
val x12: stagium.examples.fft.Complex = a6 * stagium.examples.fft.Complex(1.0, 0.0)
val x3: stagium.examples.fft.Complex = a7 * stagium.examples.fft.Complex(1.0, 0.0)
val x15: stagium.examples.fft.Complex = a8 * stagium.examples.fft.Complex(1.0, 0.0)
val x14: stagium.examples.fft.Complex = a2 - x12
val x17: stagium.examples.fft.Complex = a4 - x15
val x4: stagium.examples.fft.Complex = a3 + x3
val x1: stagium.examples.fft.Complex = a1 + x0
val x13: stagium.examples.fft.Complex = a2 + x12
val x5: stagium.examples.fft.Complex = a3 - x3
val x16: stagium.examples.fft.Complex = a4 + x15
val x2: stagium.examples.fft.Complex = a1 - x0
val x6: stagium.examples.fft.Complex = x4 * stagium.examples.fft.Complex(1.0, 0.0)
val x9: stagium.examples.fft.Complex = x5 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x21: stagium.examples.fft.Complex = x17 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x18: stagium.examples.fft.Complex = x16 * stagium.examples.fft.Complex(1.0, 0.0)
val x10: stagium.examples.fft.Complex = x2 + x9
val x20: stagium.examples.fft.Complex = x13 - x18
val x7: stagium.examples.fft.Complex = x1 + x6
val x11: stagium.examples.fft.Complex = x2 - x9
val x19: stagium.examples.fft.Complex = x13 + x18
val x23: stagium.examples.fft.Complex = x14 - x21
val x8: stagium.examples.fft.Complex = x1 - x6
val x22: stagium.examples.fft.Complex = x14 + x21
val x24: stagium.examples.fft.Complex = x19 * stagium.examples.fft.Complex(1.0, 0.0)
val x27: stagium.examples.fft.Complex = x22 * stagium.examples.fft.Complex(0.7071067811865476, 0.7071067811865475)
val x33: stagium.examples.fft.Complex = x23 * stagium.examples.fft.Complex(-0.7071067811865475, 0.7071067811865476)
val x30: stagium.examples.fft.Complex = x20 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x35: stagium.examples.fft.Complex = x11 - x33
val x32: stagium.examples.fft.Complex = x8 - x30
val x28: stagium.examples.fft.Complex = x10 + x27
val x26: stagium.examples.fft.Complex = x7 - x24
val x31: stagium.examples.fft.Complex = x8 + x30
val x34: stagium.examples.fft.Complex = x11 + x33
val x29: stagium.examples.fft.Complex = x10 - x27
val x25: stagium.examples.fft.Complex = x7 + x24
val x52: stagium.examples.fft.Complex = x28 / 2.0
val x56: stagium.examples.fft.Complex = x34 / 2.0
val x53: stagium.examples.fft.Complex = x29 * stagium.examples.fft.Complex(0.5, -0.0)
val x40: stagium.examples.fft.Complex = x31 / 2.0
val x57: stagium.examples.fft.Complex = x35 * stagium.examples.fft.Complex(0.5, -0.0)
val x37: stagium.examples.fft.Complex = x26 * stagium.examples.fft.Complex(0.5, -0.0)
val x41: stagium.examples.fft.Complex = x32 * stagium.examples.fft.Complex(0.5, -0.0)
val x36: stagium.examples.fft.Complex = x25 / 2.0
val x42: stagium.examples.fft.Complex = x40 + x41
val x58: stagium.examples.fft.Complex = x56 + x57
val x38: stagium.examples.fft.Complex = x36 + x37
val x54: stagium.examples.fft.Complex = x52 + x53
val x61: stagium.examples.fft.Complex = x58 * stagium.examples.fft.Complex(0.5, -0.0)
val x60: stagium.examples.fft.Complex = x54 / 2.0
val x45: stagium.examples.fft.Complex = x42 * stagium.examples.fft.Complex(0.5, -0.0)
val x44: stagium.examples.fft.Complex = x38 / 2.0
val x46: stagium.examples.fft.Complex = x44 + x45
val x62: stagium.examples.fft.Complex = x60 + x61
val x69: stagium.examples.fft.Complex = x62 * stagium.examples.fft.Complex(0.5, -0.0)
val x68: stagium.examples.fft.Complex = x46 / 2.0
val x70: stagium.examples.fft.Complex = x68 + x69
x70: stagium.examples.fft.Complex
} // end of code block of 57 instructions
x84: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
} // end of function x84: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
*********************************
<function8 called>
Down to 57 instructions. Now we see see many multiplications, either by 1 or by 0.5. We can also eliminate those:
def infix_*(t1: Exp[Complex], t2: Exp[Complex]): Exp[Complex] =
(t1, t2) match {
case (t1, Con(Complex(scalar, 0.0))) =>
if (scalar == 1.0)
t1
else
infix_**(t1, Con(scalar))
case _ => Mul(t1, t2)
}
Running again we get:
$ st-scalac fft.scala && st-scala stagium.examples.fft.Test
Need to compile and run:
*********************************
{
val x77: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex =
(a1: stagium.examples.fft.Complex, a2: stagium.examples.fft.Complex, a3: stagium.examples.fft.Complex, a4: stagium.examples.fft.Complex, a5: stagium.examples.fft.Complex, a6: stagium.examples.fft.Complex, a7: stagium.examples.fft.Complex, a8: stagium.examples.fft.Complex) => {
val x10: stagium.examples.fft.Complex = a2 - a6
val x0: stagium.examples.fft.Complex = a1 + a5
val x1: stagium.examples.fft.Complex = a1 - a5
val x11: stagium.examples.fft.Complex = a4 + a8
val x12: stagium.examples.fft.Complex = a4 - a8
val x3: stagium.examples.fft.Complex = a3 - a7
val x9: stagium.examples.fft.Complex = a2 + a6
val x2: stagium.examples.fft.Complex = a3 + a7
val x14: stagium.examples.fft.Complex = x9 - x11
val x4: stagium.examples.fft.Complex = x0 + x2
val x6: stagium.examples.fft.Complex = x3 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x13: stagium.examples.fft.Complex = x9 + x11
val x5: stagium.examples.fft.Complex = x0 - x2
val x15: stagium.examples.fft.Complex = x12 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x17: stagium.examples.fft.Complex = x10 - x15
val x7: stagium.examples.fft.Complex = x1 + x6
val x19: stagium.examples.fft.Complex = x4 - x13
val x23: stagium.examples.fft.Complex = x14 * stagium.examples.fft.Complex(6.123233995736766E-17, 1.0)
val x8: stagium.examples.fft.Complex = x1 - x6
val x16: stagium.examples.fft.Complex = x10 + x15
val x18: stagium.examples.fft.Complex = x4 + x13
val x24: stagium.examples.fft.Complex = x5 + x23
val x20: stagium.examples.fft.Complex = x16 * stagium.examples.fft.Complex(0.7071067811865476, 0.7071067811865475)
val x26: stagium.examples.fft.Complex = x17 * stagium.examples.fft.Complex(-0.7071067811865475, 0.7071067811865476)
val x29: stagium.examples.fft.Complex = x18 / 2.0
val x25: stagium.examples.fft.Complex = x5 - x23
val x30: stagium.examples.fft.Complex = x19 * 0.5
val x27: stagium.examples.fft.Complex = x8 + x26
val x33: stagium.examples.fft.Complex = x24 / 2.0
val x21: stagium.examples.fft.Complex = x7 + x20
val x28: stagium.examples.fft.Complex = x8 - x26
val x31: stagium.examples.fft.Complex = x29 + x30
val x34: stagium.examples.fft.Complex = x25 * 0.5
val x22: stagium.examples.fft.Complex = x7 - x20
val x46: stagium.examples.fft.Complex = x22 * 0.5
val x35: stagium.examples.fft.Complex = x33 + x34
val x45: stagium.examples.fft.Complex = x21 / 2.0
val x37: stagium.examples.fft.Complex = x31 / 2.0
val x49: stagium.examples.fft.Complex = x27 / 2.0
val x50: stagium.examples.fft.Complex = x28 * 0.5
val x47: stagium.examples.fft.Complex = x45 + x46
val x51: stagium.examples.fft.Complex = x49 + x50
val x38: stagium.examples.fft.Complex = x35 * 0.5
val x39: stagium.examples.fft.Complex = x37 + x38
val x53: stagium.examples.fft.Complex = x47 / 2.0
val x54: stagium.examples.fft.Complex = x51 * 0.5
val x61: stagium.examples.fft.Complex = x39 / 2.0
val x55: stagium.examples.fft.Complex = x53 + x54
val x62: stagium.examples.fft.Complex = x55 * 0.5
val x63: stagium.examples.fft.Complex = x61 + x62
x63: stagium.examples.fft.Complex
} // end of code block of 50 instructions
x77: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
} // end of function x77: (stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex, stagium.examples.fft.Complex) => stagium.examples.fft.Complex
*********************************
<function8 called>
So we're down to 50 instructions, from 164. Furthermore, most of these instructions are scalar multiplications, which can be further simplified. Also, since Complex is a value class, its two fields can be split and treated separately. But since these are all implemented in the lightweight modular staging framework we will stop here and conclude that using the staging plugin, not only that we were able to burn through several layers of collection functions, but we were also able to reduce the example to mere additions, subtractions, multiplications and divisions.
See the [next chapter](Test Suite) for running the test suite.