-
Notifications
You must be signed in to change notification settings - Fork 15
Documentation website (including first Tutorial) #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
51ee203
Added Tutorial app showing basic overview of RISE and ELEVATE being u…
michel-steuwer 88d2c1b
Fixed warning.
michel-steuwer ff52aca
Moved Tutorial to markdown in docs folder using https://scalameta.org…
michel-steuwer 1ea6403
Check documentation with github actions
michel-steuwer 47192d2
Added Docusaurus documentation webpage
michel-steuwer 9bfb885
Tweaked github actions
michel-steuwer 15f1c2c
Tweaked github actions
michel-steuwer d50509f
Added deployment workflow
michel-steuwer 46ba4f3
Testing Deployment
michel-steuwer 62c3e19
Finalized github actions config
michel-steuwer 3b40f96
Reverted |-> notation
michel-steuwer 9cc2765
... and updated the documentation as well
michel-steuwer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Submodule elevate
updated
2 files
| +12 −7 | macros/src/main/scala/elevate/macros/CombinatorMacro.scala | |
| +9 −4 | macros/src/main/scala/elevate/macros/RuleMacro.scala |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| package apps | ||
|
|
||
| import elevate.core._ | ||
| import rise.core.DSL.Type._ | ||
| import rise.core.DSL._ | ||
| import rise.core._ | ||
| import rise.core.primitives.{let => _, _} | ||
| import rise.core.types._ | ||
| import rise.elevate._ | ||
| import rise.elevate.rules.algorithmic._ | ||
| import rise.elevate.rules.lowering._ | ||
| import rise.elevate.strategies.predicate._ | ||
| import rise.elevate.strategies.traversal._ | ||
| import util.gen | ||
|
|
||
| object Tutorial extends scala.App { | ||
| /** | ||
| * Starting from a High-Level RISE Program and an ELEVATE Optimization | ||
| * Strategy the Shine compiler rewrites the high-level program as specified | ||
| * by the optimization strategy into a Low-Level RISE Program that encodes | ||
| * all implementation and optimization decisions explicitly. | ||
| * | ||
| * The code generator processes the low-level program to generate | ||
| * the final Optimized C, OpenMP, OpenCL, or CUDA Program. | ||
| */ | ||
| println("An overview of the RISE language and the Shine compiler") | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This is an example of a high-Level program written in RISE. | ||
| * The shown example is the multiplication of a nxk-matrix called `A` | ||
| * and a mxk-matrix called `B`. | ||
| */ | ||
| val highLevelProgram: ToBeTyped[Rise] = | ||
| depFun((n: Nat, m: Nat, k: Nat) => | ||
| fun(n`.`k`.`f32)(A => fun(k`.`m`.`f32)(B => | ||
| A |> map(fun(rowOfA => | ||
| B |> transpose |> map(fun(colOfB => | ||
| zip(rowOfA)(colOfB) |> | ||
| map(fun(x => fst(x) * snd(x))) |> | ||
| reduce(add)(l(0.0f)) )) )) )) ) | ||
| // The matrix dimensions are represented as part of the type of the matrices: | ||
| // - the type of matrix `A` is `n.k.f32` | ||
| // - the type of matrix `B` is `k.m.f32` | ||
| // The identifies used in the type (here: `n`, `m`, and `k`) are introduced | ||
| // and scoped by `depFun` | ||
| // | ||
| // The matrix values are introduced and scoped as function parameters by two | ||
| // nested `fun`s | ||
| // | ||
| // The body of the nested functions represents the computation of the matrix | ||
| // matrix multiplication: | ||
| // - two nested `map` primitives apply the dot product to each combination | ||
| // of a `rowOfA` and a `colOfB` | ||
| // - the dot product computation is represented by a composition of the | ||
| // `zip`, `map`, and `reduce` primitives | ||
| // | ||
| // We often prefer the pipe notation `(x |> f)` over the equivalent function | ||
| // call notation `f(x)` as it allows expressions to be read from | ||
| // left-to-right and top-to-bottom. | ||
| // | ||
| // Primitives (such as `map`, `transpose`, `zip`, and `reduce`) are functions | ||
| // with types that explain their possible usage and with a clearly defined | ||
| // denotational semantics: | ||
| // - `[x1, ..., xn] |> map(f) == [f(x1), ..., f(xn)]` | ||
| // - `[ [x11, ...., x1n], ..., [xm1, ..., xmn] ] |> transpose | ||
| // == [ [x11, ...., xm1], ..., [x1n, ..., xmn] ]` | ||
| // - `zip([x1, ..., xn])([y1, ..., yn]) == [(x1, y1), ..., (xn, yn)]` | ||
| // - `[x1, ..., xn] |> reduce(op)(init) == init op x1 op ... op xn` | ||
| // | ||
| // The resulting RISE expression has the Scala type `ToBeTyped[Rise]` | ||
| // On conversion to the underlying Scala type `Rise` type inference will be | ||
| // performed automatically. | ||
|
|
||
| // We can easily print the internal representation of the high-level program: | ||
| println("High-Level RISE Program:") | ||
| println(highLevelProgram.toExpr) | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This is an example of an optimization strategy written in ELEVATE. | ||
| * It describes that the outermost map computation will be performed in | ||
| * parallel as well as that the nested map computation and the reduction | ||
| * will be performed sequentially. | ||
| */ | ||
| val optimizationStrategy: Strategy[Rise] = | ||
| (`map |-> mapPar` `@` outermost(isPrimitive(map))) `;` | ||
| (`map |-> mapSeq` `@` outermost(isPrimitive(map))) `;` | ||
| (`reduce |-> reduceSeq` `@` everywhere) | ||
| // The shown example demonstrates one possible way to rewrite the high-level | ||
| // RISE program above into a low-level RISE program from which code can be | ||
| // generated. | ||
| // | ||
| // Strategies in ELEVATE are functions with the following specific type: | ||
| // type Strategy[P] = P => RewriteResult[P] | ||
| // | ||
| // The return type `RewriteResult[P]` indicates the two possible outcomes of | ||
| // applying a rewrite strategy to a program of type `P`: either the program | ||
| // has been successfully rewritten, or the rewrite strategy failed. | ||
| // | ||
| // Strategies in ELEVATE are written as compositions of smaller strategies. | ||
| // | ||
| // The simplest strategies are rewrite rules that replace an expression | ||
| // with another expression. An example of such a rule is the `map |-> mapPar` | ||
| // strategy that replaces an occurrence of the `map` primitive with the | ||
| // `mapPar` primitive indicating that the computation of the map should be | ||
| // performed in parallel. | ||
| // | ||
| // The `outermost` and `everywhere` strategies are examples of traversals | ||
| // that describe where other strategies should be applied. | ||
| // We can use the `@` notation to compose them as shown in the example. | ||
|
|
||
| // We can also easily print the internal representation of the | ||
| // optimization strategy: | ||
| println("ELEVATE Optimization Strategy:") | ||
| println(s" $optimizationStrategy") | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This alternative strategy explicitly fused the innermost map and reduce | ||
| * patterns. It then turns every remaining map into a sequential map and the | ||
| * reduce into a sequential reduction. | ||
| */ | ||
| val anotherOptimizationStrategy: Strategy[Rise] = | ||
| (`map >> reduce |-> reduce` `@` everywhere) `;` | ||
| (`map |-> mapSeq` `@` everywhere) `;` | ||
| (`reduce |-> reduceSeq` `@` everywhere) | ||
|
|
||
| println("Another Optimization Strategy:") | ||
| println(s" $anotherOptimizationStrategy") | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This strategy vectorizes the computation of the innermost map pattern | ||
| * that itself will be performed sequentially and stores its temporary output | ||
| * as vectors. It will then use the optimization and implementation decisions | ||
| * described in the initial optimization strategy. | ||
| */ | ||
| val yetAnotherOptimizationStrategy: Strategy[Rise] = | ||
| innermost(isAppliedMap)( | ||
| `map(f) |-> asVector >> map(f_vec) >> asScalar`(4) `;` | ||
| (`map |-> mapSeq` `@` innermost(isPrimitive(map))) `;` | ||
| storeTempAsVectors | ||
| ) `;` | ||
| optimizationStrategy | ||
|
|
||
| println("Yet Another Optimization Strategy:") | ||
| println(s" $yetAnotherOptimizationStrategy") | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This function performs the rewriting by applying the given | ||
| * optimization strategy to the given program. | ||
| */ | ||
| def rewriting(program: Rise, strategy: Strategy[Rise]): Rise = { | ||
| println("> Rewrite high-level program using the ") | ||
| println(s"> $strategy") | ||
| println("> optimization strategy") | ||
| println("--------------------------------------------------") | ||
|
|
||
| // we know that the shown strategies will always succeed, therefore, it is | ||
| // ok to unwrap the final RewriteResult using .get | ||
| strategy(program).get | ||
| } | ||
|
|
||
| /** | ||
| * This is the low-level RISE program that is produced by rewriting the | ||
| * high-level program using one of the optimization strategies | ||
| */ | ||
| val lowLevelProgram: Rise = | ||
| rewriting(highLevelProgram, optimizationStrategy) | ||
|
|
||
| println("Low-Level RISE Program:") | ||
| println(lowLevelProgram) | ||
| println("--------------------------------------------------") | ||
|
|
||
| /** | ||
| * This function performs the code generation translating the given | ||
| * low-level program to optimized code. | ||
| */ | ||
| def codeGeneration(program: Rise): String = { | ||
| println("> Generate code for the low-level program") | ||
| println("--------------------------------------------------") | ||
|
|
||
| gen.openmp.function.asStringFromExpr(program) | ||
| // similar API for generating C or OpenCL code exist: | ||
| // gen.c.function.asStringFromExpr(program) | ||
| // gen.opencl.kernel.asStringFromExpr(program) | ||
| } | ||
|
|
||
| /** | ||
| * The final optimized program in C, OpenMP, or OpenCL. | ||
| */ | ||
| val optimizedProgram: String = | ||
| codeGeneration(lowLevelProgram) | ||
|
|
||
| println("Optimized Program:") | ||
| println(optimizedProgram) | ||
| println("--------------------------------------------------") | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.