Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions benchmarks/wasm/for_loop.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
(module
(func $for_loop (result i32)
(local i32)
(local i32)

for
(
;; init
i32.const 0
local.set 0
i32.const 0
local.set 1
|
;; cond
local.get 1
i32.const 10
i32.gt_s
i32.eqz
|
;; post
local.get 1
i32.const 1
i32.add
local.set 1
)

;; es
local.get 0
local.get 1
i32.add
local.set 0

local.get 0


)

(export "for_loop" (func 0))

)

2 changes: 2 additions & 0 deletions grammar/WatLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ UNREACHABLE: 'unreachable' ;
DROP: 'drop' ;
BLOCK: 'block' ;
LOOP: 'loop' ;
FOR : 'for';
VBAR: '|';
END: 'end' ;
BR: 'br' ;
BR_IF: 'br_if' ;
Expand Down
5 changes: 5 additions & 0 deletions grammar/WatParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ instr
| blockInstr
| foldedInstr
| resumeInstr
| forLoop
;

forLoop
: 'for' '(' instrList '|' instrList '|' instrList ')' instrList
;

plainInstr
Expand Down
2,689 changes: 1,355 additions & 1,334 deletions src/main/java/wasm/WatLexer.java

Large diffs are not rendered by default.

3,151 changes: 1,620 additions & 1,531 deletions src/main/java/wasm/WatParser.java

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/main/java/wasm/WatParserBaseListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,18 @@ public class WatParserBaseListener implements WatParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitInstr(WatParser.InstrContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterForLoop(WatParser.ForLoopContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitForLoop(WatParser.ForLoopContext ctx) { }
/**
* {@inheritDoc}
*
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/wasm/WatParserBaseVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ public class WatParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> impleme
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitInstr(WatParser.InstrContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitForLoop(WatParser.ForLoopContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/wasm/WatParserListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ public interface WatParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitInstr(WatParser.InstrContext ctx);
/**
* Enter a parse tree produced by {@link WatParser#forLoop}.
* @param ctx the parse tree
*/
void enterForLoop(WatParser.ForLoopContext ctx);
/**
* Exit a parse tree produced by {@link WatParser#forLoop}.
* @param ctx the parse tree
*/
void exitForLoop(WatParser.ForLoopContext ctx);
/**
* Enter a parse tree produced by {@link WatParser#plainInstr}.
* @param ctx the parse tree
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/wasm/WatParserVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ public interface WatParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitInstr(WatParser.InstrContext ctx);
/**
* Visit a parse tree produced by {@link WatParser#forLoop}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitForLoop(WatParser.ForLoopContext ctx);
/**
* Visit a parse tree produced by {@link WatParser#plainInstr}.
* @param ctx the parse tree
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/wasm/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ case class Select(ty: Option[List[ValueType]]) extends Instr
case class Block(ty: BlockType, instrs: List[Instr]) extends Instr
case class IdBlock(id: Int, ty: BlockType, instrs: List[Instr]) extends Instr
case class Loop(ty: BlockType, instrs: List[Instr]) extends Instr
case class ForLoop(init:List[Instr], cond: List[Instr], post: List[Instr], body: List[Instr]) extends Instr
case class IdLoop(id: Int, ty: BlockType, instrs: List[Instr]) extends Instr
case class If(ty: BlockType, thenInstrs: List[Instr], elseInstrs: List[Instr]) extends Instr
case class IdIf(ty: BlockType, thenInstrs: IdBlock, elseInstrs: IdBlock) extends Instr
Expand Down
30 changes: 29 additions & 1 deletion src/main/scala/wasm/MiniWasm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,12 @@ case class Evaluator(module: ModuleInstance) {
trail: List[Cont[Ans]]): Ans = {
if (insts.isEmpty) return kont(stack)



val inst = insts.head
val rest = insts.tail


// println(s"inst: ${inst} \t | ${frame.locals} | ${stack.reverse}" )

inst match {
Expand Down Expand Up @@ -383,6 +386,30 @@ case class Evaluator(module: ModuleInstance) {
def loop(retStack: List[Value]): Ans =
eval(inner, retStack.take(funcTy.inps.size), frame, restK, loop _ :: trail)
loop(inputs)

case ForLoop(init, cond, post, body) =>
val restK: Cont[Ans] = retStack =>
eval(rest, retStack, frame, kont, trail)

def forloop(retStack: List[Value]): Ans = {

eval(cond, retStack, frame, {

case I32V(0) :: _ =>

restK(retStack)
case (_: I32V) :: _ =>
eval(body, retStack, frame, newStack => {
eval(post, newStack, frame, postStack => {
forloop(postStack)
}, trail)
} , trail)
case _ =>
throw new RuntimeException("Condition did not return I32V as expected")
}, trail)
}
eval(init, stack, frame, forloop, trail)

case If(ty, thn, els) =>
val funcTy = getFuncType(ty)
val I32V(cond) :: newStack = stack
Expand Down Expand Up @@ -437,7 +464,8 @@ case class Evaluator(module: ModuleInstance) {
})
}
if (instrs.isEmpty) println("Warning: nothing is executed")
eval(instrs, List(), Frame(ArrayBuffer(I32V(0))), halt, List(halt))

eval(instrs, List(), Frame(ArrayBuffer(I32V(0),I32V(0))), halt, List(halt))
Comment on lines +467 to +468
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meeting notes: frame's length should depends on the number of local variables, which declared in main's fields.

}

def evalTop(m: ModuleInstance): Unit = evalTop(stack => ())
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/wasm/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
def toNumType(t: String): NumType = NumType(toNumKind(t))

/* Overriding visitors */
override def visitForLoop(ctx:ForLoopContext): Instr = {
val InstrList(init) = visit(ctx.instrList(0))
val InstrList(cond) = visit(ctx.instrList(1))
val InstrList(post) = visit(ctx.instrList(2))
val InstrList(body) = visit(ctx.instrList(3))
ForLoop(init,cond,post,body)

}

override def visitModule(ctx: ModuleContext): WIR = {
if (ctx.module_() != null) return visit(ctx.module_())
Expand Down
6 changes: 6 additions & 0 deletions src/test/scala/genwasym/TestEval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class TestEval extends FunSuite {
evaluator.evalTop(haltK, main)
}


// TODO: the power test can be used to test the stack
// For now: 2^10 works, 2^100 results in 0 (TODO: why?),
// and 2^1000 results in a stack overflow
Expand Down Expand Up @@ -74,6 +75,9 @@ class TestEval extends FunSuite {
test("loop block - poly br") {
testFile("./benchmarks/wasm/loop_poly.wat", None, ExpStack(List(2, 1)))
}
test("for loop") {
testFile("./benchmarks/wasm/for_loop.wat", Some("for_loop"), ExpInt(55))
}

// just for parsing
test("fx types") {
Expand All @@ -90,4 +94,6 @@ class TestEval extends FunSuite {
//test("tribonacci-ret") { testFile("./benchmarks/wasm/tribonacci_ret.wat", None, Some(504)) }

// TODO: add wasm spec tests? How to utilize wast files?

}

Loading