diff --git a/src/main/scala/apps/GAP8HwceDma.scala b/src/main/scala/apps/GAP8HwceDma.scala new file mode 100644 index 000000000..04fcb22bb --- /dev/null +++ b/src/main/scala/apps/GAP8HwceDma.scala @@ -0,0 +1,373 @@ +package apps + +import arithexpr.arithmetic.NamedVar +import elevate.core.Strategy +import rise.GAP8.DSL.gap8Run +import rise.GAP8.primitives.{allocL1, allocL2, copy2DOffsetToL1, copyToL1, copyToL2, gap8hwConv3x3, gap8hwConv5x5} +import rise.core.DSL.HighLevelConstructs.{padCst2D, slide2D, zipND} +import rise.core.DSL.Type.TypeConstructors +import rise.core.DSL.{ToBeTyped, depFun, foreignFun, fun, letf, li16} +import rise.core.primitives._ +import rise.core.types.DataType.{ArrayType, i16, int, u8} +import rise.core.types.Nat +import rise.elevate.Rise +import rise.elevate.strategies.traversal.everywhere +import rise.elevate.strategies.traversal.AtHelper +import rise.elevate.rules.lowering.`map -> mapPar` +import rise.openMP.primitives.mapPar +import shine.GAP8.Module.translateToString + +// scalastyle: off +object GAP8HwceDma { + def main(args: Array[String]): Unit = { + //24.10.2023. If Type is i16 -> i16, one should be 1u << 14 + val gapSqrt = foreignFun("gap_sqrt", + Seq("a_nInput"), + """ + | { + | uint32_t op = a_nInput; + | uint32_t res = 0; + | + | uint32_t one = 1uL << 30; + | while (one > op){ + | one >>= 2; + | } + | while (one != 0) { + | if (op >= res + one){ + | op = op - (res + one); + | res = res + 2 * one; + | } + | res >>= 1; + | one >>= 2; + | } + | return res; + | } + |""".stripMargin, + i16 ->: i16 + ) + + val size: Nat = 4 + val fixSize: ToBeTyped[Rise] = fun(ArrayType(size, u8) ->: ArrayType(size, u8))(in => + gap8Run(8)( + in |> + copyToL1 |> + allocL1 |> + mapSeq(fun(x => x)) |> + allocL1 |> + copyToL2 + ) + ) + //println(translateToString(util.gen.gap8.hosted.fromExpr(fixSize))) + + val varSize: ToBeTyped[Rise] = depFun((sz: Nat) => + fun(ArrayType(sz, u8) ->: ArrayType(sz, u8))(in => + gap8Run(8)( + in |> + copyToL1 |> + allocL1 |> + mapSeq(fun(x => x)) |> + allocL1 |> + copyToL2 + ))) + //println(translateToString(util.gen.gap8.hosted.fromExpr(varSize))) + + val fixSizeDmaHwce: ToBeTyped[Rise] = fun( + ArrayType(size, ArrayType(size, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(size - 2, ArrayType(size - 2, i16)))((in, filter) => + gap8Run(8)( + in |> copyToL1 |> allocL1 |> letf(innerin => + filter |> copyToL1 |> allocL1 |> letf(innerf => + gap8hwConv3x3(0)(innerin, innerf) |> allocL1 |> copyToL2 + ) + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("conv").fromExpr(fixSizeDmaHwce))) + + //Passes + val theSmallestSlide: ToBeTyped[Rise] = fun( + ArrayType(5, i16) ->: ArrayType(3, ArrayType(3, i16)) + )(arr => + gap8Run(8)( + arr |> slide(3)(1) |> mapSeq(mapSeq(fun(elem => add(elem)(li16(1))))) + ) + ) + //printf(translateToString(util.gen.gap8.hosted("theSmallest").fromExpr(theSmallestSlide))) + //translateToString(util.gen.gap8.hosted("theSmallest").fromExpr(theSmallestSlide)) + println("======================================================================") + + val inBetweenSlideExample: ToBeTyped[Rise] = fun( + ArrayType(5, i16) ->: ArrayType(3, ArrayType(3, i16)) + )(arr => + gap8Run(8)( + arr |> slide(3)(1) |> mapSeq(fun(tile => + tile |> copyToL1 |> allocL1 |> letf(tstletf => + tstletf |> mapSeq(fun(elem => add(elem)(li16(1)))) |> allocL1 |> copyToL2 + ) + )) + ) + ) + //println(translateToString(util.gen.gap8.hosted("inBetween").fromExpr(inBetweenSlideExample))) + //translateToString(util.gen.gap8.hosted("inBetween").fromExpr(inBetweenSlideExample)) + println("======================================================================") + + //Does not pass + val thisMaybe: ToBeTyped[Rise] = fun( + ArrayType(5, i16) ->: ArrayType(9, i16) + )(arr => + gap8Run(8)( + arr |> slide(3)(1) |> join |> copyToL1 |> allocL1 |> letf(sth => + sth |> mapSeq(fun(elem => add(elem)(li16(1)))) |> allocL1 |> copyToL2 + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("thisMaybe").fromExpr(thisMaybe))) + //translateToString(util.gen.gap8.hosted("thisMaybe").fromExpr(thisMaybe)) + + //Does not pass either + val evenSmallerSlideExample: ToBeTyped[Rise] = fun( + ArrayType(5, i16) ->: ArrayType(3, ArrayType(3, i16)) + )(arr => + gap8Run(8)( + arr |> slide(3)(1) |> mapSeq(fun(tile => + tile |> copyToL1 |> allocL1 |> letf(tilel1 => + tilel1 |> mapSeq(fun(elem => add(elem)(li16(1)))) |> allocL1 |> copyToL2 + ) + )) + ) + ) + //println(translateToString(util.gen.gap8.hosted("evenSmallerSlideExample").fromExpr(evenSmallerSlideExample))) + //translateToString(util.gen.gap8.hosted("evenSmallerSlideExample").fromExpr(evenSmallerSlideExample)) + + //No way + val minSlideExample: ToBeTyped[Rise] = fun( + ArrayType(5, ArrayType(5, i16)) ->: + ArrayType(3, ArrayType(5, i16)) ->: + ArrayType(9, ArrayType(5, i16)))((sth, filter) => + gap8Run(8)( + sth |> slide(3)(1) |> mapSeq(fun(tile => + tile |> copyToL1 |> allocL1 |> letf(tilel1 => + zipND(2)(tilel1, filter) |> mapPar(mapPar(fun(elems => + add(fst(elems))(snd(elems)) + ))) |> allocL1 |> copyToL2 + ) + )) |> join + ) + ) + //println(translateToString(util.gen.gap8.hosted("minSlide").fromExpr(minSlideExample))) + + val w: Nat = 320 + val h: Nat = 240 + //Padded horizontally + val tiledFixSizeDmaHwce: ToBeTyped[Rise] = + fun( + ArrayType(h, ArrayType(w, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(h - 2, ArrayType(w, i16)))((pic, hw, vw) => + gap8Run(8)( + hw |> copyToL1 |> allocL1 |> letf(l1hw => + vw |> copyToL1 |> allocL1 |> letf(l1vw => + // pic |> padCst2D(1, 1, 0, 0)(li16(0)) |> slide(16)(14) |> + // pic: 240.320.i16 + pic |> slide (16)(14) |> + // 14*16+16 => 240 (n: 16) + // 17.16.320.i16 + mapSeq(fun(stripe => + // stripe: 16.320.i16 + stripe |> copy2DOffsetToL1(0)(1) |> allocL1 |> // letf(l1stripe => + + // l1stripe |> padCst2D(0, 0, 1, 1)(li16(0)) |> + // mapSeq(mapSeq(fun(x => x))) |> allocL1 |> + // l1convstripe: 18.322.i16 + // if offsetH = 0 -> 16.322.i16 + letf(l1convstripe => + // convresult(s): 16.320.i16 + // if offsetH =0 -> 14.320.i16 + gap8hwConv3x3(0)(l1convstripe, l1hw) |> allocL1 |> letf(hconvres => + gap8hwConv3x3(0)(l1convstripe, l1vw) |> allocL1 |> letf(vconvres => + // zipND: 16.320.(i16, i16) + zipND(2)(hconvres)(vconvres) |> mapPar(mapPar(fun(elems => + gapSqrt(add(mul(fst(elems))(fst(elems)))(mul(snd(elems))(snd(elems)))) + //copy back 16.320.i16 + ))) |> allocL1 |> copyToL2 + ) + ) + // ) + ) + //(17*16).320.i16 + //offsetH -> 0 (17*14).320.i16 + )) |> join + ) + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("tiledConv").fromExpr(tiledFixSizeDmaHwce))) + + //Padded vertically + val tiledFixSizeDmaHwcePaddedVertically: ToBeTyped[Rise] = + fun( + ArrayType(h, ArrayType(w, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(h - 2, ArrayType(w - 2, i16)))((pic, hw, vw) => + gap8Run(8)( + hw |> copyToL1 |> allocL1 |> letf(l1hw => + vw |> copyToL1 |> allocL1 |> letf(l1vw => + // pic: 240.320.i16 + pic |> slide(16)(14) |> + // 14*16+16 => 240 (n: 16) + // 17.16.320.i16 + mapSeq(fun(stripe => + // stripe: 16.320.i16 + stripe |> copy2DOffsetToL1(1)(0) |> allocL1 |> // letf(l1stripe => + // l1convstripe 18.320.i16 + letf(l1convstripe => + // convresult(s): 16.318.i16 + gap8hwConv3x3(0)(l1convstripe, l1hw) |> allocL1 |> letf(hconvres => + gap8hwConv3x3(0)(l1convstripe, l1vw) |> allocL1 |> letf(vconvres => + // zipND: 16.318.(i16, i16) + zipND(2)(hconvres)(vconvres) |> mapPar(mapPar(fun(elems => + gapSqrt(add(mul(fst(elems))(fst(elems)))(mul(snd(elems))(snd(elems)))) + //copy back 16.318.i16 + ))) |> allocL1 |> take(15) |> drop(1) |> copyToL2 + ) + ) + ) + //(17*16).318.i16 + )) |> join + ) + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("tiledConv").fromExpr(tiledFixSizeDmaHwcePaddedVertically))) + + val tiledFixSizeDmaHwceNoPadding: ToBeTyped[Rise] = + fun( + ArrayType(h, ArrayType(w, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(h - 2, ArrayType(w - 2, i16)))((pic, hw, vw) => + gap8Run(8)( + hw |> copyToL1 |> allocL1 |> letf(l1hw => + vw |> copyToL1 |> allocL1 |> letf(l1vw => + // pic: 240.320.i16 + pic |> slide(16)(14) |> + // 14*16+16 => 240 (n: 16) + // 17.16.320.i16 + mapSeq(fun(stripe => + // stripe: 16.320.i16 + stripe |> copyToL1 |> allocL1 |> // letf(l1stripe => + // l1convstripe 16.320.i16 + letf(l1convstripe => + // convresult(s): 14.318.i16 + gap8hwConv3x3(0)(l1convstripe, l1hw) |> allocL1 |> letf(hconvres => + gap8hwConv3x3(0)(l1convstripe, l1vw) |> allocL1 |> letf(vconvres => + // zipND: 14.318.(i16, i16) + zipND(2)(hconvres)(vconvres) |> mapPar(mapPar(fun(elems => + gapSqrt(add(mul(fst(elems))(fst(elems)))(mul(snd(elems))(snd(elems)))) + //copy back 14.318.i16 + ))) |> allocL1 |> copyToL2 + ) + ) + ) + // + + )) |> join + ) + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("tiledConv").fromExpr(tiledFixSizeDmaHwceNoPadding))) + val ww: Nat = 320 + val hh: Nat = 244 + val tiledFixSizeDmaHwceNoPadding_Gaussian: ToBeTyped[Rise] = + fun( + ArrayType(hh, ArrayType(ww, i16)) ->: + ArrayType(5, ArrayType(5, i16)) ->: + ArrayType(hh - 4, ArrayType(ww - 4, i16)))((pic, filter) => + gap8Run(8)( + filter |> copyToL1 |> allocL1 |> letf(l1filter => + // pic: 240.320.i16 + pic |> slide(16)(12) |> + // step * n + size = 240 + // 17.16.320.i16 + mapSeq(fun(stripe => + //stripe 16.320.i16 + stripe |> copyToL1 |> allocL1 |> + letf(l1stripe => + // convresult (12.316.i16) + gap8hwConv5x5(0)(l1stripe, l1filter) |> allocL1 |> copyToL2 + ) + )) |> join + ) + ) + ) + println(translateToString(util.gen.gap8.hosted("GaussianBlur").fromExpr(tiledFixSizeDmaHwceNoPadding_Gaussian))) + + val gaussianNoPadHWCE: ToBeTyped[Rise] = fun( + ArrayType(hh, ArrayType(ww, i16)) ->: + ArrayType(5, ArrayType(5, i16)) ->: + ArrayType(hh - 4, ArrayType(ww - 4, i16)) + )((pic, filter) => + gap8Run(8)( + gap8hwConv5x5(0)(pic, filter) + ) + ) + println(translateToString(util.gen.gap8.hosted("GaussianBlur_HWCE").fromExpr(gaussianNoPadHWCE))) + + val gaussianBlurPlain: ToBeTyped[Rise] = fun( + ArrayType(hh, ArrayType(ww, i16)) ->: + ArrayType(5, ArrayType(5, i16)) ->: + ArrayType(hh - 4, ArrayType(ww - 4, i16)) + )((pic, filter) => + gap8Run(8)( + pic |> + slide2D(sz = 5, st = 1) |> + mapPar(mapPar(fun(submat => + zip(submat |> join)(filter |> join) |> map(fun(e => fst(e) * snd(e))) |> reduceSeqUnroll(add)(li16(0)) + ))) + ) + ) + println(translateToString(util.gen.gap8.hosted("GaussianBlur_Plain").fromExpr(gaussianBlurPlain))) + + /*val strategy: Strategy[Rise] = + `map -> mapPar` `@` everywhere + val ex_mapfor: ToBeTyped[Rise] = depFun((n: Nat) => + fun(ArrayType(n, int) ->: ArrayType(n, int))(input => + input |> map(fun(x => x)) + ) + ) + println(util.gen.openmp.function("ex_mapfor").asStringFromExpr(strategy(ex_mapfor).get))*/ + + val simpleNoSlide: ToBeTyped[Rise] = + fun( + ArrayType(size, ArrayType(size, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(size - 2, ArrayType(size - 2, i16)))((pic, hw, vw) => + gap8Run(8)( + hw |> copyToL1 |> allocL1 |> letf(l1hw => + vw |> copyToL1 |> allocL1 |> letf(l1vw => + pic |> copyToL1 |> allocL1 |> letf(l1pic => + gap8hwConv3x3(0)(l1pic, l1hw) |> allocL1 |> letf (hconvres => // hconvres |> copyToL2 + gap8hwConv3x3(0)(l1pic, l1vw) |> allocL1 |> letf (vconvres => + zipND(2)(hconvres)(vconvres) |> mapPar(mapPar(fun(elems => + add(fst(elems))(snd(elems)) + ))) |> allocL1 |> copyToL2 + /*zip(hconvres)(vconvres) |> mapPar(fun(rows => + zip(fst(rows))(snd(rows)) |> mapPar(fun(elems => + add(fst(elems))(snd(elems)) + )) + )) |> allocL1 |> copyToL2*/ + ) + ) + ) + ) + ) + ) + ) + //println(translateToString(util.gen.gap8.hosted("doubleconv").fromExpr(simpleNoSlide))) + } +} diff --git a/src/main/scala/apps/tester.scala b/src/main/scala/apps/tester.scala new file mode 100644 index 000000000..16b3efaa2 --- /dev/null +++ b/src/main/scala/apps/tester.scala @@ -0,0 +1,137 @@ +package apps + +import elevate.core._ +import rise.GAP8.DSL.gap8Run +import rise.GAP8.primitives.{allocL1, allocL2, copyToL1, copyToL2, gap8hwConv3x3} +import rise.core.DSL.HighLevelConstructs.{slide2D, zipND} +import rise.core.DSL.Type._ +import rise.core.DSL._ +import rise.core._ +import rise.core.primitives.{mapSeq, reduceSeq, let => _, _} +import rise.core.types.DataType.{ArrayType, i16, int, u32, u8} +import rise.core.types.{DataType, _} +import rise.elevate._ +import rise.elevate.rules.algorithmic._ +import rise.elevate.rules.lowering._ +import rise.elevate.strategies.predicate.isPrimitive +import rise.elevate.strategies.traversal._ +import rise.openMP.primitives.mapPar +import shine.GAP8.Module.translateToString + +// scalastyle:off +object tester { + def main(args: Array[String]) = { + + val gapSqrt = foreignFun("gap_sqrt", + Seq("a_nInput"), + """ + | { + | uint32_t op = a_nInput; + | uint32_t res = 0; + | + | uint32_t one = 1u << 14; + | while (one > op){ + | one >>= 2; + | } + | while (one != 0) { + | if (op >= res + one){ + | op = op - (res + one); + | res = res + 2 * one; + | } + | res >>= 1; + | one >>= 2; + | } + | return res; + | } + |""".stripMargin, + i16 ->: i16 + ) + + val h: Nat = 240 + val w: Nat = 320 + + val sobelWithoutPad: ToBeTyped[Rise] = + fun( + ArrayType(h, ArrayType(w, u8)) ->: + ArrayType(3, ArrayType(3, int)) ->: + ArrayType(3, ArrayType(3, int)) ->: + ArrayType(h - 2, ArrayType(w - 2, u8)) + )((pic, hf, vf) => + gap8Run(8)( + pic |> + slide2D(sz = 3, st = 1) |> + mapPar(mapPar(fun(submat => + zip(submat |> join)(hf |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> rise.core.primitives.reduceSeqUnroll(add)(cast(l(0)) :: u32) |> letf(h => + zip(submat |> join)(vf |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> rise.core.primitives.reduceSeqUnroll(add)(cast(l(0)) :: u32) |> letf(v => + cast(gapSqrt(h * h + v * v)) :: u8 + ) + ) + )))) + ) + + //println(translateToString(util.gen.gap8.hosted("SobelWOutPad").fromExpr(sobelWithoutPad))) + + //TODO: Check gapSqrt type, it's changed above just to fit this expression type + val sobelWithoutPadHWCE: ToBeTyped[Rise] = { + fun( + ArrayType(h, ArrayType(w, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(3, ArrayType(3, i16)) ->: + ArrayType(h - 2, ArrayType(w - 2, i16)) + )((pic, hf, vf) => + gap8Run(8)( + //pic |> + //pic is 320 x 240 + gap8hwConv3x3(0)(pic, hf) |> allocL2 |> letf(hconvres => + gap8hwConv3x3(0)(pic, vf) |> allocL2 |> letf(vconvres => + //hconvres and vconvres are 318x238 + zipND(2)(hconvres)(vconvres) |> mapPar(mapPar(fun(elems => + gapSqrt(add(mul(fst(elems))(fst(elems)))(mul(snd(elems))(snd(elems)))) + ))) + ) + ) + ) + ) + } + //println(translateToString(util.gen.gap8.hosted("SobelWOutPadHWCE").fromExpr(sobelWithoutPadHWCE))) + + + val matAdd: ToBeTyped[Expr] = depFun((n: Nat, m: Nat) => + fun(ArrayType(n, ArrayType(m, u32)) ->: ArrayType(n, ArrayType(m, u32)) ->: ArrayType(n, ArrayType(m, u32)))((x, y) => + gap8Run(8)( + zip(x)(y) |> + map(fun(pair => zip(fst(pair))(snd(pair)))) |> + mapPar(mapPar(fun(pair => fst(pair) + snd(pair)))) + ) + ) + ) + + val conv: Strategy[Rise] = + (gap8hwConvMerge `@` everywhere) + + + val optimizationStrategy: Strategy[Rise] = + (`map -> mapPar` `@` outermost(isPrimitive(map))) `;` + (`map -> mapSeq` `@` outermost(isPrimitive(map))) `;` + (`reduce -> reduceSeq` `@` everywhere) + +/* + val anotherOptimizationStrategy: Strategy[Rise] = + (`map >> reduce -> reduce` `@` everywhere) `;` + (`map -> mapSeq` `@` everywhere) `;` + (`reduce -> reduceSeq` `@` everywhere) + + val myStrategy: Strategy[Rise] = + (`map >> reduce -> reduce` `@` everywhere) `;` + (`map -> mapPar` `@` outermost(isPrimitive(map))) `;` + (`map -> mapSeq` `@` everywhere) + + val yetAnotherOptimizationStrategy: Strategy[Rise] = + innermost(isAppliedMap)( + `map(f) -> asVector >> map(f_vec) >> asScalar`(4) `;` + (`map -> mapSeq` `@` innermost(isPrimitive(map))) `;` + storeTempAsVectors + ) `;` + optimizationStrategy*/ + } +} diff --git a/src/main/scala/rise/GAP8/primitives/allocL1.scala b/src/main/scala/rise/GAP8/primitives/allocL1.scala new file mode 100644 index 000000000..42318250b --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/allocL1.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object allocL1 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "allocL1" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (t: DataType) => t ->: t } + } + override def toString: String = "allocL1" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/allocL2.scala b/src/main/scala/rise/GAP8/primitives/allocL2.scala new file mode 100644 index 000000000..033a713c3 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/allocL2.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object allocL2 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "allocL2" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (t: DataType) => t ->: t } + } + override def toString: String = "allocL2" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/copy2DOffsetToL1.scala b/src/main/scala/rise/GAP8/primitives/copy2DOffsetToL1.scala new file mode 100644 index 000000000..091e0d4e3 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/copy2DOffsetToL1.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object copy2DOffsetToL1 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "copy2DOffsetToL1" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (t: DataType) => impl { (h: Nat) => impl { (w: Nat) => expl { (offsetH: Nat) => expl { (offsetW: Nat) => ArrayType(h, ArrayType(w, t)) ->: ArrayType(h + 2 * offsetH, ArrayType(w + 2 * offsetW, t)) } } } } } + } + override def toString: String = "copy2DOffsetToL1" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/copyToL1.scala b/src/main/scala/rise/GAP8/primitives/copyToL1.scala new file mode 100644 index 000000000..60a25ec57 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/copyToL1.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object copyToL1 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "copyToL1" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (t: DataType) => t ->: t } + } + override def toString: String = "copyToL1" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/copyToL2.scala b/src/main/scala/rise/GAP8/primitives/copyToL2.scala new file mode 100644 index 000000000..3323c0573 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/copyToL2.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object copyToL2 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "copyToL2" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (t: DataType) => t ->: t } + } + override def toString: String = "copyToL2" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/gap8hwConv3x3.scala b/src/main/scala/rise/GAP8/primitives/gap8hwConv3x3.scala new file mode 100644 index 000000000..c9bef2ad9 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/gap8hwConv3x3.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object gap8hwConv3x3 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "gap8hwConv3x3" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (h: Nat) => impl { (w: Nat) => impl { (dt: DataType) => expl { (bias: Nat) => ArrayType(h, ArrayType(w, dt)) ->: ArrayType(3, ArrayType(3, dt)) ->: ArrayType(h - 2, ArrayType(w - 2, dt)) } } } } + } + override def toString: String = "gap8hwConv3x3" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/gap8hwConv5x5.scala b/src/main/scala/rise/GAP8/primitives/gap8hwConv5x5.scala new file mode 100644 index 000000000..8321e7504 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/gap8hwConv5x5.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object gap8hwConv5x5 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "gap8hwConv5x5" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (h: Nat) => impl { (w: Nat) => impl { (dt: DataType) => expl { (bias: Nat) => ArrayType(h, ArrayType(w, dt)) ->: ArrayType(5, ArrayType(5, dt)) ->: ArrayType(h - 4, ArrayType(w - 4, dt)) } } } } + } + override def toString: String = "gap8hwConv5x5" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/gap8hwConv7x4.scala b/src/main/scala/rise/GAP8/primitives/gap8hwConv7x4.scala new file mode 100644 index 000000000..accbb2a80 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/gap8hwConv7x4.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object gap8hwConv7x4 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "gap8hwConv7x4" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (h: Nat) => impl { (w: Nat) => impl { (dt: DataType) => expl { (bias: Nat) => ArrayType(h, ArrayType(w, dt)) ->: ArrayType(4, ArrayType(7, dt)) ->: ArrayType(h - 3, ArrayType(w - 6, dt)) } } } } + } + override def toString: String = "gap8hwConv7x4" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/gap8hwConv7x7.scala b/src/main/scala/rise/GAP8/primitives/gap8hwConv7x7.scala new file mode 100644 index 000000000..f19b282b7 --- /dev/null +++ b/src/main/scala/rise/GAP8/primitives/gap8hwConv7x7.scala @@ -0,0 +1,25 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package rise.GAP8.primitives +import rise.core.DSL._ +import rise.core.DSL.Type._ +import rise.core._ +import rise.core.types._ +import rise.core.types.DataType._ +import arithexpr.arithmetic._ +object gap8hwConv7x7 extends Builder { + private final case class Primitive()(override val t: ExprType = TypePlaceholder) extends rise.core.Primitive { + override val name: String = "gap8hwConv7x7" + override def setType(ty: ExprType): Primitive = Primitive()(ty) + override def primEq(obj: rise.core.Primitive): Boolean = obj.getClass == getClass + override def typeScheme: ExprType = impl { (h: Nat) => impl { (w: Nat) => impl { (dt: DataType) => expl { (bias: Nat) => ArrayType(h, ArrayType(w, dt)) ->: ArrayType(7, ArrayType(7, dt)) ->: ArrayType(h - 6, ArrayType(w - 6, dt)) } } } } + } + override def toString: String = "gap8hwConv7x7" + override def primitive: rise.core.Primitive = Primitive()() + override def apply: ToBeTyped[rise.core.Primitive] = toBeTyped(Primitive()()) + override def unapply(arg: Expr): Boolean = arg match { + case _: Primitive => true + case _ => false + } +} diff --git a/src/main/scala/rise/GAP8/primitives/primitives.rise b/src/main/scala/rise/GAP8/primitives/primitives.rise index cc3f8ad30..5a16374e4 100644 --- a/src/main/scala/rise/GAP8/primitives/primitives.rise +++ b/src/main/scala/rise/GAP8/primitives/primitives.rise @@ -1 +1,27 @@ def gap8RunPrimitive: (cores: nat) -> {t: data} -> t -> t + +def gap8hwConv3x3: {h: nat} -> {w: nat} -> {dt: data} -> + (bias: nat) -> + h.w.dt -> 3.3.dt -> (h-2).(w-2).dt + +def gap8hwConv5x5: {h: nat} -> {w: nat} -> {dt: data} -> + (bias: nat) -> + h.w.dt -> 5.5.dt -> (h-4).(w-4).dt + +def gap8hwConv7x7: {h: nat} -> {w: nat} -> {dt: data} -> + (bias: nat) -> + h.w.dt -> 7.7.dt -> (h-6).(w-6).dt + +def gap8hwConv7x4: {h: nat} -> {w: nat} -> {dt: data} -> + (bias: nat) -> + h.w.dt -> 4.7.dt -> (h-3).(w-6).dt + +def copyToL1: {t: data} -> t -> t +def copyToL2: {t: data} -> t -> t + +def copy2DOffsetToL1: {t: data} -> {h: nat} -> {w: nat} + -> (offsetH: nat) -> (offsetW: nat) -> (h.w.t) + -> (h + 2 * offsetH).(w + 2 * offsetW).t + +def allocL1: {t: data} -> t -> t +def allocL2: {t: data} -> t -> t \ No newline at end of file diff --git a/src/main/scala/rise/elevate/rules/algorithmic.scala b/src/main/scala/rise/elevate/rules/algorithmic.scala index ac36a1b73..8eda2d3cf 100644 --- a/src/main/scala/rise/elevate/rules/algorithmic.scala +++ b/src/main/scala/rise/elevate/rules/algorithmic.scala @@ -14,6 +14,7 @@ import rise.core.types._ import rise.elevate._ import rise.elevate.strategies.normalForm.DFNF import rise.elevate.strategies.predicate._ +import rise.GAP8.primitives._ // noinspection MutatorLikeMethodIsParameterless object algorithmic { @@ -566,4 +567,58 @@ object algorithmic { case e @ App(sum2, App(join(), in)) if sum2 =~= ((sum !: sum2.t): Expr) => Success((preserveType(in) |> transpose |> map(sum) |> sum) !: e.t) } + + /*@rule def colapseOpenMPfor: Strategy[Rise] = { + ??? + }*/ + + /** + * TODO: A couple of things to think about: + * 1.This is extremely specific. Is there a way to make it more general in any way? + * 2. Concrete HWCE primitive depends not only on the size of the sliding window, + * but on the appropirate dimensions of the input parameters as well. Patch that in + * 3. slide2D has to be deconstructed fully to ensure that the underlying pattern + * fully conforms with the slide2D + * 4. Generalize mapSeq() and reduceSeq() + * 5. This should apply only if wrapped somewhere within gap8run (HWCE is in cluster) + * */ + @rule def gap8hwConvMerge: Strategy[Rise] = { + case e @ + App( + App(mapSeq(), + App(mapSeq(), Lambda(_, + App( + App( + App(reduceSeq(), add()), + App(cast(), _)), + App( + App(map(), Lambda(_, + App(App(mul(), App(fst(), _)), App(snd(), _)) + ) + ), + App(App(zip(), App(join(), _)), App(join(), filter)) + ) + ) + ) + ) + ), + App(Lambda(_, + App(_, + App(Lambda(_, + App( + DepApp(NatKind, DepApp(NatKind, slide(), size), step), _ + ) + ), _) + ) + ), in) + ) => + (size, step) match { + case (Cst(iSize), Cst(iStep)) => + if(1 == iStep && 3 == iSize) Success(gap8hwConv3x3(0)(in)(filter) !: e.t) + else if(1 == iStep && 5 == iSize) Success(gap8hwConv5x5(0)(in)(filter) !: e.t) + else if(1 == iStep && 7 == iSize) Success(gap8hwConv7x7(0)(in)(filter) !: e.t) + else Failure(gap8hwConvMerge) + case _ => Failure(gap8hwConvMerge) + } + } } diff --git a/src/main/scala/shine/C/Compilation/CodeGenerator.scala b/src/main/scala/shine/C/Compilation/CodeGenerator.scala index 2efd4a8a5..759a8d2e7 100644 --- a/src/main/scala/shine/C/Compilation/CodeGenerator.scala +++ b/src/main/scala/shine/C/Compilation/CodeGenerator.scala @@ -67,6 +67,7 @@ class CodeGenerator(val decls: CodeGenerator.Declarations, } + // Must be overridden by every subclass def updatedRanges(key: String, value: arithexpr.arithmetic.Range): CodeGenerator = new CodeGenerator(decls, ranges.updated(key, value)) diff --git a/src/main/scala/shine/DPIA/Compilation/AcceptorTranslation.scala b/src/main/scala/shine/DPIA/Compilation/AcceptorTranslation.scala index e1603b1ba..fb0130319 100644 --- a/src/main/scala/shine/DPIA/Compilation/AcceptorTranslation.scala +++ b/src/main/scala/shine/DPIA/Compilation/AcceptorTranslation.scala @@ -1,23 +1,22 @@ package shine.DPIA.Compilation import arithexpr.arithmetic.{NamedVar, RangeAdd} +import rise.core.DSL.Type._ +import rise.core.substitute.{natInType => substituteNatInType} +import rise.core.types.DataType._ +import rise.core.types.{Nat, NatIdentifier, _} import shine.DPIA.Compilation.TranslationToImperative._ import shine.DPIA.DSL.{comment, _} import shine.DPIA.Phrases._ -import rise.core.types.{DataType, Fragment, MatrixLayout, NatIdentifier, NatKind, read, write} -import rise.core.DSL.Type._ -import rise.core.types.DataType._ -import rise.core.substitute.{natInType => substituteNatInType} import shine.DPIA.Types.{AccType, CommType, ExpType, TypeCheck, comm} -import rise.core.types.DataTypeOps._ import shine.DPIA._ import shine.DPIA.primitives.functional._ import shine.DPIA.primitives.imperative.{Seq => _, _} +import shine.GAP8.{L1toL2, L2toL1} +import shine.GAP8.primitives.{functional => gap8, imperative => gap8Imp} +import shine.OpenCL.primitives.{functional => ocl, imperative => oclImp} import shine.OpenMP.primitives.{functional => omp} -import shine.OpenCL.primitives.{functional => ocl} -import shine.OpenCL.primitives.{imperative => oclImp} -import shine.cuda.primitives.{functional => cuda} -import shine.cuda.primitives.{imperative => cudaImp} +import shine.cuda.primitives.{functional => cuda, imperative => cudaImp} object AcceptorTranslation { def acc(E: Phrase[ExpType]) @@ -391,7 +390,74 @@ object AcceptorTranslation { con(cMatrix)(λ(ExpType(FragmentType(m, n, k, dataTypeAcc, Fragment.Accumulator, MatrixLayout.None), read))(cMatrix => cudaImp.WmmaMMA(m, n, k, layoutA, layoutB, dataType, dataTypeAcc, aMatrix, bMatrix, cMatrix, A))))))) - //GAP8 + // GAP8 + // TODO: think about generalizing this. This currently only works if the filter is an identifier + case gap8.FunConv3x3(h, w, dt, bias, in, filter: Identifier[ExpType]) => + con(in)(λ(ExpType(h`.`(w`.`dt), read))(inInner => { + // val paddedArray = PadCst(3 * 3, 0, 1, dt, Literal(Unsigned8BitIntData(0)), Join(3, 3, read, dt, filter)) + // val paddedArray = shine.DPIA.Phrases.Identifier(filter.name, ExpType(ArrayType(10, dt), read)) + val paddedArray = gap8.Cast( + ArrayType(3, ArrayType(3, dt)), + ArrayType(10, dt), + filter + ) + con(paddedArray)(λ(ExpType(ArrayType(10, dt), read))(filterInner => + gap8Imp.Conv3x3(h, w, dt, bias, inInner, filterInner, A) + )) + })) + case gap8.FunConv5x5(h, w, dt, bias, in, filter: Identifier[ExpType]) => + con(in)(λ(ExpType(h`.`(w`.`dt), read))(inInner => { + val paddedArray = gap8.Cast( + ArrayType(5, ArrayType(5, dt)), + ArrayType(26, dt), + filter + ) + con(paddedArray)(λ(ExpType(ArrayType(26, dt), read))(filterInner => + gap8Imp.Conv5x5(h, w, dt, bias, inInner, filterInner, A) + )) + })) + case gap8.FunConv7x7(h, w, dt, bias, in, filter: Identifier[ExpType]) => + con(in)(λ(ExpType(h`.`(w`.`dt), read))(inInner => { + val paddedArray = gap8.Cast( + ArrayType(7, ArrayType(7, dt)), + ArrayType(56, dt), + filter + ) + con(paddedArray)(λ(ExpType(ArrayType(56, dt), read))(filterInner => + gap8Imp.Conv7x7(h, w, dt, bias, inInner, filterInner, A) + )) + })) + case gap8.FunConv7x4(h, w, dt, bias, in, filter: Identifier[ExpType]) => + con(in)(λ(ExpType(h`.`(w`.`dt), read))(inInner => { + val paddedArray = gap8.Cast( + ArrayType(4, ArrayType(7, dt)), + ArrayType(28, dt), + filter + ) + con(paddedArray)(λ(ExpType(ArrayType(28, dt), read))(filterInner => + gap8Imp.Conv7x4(h, w, dt, bias, inInner, filterInner, A) + )) + })) + + case gap8.CopyToL1(dt, input) => + con(input)(λ(ExpType(dt, read))(i => + gap8Imp.DmaCopy(L2toL1)(dt, i, A) + )) + + case gap8.CopyToL2(dt, input) => + con(input)(λ(ExpType(dt, read))(i => + gap8Imp.DmaCopy(L1toL2)(dt, i, A) + )) + + case gap8.Copy2DOffsetToL1(dt, h, w, offsetH, offsetW, input) => + con(input)(λ(ExpType(h`.`w`.`dt, read))(i => + // set larger output to 0 + gap8Imp.MemorySet((h+2*offsetH)`.`(w+2*offsetW)`.`dt, Literal(IntData(0)), A) `;` + // copy smaller input into output with offset + gap8Imp.Dma2DOffsetCopy(L2toL1)(dt, h, w, offsetH, offsetW, i, A) + )) + + case r@shine.GAP8.primitives.functional.Run(cores) => { ??? } diff --git a/src/main/scala/shine/DPIA/Compilation/ContinuationTranslation.scala b/src/main/scala/shine/DPIA/Compilation/ContinuationTranslation.scala index db385a900..7431ec418 100644 --- a/src/main/scala/shine/DPIA/Compilation/ContinuationTranslation.scala +++ b/src/main/scala/shine/DPIA/Compilation/ContinuationTranslation.scala @@ -4,6 +4,7 @@ import rise.core.types.{AddressSpace, DataType, NatKind, read, write} import rise.core.types.DataType._ import rise.core.DSL.Type._ import rise.core.substitute.{natInType => substituteNatInType} +import rise.core.types.AddressSpace.Private import shine.DPIA.Compilation.TranslationToImperative._ import shine.DPIA.DSL.{comment, _} import shine.DPIA.Phrases._ @@ -12,11 +13,14 @@ import shine.DPIA.Types._ import shine.DPIA._ import shine.DPIA.primitives.functional._ import shine.DPIA.primitives.imperative.{Seq => _, _} +import shine.GAP8.{L1, L1toL2, L2, L2toL1} import shine.OpenCL.AdjustArraySizesForAllocations import shine.OpenMP.primitives.{functional => omp} import shine.OpenCL.primitives.{functional => ocl} import shine.cuda.primitives.{functional => cuda} import shine.cuda.primitives.{imperative => cudaIm} +import shine.GAP8.primitives.{functional => gap8} +import shine.GAP8.primitives.{imperative => gap8Imp} object ContinuationTranslation { def con(E: Phrase[ExpType]) @@ -401,10 +405,22 @@ object ContinuationTranslation { case ocl.ToMem(addrSpace, dt, input) => val adj = AdjustArraySizesForAllocations(input, dt, addrSpace) - shine.OpenCL.DSL.`new` (addrSpace) (adj.dt, tmp => acc(input)(adj.accF(tmp.wr)) `;` C(adj.exprF(tmp.rd))) + case gap8.AllocL1(dt, input) => + shine.GAP8.DSL.GAP8MemoryAlloc(L1)(dt, tmp => { + acc(input)(tmp.wr) `;` C(tmp.rd) + }) + + case gap8.AllocL2(dt, input) => + shine.GAP8.DSL.GAP8MemoryAlloc(L2)(dt, tmp => { + acc(input)(tmp.wr) `;` C(tmp.rd) + }) + + case gap8.Cast(dt1, dt2, input) => + con(input)(λ(expT(dt1, read))(inputT => C(gap8.Cast(dt1, dt2, inputT)))) + // CUDA case cuda.GlobalToShared(dt, inputGlobal) => val adj = AdjustArraySizesForAllocations(inputGlobal, dt, AddressSpace.Local) diff --git a/src/main/scala/shine/DPIA/InferAccessAnnotation.scala b/src/main/scala/shine/DPIA/InferAccessAnnotation.scala index 2b4b25c2a..70d76aa01 100644 --- a/src/main/scala/shine/DPIA/InferAccessAnnotation.scala +++ b/src/main/scala/shine/DPIA/InferAccessAnnotation.scala @@ -8,6 +8,7 @@ import rise.core.DSL.Type.{->:, ArrayTypeConstructors, TupleTypeConstructors, `( import rise.openMP.{primitives => rompp} import rise.openCL.{primitives => roclp} import rise.Cuda.{primitives => rocup} +import rise.GAP8.{primitives => rg8p} import shine.DPIA.Types._ import shine.DPIA.Types.TypeCheck.SubTypeCheckHelper import shine.DPIA.fromRise._ @@ -596,11 +597,79 @@ private class InferAccessAnnotation { (expT(dt, read) ->: expT(dt, write)) ->: expT(fragType, read) ->: expT(fragType, write) } - case rise.GAP8.primitives.gap8RunPrimitive() => p.t match { + case rg8p.gap8RunPrimitive() => p.t match { case cores `(Nat)->:` ((t: rt.DataType) ->: (_: rt.DataType)) => nFunT(cores, expT(t, write) ->: expT(t, write)) case _ => error() } + + case rg8p.gap8hwConv3x3() => p.t match { + case bias `(Nat)->:` (ArrayType(h, ArrayType(w, dt: DataType)) ->: + ArrayType(_, ArrayType(_, _)) ->: ArrayType(_, ArrayType(_, _))) => + nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), read) + ->: expT(ArrayType(3, ArrayType(3, dt)), read) ->: + expT(ArrayType(h - 2, ArrayType(w - 2, dt)), write) + ) + } + + case rg8p.gap8hwConv5x5() => p.t match { + case bias `(Nat)->:` (ArrayType(h, ArrayType(w, dt: DataType)) ->: + ArrayType(_, ArrayType(_, _)) ->: ArrayType(_, ArrayType(_, _))) => + nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), read) + ->: expT(ArrayType(5, ArrayType(5, dt)), read) ->: + expT(ArrayType(h - 4, ArrayType(w - 4, dt)), write) + ) + } + + case rg8p.gap8hwConv7x7() => p.t match { + case bias `(Nat)->:` (ArrayType(h, ArrayType(w, dt: DataType)) ->: + ArrayType(_, ArrayType(_, _)) ->: ArrayType(_, ArrayType(_, _))) => + nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), read) + ->: expT(ArrayType(7, ArrayType(7, dt)), read) ->: + expT(ArrayType(h - 6, ArrayType(w - 6, dt)), write) + ) + } + + case rg8p.gap8hwConv7x4() => p.t match { + case bias `(Nat)->:` (ArrayType(h, ArrayType(w, dt: DataType)) ->: + ArrayType(_, ArrayType(_, _)) ->: ArrayType(_, ArrayType(_, _))) => + nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), read) + ->: expT(ArrayType(4, ArrayType(7, dt)), read) ->: + expT(ArrayType(h - 3, ArrayType(w - 6, dt)), write) + ) + } + + case rg8p.copyToL1() => p.t match { + case (dt: DataType) ->: (_: DataType) => + expT(dt, read) ->: expT(dt, write) + case _ => error() + } + + case rg8p.copyToL2() => p.t match { + case (dt: DataType) ->: (_: DataType) => + expT(dt, read) ->: expT(dt, write) + case _ => error() + } + + // case n `(Nat)->:` ((dt1: DataType) ->: (dt2: DataType)) => + // nFunT(n, expT(dt1, ai) ->: expT(dt2, ai)) + case rg8p.copy2DOffsetToL1() => p.t match { + case offsetH `(Nat)->:` (offsetW `(Nat)->:` ((ArrayType(h, ArrayType(w, dt: DataType))) ->: (_: DataType))) => + nFunT(offsetH, nFunT(offsetW, expT(h`.`w`.`dt, read) ->: expT((h + 2 * offsetH)`.`(w + 2 * offsetW)`.`dt, write))) + case _ => error() + } + + case rg8p.allocL1() => p.t match { + case (dt: DataType) ->: (_: DataType) => + expT(dt, write) ->: expT(dt, read) + case _ => error() + } + + case rg8p.allocL2() => p.t match { + case (dt: DataType) ->: (_: DataType) => + expT(dt, write) ->: expT(dt, read) + case _ => error() + } } checkConsistency(p.t, primitiveType) diff --git a/src/main/scala/shine/DPIA/fromRise.scala b/src/main/scala/shine/DPIA/fromRise.scala index 2944bf635..ebdd2aea7 100644 --- a/src/main/scala/shine/DPIA/fromRise.scala +++ b/src/main/scala/shine/DPIA/fromRise.scala @@ -100,9 +100,11 @@ object fromRise { import rise.openCL.{primitives => rocl} import rise.openMP.{primitives => romp} import rise.Cuda.{primitives => rcuda} + import rise.GAP8.{primitives => rgap8} import shine.OpenCL.primitives.{functional => ocl} import shine.OpenMP.primitives.{functional => omp} import shine.cuda.primitives.{functional => cuda} + import shine.GAP8.primitives.{functional => gap8} import shine.DPIA.Types.MatchingDSL._ import shine.OpenCL.{Global, Warp, WorkGroup, Lane, Local} @@ -920,13 +922,97 @@ object fromRise { case core.reduce() => throw new Exception(s"$p has no implementation") - case rise.GAP8.primitives.gap8RunPrimitive() => fromType { + case rgap8.gap8RunPrimitive() => fromType { case nFunT(cores, expT(t, `write`) ->: _) => depFun(NatKind, cores)(fun[ExpType](expT(t, write), e => shine.GAP8.primitives.functional.Run(cores)(t, e) )) } + case rgap8.gap8hwConv3x3() => fromType { + case nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `write`)) => + depFun(NatKind, bias)( + fun[ExpType](expT(ArrayType(h, ArrayType(w, dt)), read), input => + fun[ExpType](expT(ArrayType(3, ArrayType(3, dt)), read), filter => + gap8.FunConv3x3(h, w, dt, bias, input, filter) + ) + ) + ) + } + + case rgap8.gap8hwConv5x5() => fromType { + case nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `write`)) => + depFun(NatKind, bias)( + fun[ExpType](expT(ArrayType(h, ArrayType(w, dt)), read), input => + fun[ExpType](expT(ArrayType(5, ArrayType(5, dt)), read), filter => + gap8.FunConv5x5(h, w, dt, bias, input, filter) + ) + ) + ) + } + + case rgap8.gap8hwConv7x7() => fromType { + case nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `write`)) => + depFun(NatKind, bias)( + fun[ExpType](expT(ArrayType(h, ArrayType(w, dt)), read), input => + fun[ExpType](expT(ArrayType(7, ArrayType(7, dt)), read), filter => + gap8.FunConv7x7(h, w, dt, bias, input, filter) + ) + ) + ) + } + + case rgap8.gap8hwConv7x4() => fromType { + case nFunT(bias, expT(ArrayType(h, ArrayType(w, dt)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `read`) ->: + expT(ArrayType(_, ArrayType(_, _)), `write`)) => + depFun(NatKind, bias)( + fun[ExpType](expT(ArrayType(h, ArrayType(w, dt)), read), input => + fun[ExpType](expT(ArrayType(4, ArrayType(7, dt)), read), filter => + gap8.FunConv7x4(h, w, dt, bias, input, filter) + ) + ) + ) + } + + case rgap8.copyToL1() => fromType { + case expT(t, `read`) ->: expT(_, `write`) => + fun[ExpType](expT(t, read), e => gap8.CopyToL1(t, e)) + } + + case rgap8.copyToL2() => fromType { + case expT(dt, `read`) ->: expT(_, `write`) => + fun[ExpType](expT(dt, read), e => gap8.CopyToL2(dt, e)) + } + //case nFunT(n, expT(ArrayType(_, t), a) ->: + // expT(ArrayType(m, ArrayType(_, _)), _)) + // => + // depFun(NatKind, n)( + // fun[ExpType](expT({m*n}`.`t, a), e => + // Split(n, m, a, t, e))) + + case rgap8.copy2DOffsetToL1() => fromType { + case nFunT(offsetH, nFunT(offsetW, expT(ArrayType(h, ArrayType(w, dt)), `read`) ->: expT(_, `write`))) => + depFun(NatKind, offsetH)(depFun(NatKind, offsetW)(fun[ExpType](expT(h`.`w`.`dt, read), input => + gap8.Copy2DOffsetToL1(dt, h, w, offsetH, offsetW, input) + ))) + } + + case rgap8.allocL1() => fromType { + case expT(dt, `write`) ->: expT(_, `read`) => + fun[ExpType](expT(dt, write), e => gap8.AllocL1(dt, e)) + } + + case rgap8.allocL2() => fromType { + case expT(dt, `write`) ->: expT(_, `read`) => + fun[ExpType](expT(dt, write), e => gap8.AllocL2(dt, e)) + } case _ => throw new Exception(s"Missing rule for $p") } diff --git a/src/main/scala/shine/GAP8/AST/Types.scala b/src/main/scala/shine/GAP8/AST/Types.scala new file mode 100644 index 000000000..8dbb9c575 --- /dev/null +++ b/src/main/scala/shine/GAP8/AST/Types.scala @@ -0,0 +1,49 @@ +package shine.GAP8.AST + +import rise.core.types.DataType + +object Types { + //TODO: Refactor in the style of OpenCL + def sizeInBytes(dt: DataType): Int = dt match { + case rise.core.types.DataType.bool => 1 + case rise.core.types.DataType.u8 => 1 + case rise.core.types.DataType.u16 => 2 + case rise.core.types.DataType.u32 => 4 + case rise.core.types.DataType.u64 => 8 + case rise.core.types.DataType.i8 => 1 + case rise.core.types.DataType.i16 => 2 + case rise.core.types.DataType.i32 => 4 + case rise.core.types.DataType.i64 => 8 + case rise.core.types.DataType.int => 4 + case rise.core.types.DataType.NatType => 4 + case rise.core.types.DataType.IndexType(size) => 4 + case rise.core.types.DataType.VectorType(size, elemType) => (sizeInBytes(elemType) * size).evalInt + case rise.core.types.DataType.PairType(e1, e2) => sizeInBytes(e1) + sizeInBytes(e2) + case rise.core.types.DataType.ArrayType(size, elemType) => (sizeInBytes(elemType) * size).evalInt + case rise.core.types.DataType.DepArrayType(size, natToData) => ??? + case _ => + throw new RuntimeException("Should not happen") + } + + def toStdint(dt: DataType): shine.C.AST.Type = { + dt match { + case rise.core.types.DataType.bool => shine.C.AST.BasicType("bool") + case rise.core.types.DataType.u8 => shine.C.AST.Type.u8 + case rise.core.types.DataType.u16 => shine.C.AST.Type.u16 + case rise.core.types.DataType.u32 => shine.C.AST.Type.u32 + case rise.core.types.DataType.u64 => shine.C.AST.Type.u64 + case rise.core.types.DataType.i8 => shine.C.AST.Type.i8 + case rise.core.types.DataType.i16 => shine.C.AST.Type.i16 + case rise.core.types.DataType.i32 => shine.C.AST.Type.i32 + case rise.core.types.DataType.i64 => shine.C.AST.Type.i64 + case rise.core.types.DataType.int => shine.C.AST.Type.int + case rise.core.types.DataType.f32 => shine.C.AST.Type.float + case rise.core.types.DataType.f64 => shine.C.AST.Type.double + case rise.core.types.DataType.ArrayType(size, elemType) => toStdint(elemType) + case _ => throw new RuntimeException("Not implemented") + } + } +} + +//TODO +case class SizeInBytes() diff --git a/src/main/scala/shine/GAP8/Compilation/AcceleratorCodeGenerator.scala b/src/main/scala/shine/GAP8/Compilation/AcceleratorCodeGenerator.scala new file mode 100644 index 000000000..cdecea538 --- /dev/null +++ b/src/main/scala/shine/GAP8/Compilation/AcceleratorCodeGenerator.scala @@ -0,0 +1,337 @@ +package shine.GAP8.Compilation + +import arithexpr.arithmetic +import arithexpr.arithmetic.ArithExpr +import arithexpr.arithmetic.ArithExpr.toInt +import rise.core.types.DataType +import shine.C.Compilation.CodeGenerator.CIntExpr +import shine.DPIA.Compilation.{CodeGenerator, TranslationContext} +import shine.DPIA.{Nat, freshName} +import shine.DPIA.Phrases.{Identifier, Lambda, Phrase, PhrasePair} +import shine.DPIA.Types.{CommType, ExpType} +import shine.GAP8.{ConvolutionFilterSize, DMATransferType} +import shine.GAP8.primitives.functional.Cast +import shine.GAP8.primitives.imperative._ +import shine.{C, OpenMP} + +import scala.collection.{immutable, mutable} + +// scalastyle:off +class AcceleratorCodeGenerator(override val decls: C.Compilation.CodeGenerator.Declarations, + override val ranges: C.Compilation.CodeGenerator.Ranges) + extends OpenMP.CodeGenerator(decls, ranges) { + override def name: String = "GAP8 ACC" + + override def translationContext: TranslationContext = super.translationContext + + override def updatedRanges(key: String, value: arithexpr.arithmetic.Range): AcceleratorCodeGenerator = + new AcceleratorCodeGenerator(decls, ranges.updated(key, value)) + + override def exp(env: Environment, + path: List[shine.C.Compilation.CodeGenerator.PathExpr], + cont: Expr => Stmt): Phrase[ExpType] => Stmt = { + case Cast(_, _, input) => + super.exp(env, path, cont)(input) + case other => + super.exp(env, path, cont)(other) + } + + override def cmd(env: Environment): Phrase[CommType] => Stmt = { + //TODO: Supoort multicycle output for 3x3 + case Conv3x3(h, w, dt, bias, in, filter, out) => + out |> acc(env, Nil, (outputC: C.AST.Expr) => { + in |> exp(env, Nil, (inC: C.AST.Expr) => { + filter |> exp(env, Nil, (filterC: C.AST.Expr) => { + generateCalls(shine.GAP8._3x3, h, w, bias, inC, filterC, outputC) + }) + }) + }) + case Conv5x5(h, w, dt, bias, in, filter, out) => + out |> acc(env, Nil, (outputC: C.AST.Expr) => { + in |> exp(env, Nil, (inC: C.AST.Expr) => { + filter |> exp(env, Nil, (filterC: C.AST.Expr) => { + generateCalls(shine.GAP8._5x5, h, w, bias, inC, filterC, outputC) + }) + }) + }) + case Conv7x7(h, w, dt, bias, in, filter, out) => + out |> acc(env, Nil, (outputC: C.AST.Expr) => { + in |> exp(env, Nil, (inC: C.AST.Expr) => { + filter |> exp(env, Nil, (filterC: C.AST.Expr) => { + generateCalls(shine.GAP8._7x7, h, w, bias, inC, filterC, outputC) + }) + }) + }) + case Conv7x4(h, w, dt, bias, in, filter, out) => + out |> acc(env, Nil, (outputC: C.AST.Expr) => { + in |> exp(env, Nil, (inC: C.AST.Expr) => { + filter |> exp(env, Nil, (filterC: C.AST.Expr) => { + generateCalls(shine.GAP8._7x4, h, w, bias, inC, filterC, outputC) + }) + }) + }) + + /** + * Generates a call to DMA transfer + * rt_dma_memcpy(src, dest, size, direction, merge, struct) + * rt_dma_wait(struct) + * ext loc + * TODO: Rethink this as it issues a call which will wait for the transfer to complete + * immediately after the transfer has begun. Separating these two concerns could enable + * parallelization of transfers and other useful calculations + * */ + case copy@DmaCopy(transferType) => + val size = shine.GAP8.AST.Types.sizeInBytes(copy.dt) + copy.dst |> acc(env, List(CIntExpr(0)), (dstC: C.AST.Expr) => { + copy.src |> exp(env, List(CIntExpr(0)), (srcC: C.AST.Expr) => { + val (ext, loc) = transferType match { + case shine.GAP8.L1toL2 => + (dstC, srcC) + case shine.GAP8.L2toL1 => + (srcC, dstC) + } + C.AST.Block(Seq( + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("rt_dma_memcpy"), + Seq( + // TODO: Reference fetch via ampersand might be needed (ext,loc) + C.AST.Cast(C.AST.Type.u32, C.AST.UnaryExpr(C.AST.UnaryOperator.&, ext)), + C.AST.Cast(C.AST.Type.u32, C.AST.UnaryExpr(C.AST.UnaryOperator.&, loc)), + C.AST.Literal(size.toString), + C.AST.Literal(transferType.toGAP8string), + C.AST.Literal(0.toString), + C.AST.Literal("&L2toL1") + ) + )), + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("rt_dma_wait"), + Seq(C.AST.Literal("&L2toL1")) + )) + )) + }) + }) + + //short int* ImageIn_L1_Temp_Converted = + // (short int*) rt_alloc(RT_ALLOC_CL_DATA, (IMG_W + 2) * ((IMG_H / NUM_STRIPES) + 2) * sizeof(short int)); + // Array Type Memory Type Size + // DataType Nat / Address Space Nat + case malloc@MemoryAlloc(memoryType) => { + val dt = malloc.dt + malloc.f match { + case Lambda(v, p) => + val ve = Identifier(s"${v.name}_e", v.t.t1) + val va = Identifier(s"${v.name}_a", v.t.t2) + val vC = C.AST.DeclRef(v.name) + + C.AST.Block(Seq( + C.AST.DeclStmt(C.AST.VarDecl( + vC.name, + arrayToPointerType(dt), + Some( + C.AST.Cast( + C.AST.PointerType(shine.GAP8.AST.Types.toStdint(dt), false), + C.AST.FunCall( + C.AST.DeclRef("rt_alloc"), + Seq( + C.AST.Literal(memoryType.toAllocString), + C.AST.Literal(shine.GAP8.AST.Types.sizeInBytes(dt).toString) + ) + ) + ) + ) + )), + Phrase.substitute(PhrasePair(ve, va), `for` = v, `in` = p) |> + cmd(env updatedIdentEnv (ve -> vC) updatedIdentEnv (va -> vC)), + //TODO: Generate dealloc / free? + C.AST.ExprStmt( + C.AST.FunCall( + C.AST.DeclRef("rt_free"), + Seq( + C.AST.Literal(memoryType.toAllocString), + C.AST.Literal(vC.name), + C.AST.Literal(shine.GAP8.AST.Types.sizeInBytes(dt).toString) + ) + ) + ) + )) + case _ => throw new RuntimeException("This should not happen") + } + } + + case MemorySet(dt, value, array) => + array |> acc(env, Nil, (arrayC: C.AST.Expr) => { + value |> exp(env, Nil, (valueC: C.AST.Expr) => { + C.AST.Block(Seq( + C.AST.Comment("memset"), + C.AST.ExprStmt(C.AST.FunCall(C.AST.DeclRef("memset"), Seq( + arrayC, + valueC, + C.AST.Literal(shine.GAP8.AST.Types.sizeInBytes(dt).toString) + ))) + )) + }) + }) + + //rt_dma_memcpy_2d(unsigned int ext, + // unsigned int loc, + // unsigned short size, + // unsigned short stride, + // unsigned short length, + // rt_dma_dir_e dir, int merge, rt_dma_copy_t *copy); + // stride 2D stride, which is the number of bytes which are added to the beginning of the current line to switch to the next one. Must fit in 16 bits, i.e. must be less than 65536. + // length 2D length, which is the number of transfered bytes after which the DMA will switch to the next line. Must fit in 16 bits, i.e. must be less than 65536. + case copy@Dma2DOffsetCopy(transferType) => + copy.dst |> acc(env, CIntExpr(0) :: Nil, (dstC: C.AST.Expr) => { + copy.src |> exp(env, CIntExpr(0) :: Nil, (srcC: C.AST.Expr) => { + val (ext, loc) = transferType match { + case shine.GAP8.L1toL2 => + (dstC, srcC) + case shine.GAP8.L2toL1 => + (srcC, dstC) + } + val stride = toInt(copy.offsetH) * shine.GAP8.AST.Types.sizeInBytes(copy.dt) + val length = toInt(copy.w) * shine.GAP8.AST.Types.sizeInBytes(copy.dt) + val size = shine.GAP8.AST.Types.sizeInBytes(copy.dt) * copy.h * copy.w + C.AST.Block(Seq( + C.AST.Comment("dma2dOffsetCopy"), + C.AST.ExprStmt(C.AST.FunCall(C.AST.DeclRef("rt_dma_memcpy_2d"), Seq( + C.AST.Cast(C.AST.Type.u32, C.AST.UnaryExpr(C.AST.UnaryOperator.&, ext)), + C.AST.Cast(C.AST.Type.u32, C.AST.UnaryExpr(C.AST.UnaryOperator.&, loc)), + C.AST.Literal(size.toString), + C.AST.Literal(stride.toString), + C.AST.Literal(length.toString), + C.AST.Literal(transferType.toGAP8string), + C.AST.Literal(0.toString), + C.AST.Literal("&L2toL1") + ))), + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("rt_dma_wait"), + Seq(C.AST.Literal("&L2toL1")) + )) + )) + }) + }) + + case phrase => phrase |> super.cmd(env) + } + + //*(x401 + (i + 1) * (322) + (j + 1)) = *(e48 + (4480 * i_410) + i * 320 + j); + //TODO: Finish + private def generate2DLoopTransfer( + width: Int, height: Int, + src: C.AST.Expr, dst: C.AST.Expr, + offsetX: Int, offsetY: Int): Stmt = { + val firstVar = freshName("dma2d_") + val secondVar = freshName("dma2d_") + + /*C.AST.FunDecl( + name="ex_mapfor", + returnType = C.AST.Type.void, + params = Seq( + C.AST.ParamDecl("output", C.AST.PointerType(C.AST.Type.int)), + C.AST.ParamDecl("n446", C.AST.Type.int), + C.AST.ParamDecl("e447", C.AST.PointerType(C.AST.Type.int)) + ), + body = C.AST.Stmts(C.AST.Code("asdf"), C.AST.ForLoop(???, ???, ???, ???)) + )*/ + + C.AST.ForLoop( + init = C.AST.DeclStmt(C.AST.VarDecl(firstVar, C.AST.Type.int, None)), + cond = C.AST.BinaryExpr(C.AST.Literal(firstVar), C.AST.BinaryOperator.<, C.AST.Literal(width.toString)), + increment = C.AST.Assignment(C.AST.DeclRef(firstVar), C.AST.BinaryExpr(C.AST.DeclRef(firstVar), C.AST.BinaryOperator.+, C.AST.Literal("1"))), + body = C.AST.Block(Seq( + C.AST.ForLoop( + init = C.AST.DeclStmt(C.AST.VarDecl(secondVar, C.AST.Type.int, None)), + cond = C.AST.BinaryExpr(C.AST.Literal(secondVar), C.AST.BinaryOperator.<, C.AST.Literal(height.toString)), + increment = C.AST.Assignment(C.AST.DeclRef(secondVar), C.AST.BinaryExpr(C.AST.DeclRef(secondVar), C.AST.BinaryOperator.+, C.AST.Literal("1"))), + body = C.AST.Block(Seq( + C.AST.ExprStmt(C.AST.Assignment( + C.AST.UnaryExpr(C.AST.UnaryOperator.*, C.AST.ArithmeticExpr(???)), + C.AST.UnaryExpr(C.AST.UnaryOperator.*, C.AST.ArithmeticExpr(???)) + )) + )) + ) + )) + ) + } + + private def generateCalls(fs: ConvolutionFilterSize, h: Nat, w: Nat, bias: Nat, + in: Expr, filter: Expr, output: Expr): Stmt = { + C.AST.Block(Seq( + hwceEnableCall, + hwceGenericInitCall(fs), + hwceSetYinModeCall(), + generateHwceCallFunction(fs, h, w, bias, in, filter, output), + hwceDisableCall + )) + } + + private def generateHwceCallFunction(fs: ConvolutionFilterSize, h: Nat, w: Nat, bias: Nat, + in: Expr, filter: Expr, output: Expr): Stmt = { + fs match { + case shine.GAP8._3x3 => + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef(fs.functionName), + Seq(in, + output, + C.AST.Literal("NULL"), + C.AST.Literal("NULL"), + filter, + C.AST.Literal(ArithExpr.toInt(bias).toString), + C.AST.Literal(ArithExpr.toInt(w).toString), + C.AST.Literal(ArithExpr.toInt(h).toString), + C.AST.Literal("0x7") + ) + )) + case _ => + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef(fs.functionName), + Seq(in, + output, + filter, + C.AST.Literal(ArithExpr.toInt(bias).toString), + C.AST.Literal(ArithExpr.toInt(w).toString), + C.AST.Literal(ArithExpr.toInt(h).toString), + ) + )) + } + } + + //TODO: Lazy val + private val hwceEnableCall = C.AST.ExprStmt(C.AST.FunCall(C.AST.DeclRef("HWCE_Enable"), Seq())) + private val hwceDisableCall = C.AST.ExprStmt(C.AST.FunCall(C.AST.DeclRef("HWCE_Disable"), Seq())) + private val hwceSoftResetCall = C.AST.ExprStmt(C.AST.FunCall(C.AST.DeclRef("HwCE_SoftReset"), Seq())) + private def hwceSetInputBiasCall(bias: Int = 0) = C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("HwCE_SetInputBias"), Seq(C.AST.Literal(bias.toString)) + )) + private def hwceSetYinModeCall(mode: Int = 1) = C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("HwCE_SetYinMode"), + Seq(C.AST.Cast(C.AST.Type.u32, C.AST.Literal(mode.toString))) + )) + private def hwceGenericInitCall(fs: ConvolutionFilterSize, wstride: Int = 0, qnorm: Int = 0) = + C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("HWCE_GenericInit"), + Seq( + C.AST.Cast(C.AST.Type.u32, C.AST.Literal(fs.toBackendConst)), + C.AST.Cast(C.AST.Type.u32, C.AST.Literal(wstride.toString)), + C.AST.Cast(C.AST.Type.u32, C.AST.Literal(qnorm.toString)) + ) + )) + + private def arrayToPointerType(dt: DataType): Type = + dt match { + case rise.core.types.DataType.ArrayType(size, elemType) => + C.AST.PointerType( + C.AST.BasicType(shine.GAP8.AST.Types.toStdint(elemType).toString, false) + ) + case _ => typ(dt) + } + override def typ(dt: DataType): Type = super.typ(dt) +} + +object AcceleratorCodeGenerator { + def apply() = new AcceleratorCodeGenerator( + mutable.ListBuffer[C.AST.Decl](), + immutable.Map[String, arithmetic.Range]() + ) +} diff --git a/src/main/scala/shine/GAP8/Compilation/HostCodeGenerator.scala b/src/main/scala/shine/GAP8/Compilation/HostCodeGenerator.scala index dc8b1ee95..67870c187 100644 --- a/src/main/scala/shine/GAP8/Compilation/HostCodeGenerator.scala +++ b/src/main/scala/shine/GAP8/Compilation/HostCodeGenerator.scala @@ -30,6 +30,10 @@ case class HostCodeGenerator( ) extends CodeGenerator(decls, ranges){ override def name: String = "GAP8 Host" + override def updatedRanges(key: String, + value: arithexpr.arithmetic.Range): HostCodeGenerator = + new HostCodeGenerator(decls, ranges.updated(key, value), acceleratorFunctions) + override def cmd(env: Environment): Phrase[CommType] => Stmt = { case k@KernelCallCmd(kernelName, numCores, numArgs) => val calledKernel = acceleratorFunctions @@ -172,6 +176,11 @@ case class HostCodeGenerator( private def managedTyp(dt: DataType): C.AST.Type = dt match { case ArrayType(_, elemType) => C.AST.PointerType(typ(elemType)) + //TODO: Rethink + case PairType(dt1, dt2) => C.AST.StructType( + "Tuple_" + dt1.toString + "_" + dt2.toString, + Seq((typ(dt1), "_fst"), (typ(dt2), "_snd")) + ) case _ => throw new Exception(s"did not expect $dt") } diff --git a/src/main/scala/shine/GAP8/Compilation/SeparateHostAndAcceleratorCode.scala b/src/main/scala/shine/GAP8/Compilation/SeparateHostAndAcceleratorCode.scala index a3978bd34..96170f233 100644 --- a/src/main/scala/shine/GAP8/Compilation/SeparateHostAndAcceleratorCode.scala +++ b/src/main/scala/shine/GAP8/Compilation/SeparateHostAndAcceleratorCode.scala @@ -2,7 +2,7 @@ package shine.GAP8.Compilation import arithexpr.arithmetic.ArithExpr.toInt import arithexpr.arithmetic.NamedVar -import rise.core.types.{DataKind, DataType, NatIdentifier, NatKind} +import rise.core.types.{DataKind, DataType, NatIdentifier, NatKind, NatToNat, NatToNatLambda} import rise.core.types.DataType._ import shine.DPIA.Compilation.FunDef import shine.DPIA.Phrases._ @@ -109,6 +109,12 @@ object SeparateHostAndAcceleratorCode { case _ => Continue(p, this) } + override def natToNat(ft: NatToNat): NatToNat = ft match { + case NatToNatLambda(x, b) => + NatToNatLambda(x, this.copy(boundN = boundN + x).nat(b)) + case _ => super.natToNat(ft) + } + override def nat[N <: Nat](n: N): N = { natIdents ++= n.varList.collect { case v: NamedVar if !boundN(v) => v diff --git a/src/main/scala/shine/GAP8/ConvolutionFilterSize.scala b/src/main/scala/shine/GAP8/ConvolutionFilterSize.scala new file mode 100644 index 000000000..3c52b285b --- /dev/null +++ b/src/main/scala/shine/GAP8/ConvolutionFilterSize.scala @@ -0,0 +1,22 @@ +package shine.GAP8 + +sealed trait ConvolutionFilterSize { + def toBackendConst: String + def functionName: String +} +case object _3x3 extends ConvolutionFilterSize { + override def toBackendConst: String = "HWCE_CONV3x3" + override def functionName: String = "HWCE_ProcessOneTile3x3_MultiOut" +} +case object _5x5 extends ConvolutionFilterSize { + override def toBackendConst: String = "HWCE_CONV5x5" + override def functionName: String = "HWCE_ProcessOneTile5x5" +} +case object _7x7 extends ConvolutionFilterSize { + override def toBackendConst: String = "HWCE_CONV7x7" + override def functionName: String = "HWCE_ProcessOneTile7x7" +} +case object _7x4 extends ConvolutionFilterSize { + override def toBackendConst: String = "HWCE_CONV7x7" + override def functionName: String = "HWCE_ProcessOneTile7x4" +} diff --git a/src/main/scala/shine/GAP8/DMATransferType.scala b/src/main/scala/shine/GAP8/DMATransferType.scala new file mode 100644 index 000000000..8636665b6 --- /dev/null +++ b/src/main/scala/shine/GAP8/DMATransferType.scala @@ -0,0 +1,13 @@ +package shine.GAP8 + +sealed trait DMATransferType { + def toGAP8string: String +} + +case object L1toL2 extends DMATransferType { + override def toGAP8string: String = "RT_DMA_DIR_LOC2EXT" +} + +case object L2toL1 extends DMATransferType { + override def toGAP8string: String = "RT_DMA_DIR_EXT2LOC" +} \ No newline at end of file diff --git a/src/main/scala/shine/GAP8/DSL/package.scala b/src/main/scala/shine/GAP8/DSL/package.scala new file mode 100644 index 000000000..136a0aa2f --- /dev/null +++ b/src/main/scala/shine/GAP8/DSL/package.scala @@ -0,0 +1,16 @@ +package shine.GAP8 + +import rise.core.types.DataType +import shine.DPIA.DSL.λ +import shine.DPIA.Phrases.Phrase +import shine.DPIA.Types.CommType +import shine.DPIA.{VarType, varT} +import shine.GAP8.primitives.imperative.MemoryAlloc + +package object DSL { + object GAP8MemoryAlloc { + def apply(memoryType: shine.GAP8.MemoryType) + (dt: DataType, f: Phrase[VarType] => Phrase[CommType]): MemoryAlloc = + MemoryAlloc(memoryType)(dt, λ(varT(dt))(v => f(v))) + } +} diff --git a/src/main/scala/shine/GAP8/MemoryType.scala b/src/main/scala/shine/GAP8/MemoryType.scala new file mode 100644 index 000000000..721c1fd05 --- /dev/null +++ b/src/main/scala/shine/GAP8/MemoryType.scala @@ -0,0 +1,12 @@ +package shine.GAP8 + +sealed trait MemoryType { + def toAllocString: String +} + +case object L1 extends MemoryType { + override def toAllocString: String = "RT_ALLOC_CL_DATA" +} +case object L2 extends MemoryType { + override def toAllocString: String = "RT_ALLOC_L2_CL_DATA" +} diff --git a/src/main/scala/shine/GAP8/Module.scala b/src/main/scala/shine/GAP8/Module.scala index e6928dcff..bcf9c6882 100644 --- a/src/main/scala/shine/GAP8/Module.scala +++ b/src/main/scala/shine/GAP8/Module.scala @@ -88,6 +88,18 @@ object Module { )) } + //TODO: Recheck, this is not needed if HWCE is not used. (Move to AcceleratorCodeGenerator?) + /** + * Sets the corresponding bit in the event mask to 1. This is presumably necessary to enable the logic needed + * to work with HWCE + * */ + val setEventMaskStmt = C.AST.ExprStmt(C.AST.FunCall( + C.AST.DeclRef("eu_evt_maskSet"), + Seq( + C.AST.Literal("1 << ARCHI_CL_EVT_ACC0") + ) + )) + val wrappedFunction = C.AST.Function( code = C.AST.FunDecl( @@ -95,7 +107,8 @@ object Module { returnType = C.AST.Type.void, params = Seq(C.AST.ParamDecl("args", C.AST.PointerType(C.AST.Type.void))), body = C.AST.Block( - Seq(structCastDecl) + Seq(setEventMaskStmt) + ++ Seq(structCastDecl) ++ unpackingStmts ++ accFunction.map(f => Seq(f)).getOrElse(Seq()).map(_.code.body) ) diff --git a/src/main/scala/shine/GAP8/primitives/functional/AllocL1.scala b/src/main/scala/shine/GAP8/primitives/functional/AllocL1.scala new file mode 100644 index 000000000..9dc947c83 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/AllocL1.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class AllocL1(val dt: DataType, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(dt, write) + true + } + override val t: ExpType = expT(dt, read) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): AllocL1 = new AllocL1(v.data(dt), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/AllocL2.scala b/src/main/scala/shine/GAP8/primitives/functional/AllocL2.scala new file mode 100644 index 000000000..529bf6bea --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/AllocL2.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class AllocL2(val dt: DataType, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(dt, write) + true + } + override val t: ExpType = expT(dt, read) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): AllocL2 = new AllocL2(v.data(dt), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/Cast.scala b/src/main/scala/shine/GAP8/primitives/functional/Cast.scala new file mode 100644 index 000000000..263c817ec --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/Cast.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Cast(val dt1: DataType, val dt2: DataType, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(dt1, read) + true + } + override val t: ExpType = expT(dt2, read) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Cast = new Cast(v.data(dt1), v.data(dt2), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/Copy2DOffsetToL1.scala b/src/main/scala/shine/GAP8/primitives/functional/Copy2DOffsetToL1.scala new file mode 100644 index 000000000..0eff9fecd --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/Copy2DOffsetToL1.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Copy2DOffsetToL1(val dt: DataType, val h: Nat, val w: Nat, val offsetH: Nat, val offsetW: Nat, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(ArrayType(h, ArrayType(w, dt)), read) + true + } + override val t: ExpType = expT(ArrayType(h + 2 * offsetH, ArrayType(w + 2 * offsetW, dt)), write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Copy2DOffsetToL1 = new Copy2DOffsetToL1(v.data(dt), v.nat(h), v.nat(w), v.nat(offsetH), v.nat(offsetW), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/CopyToL1.scala b/src/main/scala/shine/GAP8/primitives/functional/CopyToL1.scala new file mode 100644 index 000000000..b23324332 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/CopyToL1.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class CopyToL1(val dt: DataType, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(dt, read) + true + } + override val t: ExpType = expT(dt, write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): CopyToL1 = new CopyToL1(v.data(dt), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/CopyToL2.scala b/src/main/scala/shine/GAP8/primitives/functional/CopyToL2.scala new file mode 100644 index 000000000..8b87ad227 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/CopyToL2.scala @@ -0,0 +1,19 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class CopyToL2(val dt: DataType, val input: Phrase[ExpType]) extends ExpPrimitive { + assert { + input :: expT(dt, read) + true + } + override val t: ExpType = expT(dt, write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): CopyToL2 = new CopyToL2(v.data(dt), VisitAndRebuild(input, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/FunConv3x3.scala b/src/main/scala/shine/GAP8/primitives/functional/FunConv3x3.scala new file mode 100644 index 000000000..2e629a5fd --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/FunConv3x3.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class FunConv3x3(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType]) extends ExpPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(3, ArrayType(3, dt)), read) + true + } + override val t: ExpType = expT(ArrayType(h - 2, ArrayType(w - 2, dt)), write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): FunConv3x3 = new FunConv3x3(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/FunConv5x5.scala b/src/main/scala/shine/GAP8/primitives/functional/FunConv5x5.scala new file mode 100644 index 000000000..5b39efef7 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/FunConv5x5.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class FunConv5x5(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType]) extends ExpPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(5, ArrayType(5, dt)), read) + true + } + override val t: ExpType = expT(ArrayType(h - 4, ArrayType(w - 4, dt)), write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): FunConv5x5 = new FunConv5x5(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/FunConv7x4.scala b/src/main/scala/shine/GAP8/primitives/functional/FunConv7x4.scala new file mode 100644 index 000000000..16d883616 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/FunConv7x4.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class FunConv7x4(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType]) extends ExpPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(4, ArrayType(7, dt)), read) + true + } + override val t: ExpType = expT(ArrayType(h - 3, ArrayType(w - 6, dt)), write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): FunConv7x4 = new FunConv7x4(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/FunConv7x7.scala b/src/main/scala/shine/GAP8/primitives/functional/FunConv7x7.scala new file mode 100644 index 000000000..aad82c108 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/functional/FunConv7x7.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.functional +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class FunConv7x7(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType]) extends ExpPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(7, ArrayType(7, dt)), read) + true + } + override val t: ExpType = expT(ArrayType(h - 6, ArrayType(w - 6, dt)), write) + override def visitAndRebuild(v: VisitAndRebuild.Visitor): FunConv7x7 = new FunConv7x7(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/functional/primitives.dpia b/src/main/scala/shine/GAP8/primitives/functional/primitives.dpia index 02d24e1c5..f05df395c 100644 --- a/src/main/scala/shine/GAP8/primitives/functional/primitives.dpia +++ b/src/main/scala/shine/GAP8/primitives/functional/primitives.dpia @@ -1,3 +1,51 @@ def kernelCall{name: String, cores: Int, n:Int}(inTs: n*data, outT: data, args: n*exp[*inTs, read]): exp[outT, write] def run{cores: Nat}(dt: data, input: exp[dt, write]): exp[dt, write] + +def funConv3x3( + h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[3.3.dt, read] +): exp[(h-2).(w-2).dt, write] + +def funConv5x5( + h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[5.5.dt, read] +): exp[(h-4).(w-4).dt, write] + +def funConv7x7( + h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[7.7.dt, read] +): exp[(h-6).(w-6).dt, write] + +def funConv7x4( + h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[4.7.dt, read] +): exp[(h-3).(w-6).dt, write] + +def copyToL1(dt: data, input: exp[dt, read]): exp[dt, write] +def copyToL2(dt: data, input: exp[dt, read]): exp[dt, write] + +def copy2DOffsetToL1(dt: data, h: nat, w: nat, + offsetH: nat, offsetW: nat, + input: exp[h.w.dt, read]): exp[(h+2*offsetH).(w+2*offsetW).dt, write] + +def allocL1(dt: data, input: exp[dt, write]): exp[dt, read] +def allocL2(dt: data, input: exp[dt, write]): exp[dt, read] + +def cast(dt1: data, dt2: data, input: exp[dt1, read]): exp[dt2, read] \ No newline at end of file diff --git a/src/main/scala/shine/GAP8/primitives/imperative/Conv3x3.scala b/src/main/scala/shine/GAP8/primitives/imperative/Conv3x3.scala new file mode 100644 index 000000000..c2e0d32ce --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/Conv3x3.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Conv3x3(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType], val out: Phrase[AccType]) extends CommandPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(10, dt), read) + out :: accT(ArrayType(h - 2, ArrayType(w - 2, dt))) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Conv3x3 = new Conv3x3(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v), VisitAndRebuild(out, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/Conv5x5.scala b/src/main/scala/shine/GAP8/primitives/imperative/Conv5x5.scala new file mode 100644 index 000000000..5d9608b15 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/Conv5x5.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Conv5x5(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType], val out: Phrase[AccType]) extends CommandPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(26, dt), read) + out :: accT(ArrayType(h - 4, ArrayType(w - 4, dt))) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Conv5x5 = new Conv5x5(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v), VisitAndRebuild(out, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/Conv7x4.scala b/src/main/scala/shine/GAP8/primitives/imperative/Conv7x4.scala new file mode 100644 index 000000000..a01b13273 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/Conv7x4.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Conv7x4(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType], val out: Phrase[AccType]) extends CommandPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(28, dt), read) + out :: accT(ArrayType(h - 3, ArrayType(w - 6, dt))) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Conv7x4 = new Conv7x4(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v), VisitAndRebuild(out, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/Conv7x7.scala b/src/main/scala/shine/GAP8/primitives/imperative/Conv7x7.scala new file mode 100644 index 000000000..796a6b698 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/Conv7x7.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Conv7x7(val h: Nat, val w: Nat, val dt: DataType, val bias: Nat, val in: Phrase[ExpType], val filter: Phrase[ExpType], val out: Phrase[AccType]) extends CommandPrimitive { + assert { + in :: expT(ArrayType(h, ArrayType(w, dt)), read) + filter :: expT(ArrayType(56, dt), read) + out :: accT(ArrayType(h - 6, ArrayType(w - 6, dt))) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Conv7x7 = new Conv7x7(v.nat(h), v.nat(w), v.data(dt), v.nat(bias), VisitAndRebuild(in, v), VisitAndRebuild(filter, v), VisitAndRebuild(out, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/Dma2DOffsetCopy.scala b/src/main/scala/shine/GAP8/primitives/imperative/Dma2DOffsetCopy.scala new file mode 100644 index 000000000..e720d1273 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/Dma2DOffsetCopy.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class Dma2DOffsetCopy(tt: shine.GAP8.DMATransferType)(val dt: DataType, val h: Nat, val w: Nat, val offsetH: Nat, val offsetW: Nat, val src: Phrase[ExpType], val dst: Phrase[AccType]) extends CommandPrimitive { + assert { + src :: expT(ArrayType(h, ArrayType(w, dt)), read) + dst :: accT(ArrayType(h + 2 * offsetH, ArrayType(w + 2 * offsetW, dt))) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): Dma2DOffsetCopy = new Dma2DOffsetCopy(tt)(v.data(dt), v.nat(h), v.nat(w), v.nat(offsetH), v.nat(offsetW), VisitAndRebuild(src, v), VisitAndRebuild(dst, v)) + def unwrap: (DataType, Nat, Nat, Nat, Nat, Phrase[ExpType], Phrase[AccType]) = (dt, h, w, offsetH, offsetW, src, dst) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/DmaCopy.scala b/src/main/scala/shine/GAP8/primitives/imperative/DmaCopy.scala new file mode 100644 index 000000000..4252da365 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/DmaCopy.scala @@ -0,0 +1,21 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class DmaCopy(tt: shine.GAP8.DMATransferType)(val dt: DataType, val src: Phrase[ExpType], val dst: Phrase[AccType]) extends CommandPrimitive { + assert { + src :: expT(dt, read) + dst :: accT(dt) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): DmaCopy = new DmaCopy(tt)(v.data(dt), VisitAndRebuild(src, v), VisitAndRebuild(dst, v)) + def unwrap: (DataType, Phrase[ExpType], Phrase[AccType]) = (dt, src, dst) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/MemoryAlloc.scala b/src/main/scala/shine/GAP8/primitives/imperative/MemoryAlloc.scala new file mode 100644 index 000000000..7d40909e8 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/MemoryAlloc.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class MemoryAlloc(mt: shine.GAP8.MemoryType)(val dt: DataType, val f: Phrase[FunType[PhrasePairType[ExpType, AccType], CommType]]) extends CommandPrimitive { + assert { + f :: FunType(PhrasePairType(expT(dt, read), accT(dt)), comm) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): MemoryAlloc = new MemoryAlloc(mt)(v.data(dt), VisitAndRebuild(f, v)) + def unwrap: (DataType, Phrase[FunType[PhrasePairType[ExpType, AccType], CommType]]) = (dt, f) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/MemorySet.scala b/src/main/scala/shine/GAP8/primitives/imperative/MemorySet.scala new file mode 100644 index 000000000..40b9552a2 --- /dev/null +++ b/src/main/scala/shine/GAP8/primitives/imperative/MemorySet.scala @@ -0,0 +1,20 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +// This file is automatically generated and should not be changed manually // +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // +package shine.GAP8.primitives.imperative +import arithexpr.arithmetic._ +import shine.DPIA.Phrases._ +import shine.DPIA.Types._ +import rise.core.types.{ FunType => _, DepFunType => _, TypePlaceholder => _, TypeIdentifier => _, ExprType => _, _ } +import rise.core.types.DataType._ +import rise.core.types.Kind.{ Identifier => _, _ } +import shine.DPIA._ +final case class MemorySet(val dt: DataType, val value: Phrase[ExpType], val array: Phrase[AccType]) extends CommandPrimitive { + assert { + value :: expT(int, read) + array :: accT(dt) + true + } + override val t: CommType = comm + override def visitAndRebuild(v: VisitAndRebuild.Visitor): MemorySet = new MemorySet(v.data(dt), VisitAndRebuild(value, v), VisitAndRebuild(array, v)) +} diff --git a/src/main/scala/shine/GAP8/primitives/imperative/primitives.dpia b/src/main/scala/shine/GAP8/primitives/imperative/primitives.dpia index 24aa5ec19..d40431c50 100644 --- a/src/main/scala/shine/GAP8/primitives/imperative/primitives.dpia +++ b/src/main/scala/shine/GAP8/primitives/imperative/primitives.dpia @@ -1 +1,43 @@ -def kernelCallCmd{name: String, cores: Int, n: Int}(inTs: n*data, dt: data, args: n*exp[*inTs, read], output: acc[dt]): comm +def kernelCallCmd{name: String, cores: Int, n: Int} + (inTs: n*data, dt: data, args: n*exp[*inTs, read], output: acc[dt]): comm + +def conv3x3(h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[10.dt, read], + out: acc[(h-2).(w-2).dt]): comm + +def conv5x5(h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[26.dt, read], + out: acc[(h-4).(w-4).dt]): comm + +def conv7x7(h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[56.dt, read], + out: acc[(h-6).(w-6).dt]): comm + +def conv7x4(h: nat, + w: nat, + dt: data, + bias: nat, + in: exp[h.w.dt, read], + filter: exp[28.dt, read], + out: acc[(h-3).(w-6).dt]): comm + +def dmaCopy{tt: shine.GAP8.DMATransferType}(dt: data, src: exp[dt, read], dst: acc[dt]): comm +def memoryAlloc{mt: shine.GAP8.MemoryType}(dt: data, f: var[dt] -> comm): comm + +def dma2DOffsetCopy{tt: shine.GAP8.DMATransferType}(dt: data, h: nat, w: nat, + offsetH: nat, offsetW: nat, + src: exp[h.w.dt, read], dst: acc[(h+2*offsetH).(w+2*offsetW).dt]): comm + +def memorySet(dt: data, value: exp[int, read], array: acc[dt]): comm \ No newline at end of file diff --git a/src/main/scala/shine/OpenCL/Compilation/HostCodeGenerator.scala b/src/main/scala/shine/OpenCL/Compilation/HostCodeGenerator.scala index 857cec97e..b779652f0 100644 --- a/src/main/scala/shine/OpenCL/Compilation/HostCodeGenerator.scala +++ b/src/main/scala/shine/OpenCL/Compilation/HostCodeGenerator.scala @@ -26,6 +26,10 @@ case class HostCodeGenerator(override val decls: C.Compilation.CodeGenerator.Dec { override def name: String = "OpenCL Host" + override def updatedRanges(key: String, + value: arithexpr.arithmetic.Range): HostCodeGenerator = + new HostCodeGenerator(decls, ranges.updated(key, value), kernelModules) + override def cmd(env: Environment): Phrase[CommType] => Stmt = { case k@KernelCallCmd(name, LocalSize(ls), GlobalSize(gs), n) => kernelCallCmd(name, ls, gs, k.output, k.args, env) diff --git a/src/main/scala/shine/OpenCL/Compilation/HostManagedBuffers.scala b/src/main/scala/shine/OpenCL/Compilation/HostManagedBuffers.scala index 86ac0553b..02761eee8 100644 --- a/src/main/scala/shine/OpenCL/Compilation/HostManagedBuffers.scala +++ b/src/main/scala/shine/OpenCL/Compilation/HostManagedBuffers.scala @@ -6,6 +6,7 @@ import shine.DPIA._ import shine.DPIA.Phrases._ import shine.DPIA.Types._ import shine.DPIA.primitives.{imperative => dpia} +import shine.GAP8.primitives.imperative.{Conv3x3, Conv5x5, Conv7x4, Conv7x7} import shine.OpenCL._ import shine.OpenCL.primitives.imperative.HostExecution import shine.OpenCL.primitives.{imperative => ocl} @@ -178,6 +179,8 @@ object HostManagedBuffers { newArgs.map(_.t.dataType), newOutput.t.dataType, k.args.map(VisitAndRebuild(_, this)), newOutput )) case _: HostExecution => Stop(p) + case _: Conv3x3 | _: Conv5x5 | _: Conv7x7 | _: Conv7x4 => + Continue(p, this) case unexpected => throw new Exception(s"did not expect $unexpected") } } diff --git a/src/main/scala/shine/OpenMP/CodeGenerator.scala b/src/main/scala/shine/OpenMP/CodeGenerator.scala index 9870cc202..b19cf4345 100644 --- a/src/main/scala/shine/OpenMP/CodeGenerator.scala +++ b/src/main/scala/shine/OpenMP/CodeGenerator.scala @@ -291,6 +291,9 @@ class CodeGenerator(override val decls: CCodeGenerator.Declarations, case (_: ScalarType, Nil) => CCodeGen.codeGenForeignFunctionCall(funDecl, inTs, outT, args, env, cont) + case (pt@PairType(dt1, dt2), _) => + CCodeGen.codeGenForeignFunctionCall(funDecl, inTs, outT, args, env, cont) + // TODO: This has to be generalised at some point ... case (VectorType(_, elemType), i :: Nil) => // this is not really generic, to treat all arguments the same ... @@ -313,7 +316,6 @@ class CodeGenerator(override val decls: CCodeGenerator.Declarations, } CCodeGen.codeGenForeignCall(funDecl.name, args, env, i :: Nil, cont) - case _ => throw new Exception(s"Can not generate fun call to $funDecl with current path $ps") } diff --git a/src/main/scala/util/SyntaxChecker.scala b/src/main/scala/util/SyntaxChecker.scala index 60f747329..2f16d9c2d 100644 --- a/src/main/scala/util/SyntaxChecker.scala +++ b/src/main/scala/util/SyntaxChecker.scala @@ -29,6 +29,16 @@ object SyntaxChecker { throw Exception(s"Code: `$code' did not pass syntax check") } } + /** + * TODO: clang emits "error: use of undeclared identifier 'ARCHI_CL_EVT_ACC0'". + * TODO: Think of a better way to make the code pass syntax checking + * */ + + @throws[SyntaxChecker.Exception]("if code does not pass the GAP8-like syntax check") + def checkGAP8(code: String): Unit = { + val mockDefine = "#define ARCHI_CL_EVT_ACC0 12" + apply(mockDefine + "\n" + code) + } @throws[SyntaxChecker.Exception]("if code doesn't pass the OpenCL syntax check") def checkOpenCL(code: String): Unit = { diff --git a/src/main/scala/util/gen.scala b/src/main/scala/util/gen.scala index 6bb8d6872..5a26c19b2 100644 --- a/src/main/scala/util/gen.scala +++ b/src/main/scala/util/gen.scala @@ -3,6 +3,7 @@ package util import rise.elevate.rules.traversal.default import shine.C.Compilation.{CodeGenerator => CCodeGenerator, ModuleGenerator => CModuleGenerator} import shine.DPIA.Compilation.FunDef +import shine.GAP8.Compilation.AcceleratorCodeGenerator import shine.OpenCL.Compilation._ import shine.OpenCL._ import shine.{C, DPIA, Pipe} @@ -105,14 +106,16 @@ object gen { case class function(name: String = "foo") { def fromExpr: Expr => GAP8.Module = - functionFromExpr(name, OpenMP.CodeGenerator()) andThen + functionFromExpr(name, AcceleratorCodeGenerator()) andThen GAP8.Module.fromCModule def asStringFromExpr: Expr => String = - functionAsStringFromExpr(name, OpenMP.CodeGenerator()) + functionAsStringFromExpr(name, AcceleratorCodeGenerator()) /** * Accelerator function only - Injects unpacking code + * + * TODO: Introduce appropriate syntax checking for GAP8 application code (not only for accelerator function) * */ private def functionAsStringFromExpr(name: String = "foo", gen: CCodeGenerator = CCodeGenerator() @@ -120,7 +123,7 @@ object gen { functionFromExpr(name, gen) andThen GAP8.Module.injectUnpacking andThen C.Module.translateToString andThen - run(SyntaxChecker(_)) + run(SyntaxChecker.checkGAP8(_)) } type HostedModule = GAP8.Module @@ -133,15 +136,14 @@ object gen { case class hosted(name: String = "foo"){ - def funDefToCModule(): FunDef => C.Module = - shine.C.Compilation.ModuleGenerator.funDefToModule(shine.C.Compilation.CodeGenerator()) - + def funDefToAcceleratorModule(): FunDef => C.Module = + shine.C.Compilation.ModuleGenerator.funDefToModule(shine.GAP8.Compilation.AcceleratorCodeGenerator()) def fromExpr: Expr => HostedModule = exprToPhrase andThen fromPhrase def fromPhrase: Phrase => HostedModule = partialHostCompiler(name) composeWith - ((((x: FunDef) => x) x map(funDefToCModule())) andThen hostFunDefToHostPart) + ((((x: FunDef) => x) x map(funDefToAcceleratorModule())) andThen hostFunDefToHostPart) private val hostFunDefToHostPart: ((FunDef, Seq[C.Module])) => (C.Module, Seq[C.Module]) = { case (hostModule, acceleratorModule) => diff --git a/src/test/scala/shine/GAP8/codegen.scala b/src/test/scala/shine/GAP8/codegen.scala index 3fea1b35c..81331055a 100644 --- a/src/test/scala/shine/GAP8/codegen.scala +++ b/src/test/scala/shine/GAP8/codegen.scala @@ -9,8 +9,10 @@ import rise.core.primitives._ import rise.core.types.DataType._ import rise.core.types._ import rise.elevate.Rise +import rise.openMP.primitives.mapPar import shine.GAP8 +// scalastyle:off class codegen extends test_util.Tests { private def findParamsStruct(typeName: String, count: Int, code: String) = { @@ -22,9 +24,6 @@ class codegen extends test_util.Tests { .sliding(typeName.length + 1) .count(wrapped => wrapped.toString().equalsIgnoreCase(typeName + " ")) .shouldBe(count) - - //.count(line => line.contains(typeName)) - //.shouldBe(count) } private def findDeviceBufferSync(count: Int, code: String) = { @@ -59,7 +58,6 @@ class codegen extends test_util.Tests { findDeviceBufferSync(2, code) checkCoreNumber(4, code) findParamsStruct("int32_t*", 2, code) - //SyntaxChecker(code) } test("Variable size") { @@ -78,11 +76,11 @@ class codegen extends test_util.Tests { test("Matmul") { val expr: ToBeTyped[Expr] = depFun((n: Nat, m: Nat, o: Nat) => - fun((n`.`o`.`f32) ->: (o`.`m`.`f32) ->: (n`.`m`.`f32))((a, b) => + fun((n`.`o`.`u32) ->: (o`.`m`.`u32) ->: (n`.`m`.`u32))((a, b) => gap8Run(8)( - a |> mapSeq(fun(rowa => - b |> transpose |> mapSeq(fun(colb => - zip(rowa)(colb) |> map(fun(x => fst(x) * snd(x))) |> reduceSeq(add)(lf32(0.0f)) + a |> mapPar(fun(rowa => + b |> transpose |> mapPar(fun(colb => + zip(rowa)(colb) |> map(fun(x => fst(x) * snd(x))) |> reduceSeq(add)(cast(l(0)) :: u32) )) )) ) @@ -94,9 +92,8 @@ class codegen extends test_util.Tests { findDeviceBufferSync(3, code) checkCoreNumber(8, code) - findParamsStruct("float*", 3, code) + findParamsStruct("uint32_t*", 3, code) findParamsStruct("int", 3, code) - //println(code) } @@ -105,11 +102,11 @@ class codegen extends test_util.Tests { fun((n`.`m`.`u8) ->: (3`.`3`.`int) ->: (3`.`3`.`int) ->: (n`.`m`.`u8))((pic, h_w, v_w) => gap8Run(8)( pic |> - padClamp2D(l = 1, r = 1) |> + padCst2D(1, 1)(cast(l(0)) :: u8) |> slide2D(sz = 3, st = 1) |> - mapSeq(mapSeq(fun(submat => { - zip(submat |> join)(h_w |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> reduceSeq(add)(cast(l(0)) :: u32) |> letf(h => - zip(submat |> join)(v_w |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> reduceSeq(add)(cast(l(0)) :: u32) |> letf(v => + mapPar(mapPar(fun(submat => { + zip(submat |> join)(h_w |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> reduceSeqUnroll(add)(cast(l(0)) :: u32) |> letf(h => + zip(submat |> join)(v_w |> join) |> map(fun(x => (cast(fst(x)) :: u32) * cast(snd(x)) :: u32)) |> reduceSeqUnroll(add)(cast(l(0)) :: u32) |> letf(v => cast(apps.SobelFilter.gapSqrt(h * h + v * v)) :: u8 ) ) @@ -128,5 +125,84 @@ class codegen extends test_util.Tests { findParamsStruct("uint8_t*", 2, code) findParamsStruct("int", 2, code) findParamsStruct("int*", 2, code) + //println(code) + } + + test("KMeans on GAP8") { + val testF = foreignFun("test", + Seq("dist", "tuple"), + """{ + | uint32_t min_dist = tuple._fst; + | uint32_t i = tuple._snd._fst; + | uint32_t index = tuple._snd._snd; + | if (dist < min_dist) { + | return (struct Record_uint32_t__uint32_t_uint32_t_){ dist, { i + 1 , i } }; + | } else { + | return (struct Record_uint32_t__uint32_t_uint32_t_){ min_dist, { i + 1, index } }; + | } + }""".stripMargin, + u32 ->: (u32 x (u32 x u32)) ->: (u32 x (u32 x u32)) + ) + + val update = fun(u32 ->: (u32 x u32) ->: u32)((dist, pair) => + dist + (pair._1 - pair._2) * (pair._1 - pair._2) + ) + + val select = fun(tuple => tuple._2._2) + + // p -> number of points, c -> number of clusters, f -> number of features + // from lift.highLevel.kmeans featuresType = ArrayType(ArrayType(Float, P), F) + // features matrix F x P + // from lift.highLevel.kmeans clustersType = ArrayType(ArrayType(Float, F), C) + // clusters matrix C X F + val expr: ToBeTyped[Rise] = depFun((p: Nat, c: Nat, f: Nat) => + fun((p`.`f`.`u32) ->: (c`.`f`.`u32) ->: (p`.`u32))((features, clusters) => + gap8Run(8)( + features |> mapPar(fun(feature => + clusters |> reduceSeq(fun(tuple => fun(cluster => { + val dist = zip(feature)(cluster) |> reduceSeq(update)(cast(l(0)) :: u32) + testF(dist)(tuple) + })))( + makePair(cast(l(4294967295L)) :: u32)(makePair(cast(l(0)) :: u32)(cast(l(0)) :: u32)) + ) |> select + )) + ) + ) + ) + + val hostedModule = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(hostedModule) + + findDeviceBufferSync(3, code) + checkCoreNumber(8, code) + findParamsStruct("uint32_t*", 3, code) + findParamsStruct("int", 3, code) + //println(code) + } + + test("Convolution 3x3") { + val expr: ToBeTyped[Rise] = { + depFun((w:Nat, h: Nat) => + fun((w`.`h`.`i16) ->: (3`.`3`.`i16) ->: ((w - 2)`.`(h - 2)`.`i16))((in, filter) => + gap8Run(8)( + in |> + slide2D(3, 1) |> + mapPar(mapPar(fun(sub => { + zip(sub |> join)(filter |> join) |> + map(fun(x => fst(x) * snd(x))) |> + reduceSeq(add)(li16(0)) + }))) + ) + ) + ) + } + + val module = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(module) + + findDeviceBufferSync(3, code) + checkCoreNumber(8, code) + findParamsStruct("int16_t*", 3, code) + //println(code) } } diff --git a/src/test/scala/shine/GAP8/hwce.scala b/src/test/scala/shine/GAP8/hwce.scala new file mode 100644 index 000000000..b5d1eb0e7 --- /dev/null +++ b/src/test/scala/shine/GAP8/hwce.scala @@ -0,0 +1,255 @@ +package shine.GAP8 + +import elevate.core.Strategy +import rise.GAP8.DSL.gap8Run +import rise.GAP8.primitives.{gap8hwConv3x3, gap8hwConv5x5, gap8hwConv7x4, gap8hwConv7x7} +import rise.core.DSL.HighLevelConstructs._ +import rise.core.DSL.Type._ +import rise.core.DSL._ +import rise.core.primitives._ +import rise.core.types.DataType._ +import rise.core.types._ +import rise.elevate.Rise +import rise.elevate.rules.algorithmic.gap8hwConvMerge +import rise.elevate.strategies.traversal._ +import shine.GAP8 + +/** + * HWCE constraint: W has to be even + * */ +class hwce extends test_util.Tests { + + val exprNoPipes: ToBeTyped[Rise] = { + fun((6`.`6`.`i16) ->: (3`.`3`.`i16) ->: ((6 - 2)`.`(6 - 2)`.`i16))((in, filter) => + gap8Run(8)( + mapSeq(mapSeq(fun(sub => { + reduceSeq(add)(li16(0))(map(fun(x => fst(x) * snd(x)))(zip(join(sub))(join(filter)))) + })))(slide2D(3, 1)(in)) + ) + ) + } + + private def checkHwceCall(code: String, filterSize: String) = { + assert( + ("HWCE_ProcessOneTile" + filterSize).r.findAllIn(code).length >= 1 + ) + } + + ignore("Sobel filter utilizes HWCE") { + val expr: ToBeTyped[Rise] = depFun((n: Nat, m: Nat) => + fun((n`.`m`.`i16) ->: (3`.`3`.`i16) ->: (3`.`3`.`i16) ->: (n`.`m`.`i16))((pic, h_w, v_w) => + gap8Run(8)( + pic |> + padCst2D(1, 1)(cast(l(0)) :: i16) |> + slide2D(sz = 3, st = 1) |> + mapSeq(mapSeq(fun(submat => { + zip(submat |> join)(h_w |> join) |> map(fun(x => fst(x) * snd(x))) |> reduceSeq(add)(li16(0)) |> letf(h => + zip(submat |> join)(v_w |> join) |> map(fun(x => fst(x) * snd(x))) |> reduceSeq(add)(li16(0)) |> letf(v => { + cast(apps.SobelFilter.gapSqrt(cast(h * h + v * v) :: u32)) :: i16 + }) + ) + } + ))) + ) + ) + ) + + val conv: Strategy[Rise] = + (gap8hwConvMerge `@` everywhere) + + val lowExpr = conv(expr).get + val module = util.gen.gap8.hosted.fromExpr(lowExpr) + val code = GAP8.Module.translateToString(module) + + + //println(expr.toExpr) + //println(exprNoPipes.toExpr) + //println(lowExpr) + + //println(code) + + //checkHwceCall(code, "3x3") + } + + test("Optimization strategy 3x3") { + val w: Nat = 6 + val h: Nat = 6 + + /** + * TODO: Pad filter with one 0 or do that in data prep step on backend (codegen) + * HWCE_ProcessOneTile3x3_MultiOut(e1, output, NULL, NULL, e2, 0, n, m, 0x7) + * */ + val exprOnAcc: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (3`.`3`.`i16) ->: ((w - 2)`.`(h - 2)`.`i16))((in, filter) => + gap8Run(8)( + in |> + slide2D(3, 1) |> + mapSeq(mapSeq(fun(sub => { + zip(sub |> join)(filter |> join) |> + map(fun(x => fst(x) * snd(x))) |> + reduceSeq(add)(li16(0)) + }))) + ) + ) + } + + val conv: Strategy[Rise] = + (gap8hwConvMerge `@` everywhere) + + val lowExpr = conv(exprOnAcc).get + val module = util.gen.gap8.hosted.fromExpr(lowExpr) + val code = GAP8.Module.translateToString(module) + + checkHwceCall(code, "3x3") + } + + test("Optimization strategy 5x5") { + val w: Nat = 10 + val h: Nat = 10 + + /** + * HWCE_ProcessOneTile5x5(e1, output, e2, 0, n, m) + * */ + val exprOnAcc: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (5`.`5`.`i16) ->: ((w - 4)`.`(h - 4)`.`i16))((in, filter) => + gap8Run(8)( + in |> + slide2D(5, 1) |> + mapSeq(mapSeq(fun(sub => { + zip(sub |> join)(filter |> join) |> + map(fun(x => fst(x) * snd(x))) |> + reduceSeq(add)(li16(0)) + }))) + ) + ) + } + + val conv: Strategy[Rise] = + (gap8hwConvMerge `@` everywhere) + + val lowExpr = conv(exprOnAcc).get + val module = util.gen.gap8.hosted.fromExpr(lowExpr) + val code = GAP8.Module.translateToString(module) + + checkHwceCall(code, "5x5") + } + + test("Optimization strategy 7x7") { + val w: Nat = 10 + val h: Nat = 10 + + /** + * HWCE_ProcessOneTile7x7(e1, output, e2, 0, n, m) + * */ + val exprOnAcc: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (7`.`7`.`i16) ->: ((w - 6)`.`(h - 6)`.`i16))((in, filter) => + gap8Run(8)( + in |> + slide2D(7, 1) |> + mapSeq(mapSeq(fun(sub => { + zip(sub |> join)(filter |> join) |> + map(fun(x => fst(x) * snd(x))) |> + reduceSeq(add)(li16(0)) + }))) + ) + ) + } + + val conv: Strategy[Rise] = + (gap8hwConvMerge `@` everywhere) + + val lowExpr = conv(exprOnAcc).get + val module = util.gen.gap8.hosted.fromExpr(lowExpr) + val code = GAP8.Module.translateToString(module) + + checkHwceCall(code, "7x7") + } + + test("Direct use of gap8hwConv3x3") { + val w: Nat = 9 + val h: Nat = 9 + + /** + * HWCE_ProcessOneTile3x3_MultiOut(e1, output, NULL, NULL, e2, 0, n, m, 0x7) + * */ + val expr: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (3`.`3`.`i16) ->: ((w - 2)`.`(h - 2)`.`i16))((in, filter) => + gap8Run(8)( + gap8hwConv3x3(0)(in)(filter) + ) + ) + } + + val hostedModule = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(hostedModule) + + checkHwceCall(code, "3x3") + //println(code) + } + + test("Direct use of gap8hwConv5x5") { + val w: Nat = 10 + val h: Nat = 10 + + /** + * HWCE_ProcessOneTile5x5(e1, output, e2, 0, n, m) + * */ + val expr: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (5`.`5`.`i16) ->: ((w - 4)`.`(h - 4)`.`i16))((in, filter) => + gap8Run(8)( + gap8hwConv5x5(0)(in)(filter) + ) + ) + } + + val hostedModule = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(hostedModule) + + checkHwceCall(code, "5x5") + //println(code) + } + + test("Direct use of gap8hwConv7x7") { + val w: Nat = 10 + val h: Nat = 10 + + /** + * HWCE_ProcessOneTile7x7(e1, output, e2, 0, n, m) + * */ + val expr: ToBeTyped[Rise] = { + fun((w`.`h`.`i16) ->: (7`.`7`.`i16) ->: ((w - 6)`.`(h - 6)`.`i16))((in, filter) => + gap8Run(8)( + gap8hwConv7x7(0)(in)(filter) + ) + ) + } + + val hostedModule = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(hostedModule) + + checkHwceCall(code, "7x7") + //println(code) + } + + test("Direct use of gap8hwConv7x4") { + val w: Nat = 10 + val h: Nat = 10 + + /** + * HWCE_ProcessOneTile7x4(e1, output, e2, 0, n, m) + * */ + val expr: ToBeTyped[Rise] = { + fun((h`.`w`.`i16) ->: (4`.`7`.`i16) ->: ((h - 3)`.`(w - 6)`.`i16))((in, filter) => + gap8Run(8)( + gap8hwConv7x4(0)(in)(filter) + ) + ) + } + + val hostedModule = util.gen.gap8.hosted.fromExpr(expr) + val code = GAP8.Module.translateToString(hostedModule) + + checkHwceCall(code, "7x4") + //println(code) + } +}