Commit 952d4eea authored by Kunshan Wang's avatar Kunshan Wang

Implemented and tested branching, switch and phi.

parent cf9b01d9
......@@ -45,8 +45,15 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
}
def ctx = stack match {
case None => "(Thred not bound to stack): "
case Some(_) => "FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(top.funcVer.repr, curBB.repr, curInst.repr, curInst.getClass.getName)
case None => "(Thred not bound to stack): "
case Some(_) => {
val ix = top.curInstIndex
if (ix >= curBB.insts.size) {
"FuncVer %s, BasicBlock %s, Instruction exceeds the basic block (error)".format(top.funcVer.repr, curBB.repr)
} else {
"FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(top.funcVer.repr, curBB.repr, curInst.repr, curInst.getClass.getName)
}
}
}
private def interpretCurrentInstruction(): Unit = try {
......@@ -321,6 +328,30 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
continueNormally()
}
case i @ InstBranch(dest) => {
branchAndMovePC(dest)
}
case i @ InstBranch2(cond, ifTrue, ifFalse) => {
val cv = boxOf(cond).asInstanceOf[BoxInt].value
val dest = if (cv == 1) ifTrue else ifFalse
branchAndMovePC(dest)
}
case i @ InstSwitch(opndTy, opnd, defDest, cases) => {
opndTy match {
case TypeInt(l) => {
val ov = boxOf(opnd).asInstanceOf[BoxInt].value
val dest = cases.find(pair => boxOf(pair._1).asInstanceOf[BoxInt].value == ov).map(_._2).getOrElse(defDest)
branchAndMovePC(dest)
}
case _ => throw new UvmRefImplException("Operand type must be integer. %s found.".format(opndTy))
}
}
case i @ InstPhi(_, _) => throw new UvmRefImplException("PHI instructions reached in normal execution, " +
"but PHI must only appear in the beginning of basic blocks and not in the entry block.")
// Indentation guide: Insert more instructions here.
case i @ InstTrap(retTy, excClause, keepAlives) => {
......@@ -359,6 +390,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
case "@uvm.thread_exit" => {
threadExit()
}
// Insert more CommInsts here.
case ciName => {
throw new UvmRefImplException("Unimplemented common instruction %s".format(ciName))
}
......@@ -384,7 +418,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
while (cont) {
dest.insts(i) match {
case phi @ InstPhi(opndTy, cases) => {
val caseVal = cases.find({ case (bb, _) => bb == dest }).map(_._2).getOrElse {
val caseVal = cases.find(_._1 == curBB).map(_._2).getOrElse {
throw new UvmRuntimeException(s"Phi node ${phi.repr} does not include the case for source basic block ${curBB.repr}")
}
val vb = boxOf(caseVal)
......@@ -405,6 +439,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def continueNormally(): Unit = {
curInst match {
case wp: InstWatchPoint => {
throw new UvmRefImplException("Not Implemented")
}
case h: HasExcClause => h.excClause match {
case None => incPC()
case Some(ec) => {
......
......@@ -224,7 +224,7 @@ case class InstAtomicRMW(var ord: MemoryOrder, var op: AtomicRMWOptr,
case class InstFence(var ord: MemoryOrder) extends Instruction
case class InstTrap(var retTy: Type, var excClause: Option[ExcClause], var keepAlives: Seq[LocalVariable]) extends AbstractTrap
case class InstTrap(var retTy: Type, var excClause: Option[ExcClause], var keepAlives: Seq[LocalVariable]) extends AbstractTrap with HasExcClause
case class InstWatchPoint(var wpID: Int, var retTy: Type,
var dis: BasicBlock, var ena: BasicBlock, var exc: Option[BasicBlock],
......
......@@ -74,17 +74,17 @@ class UvmInterpreterSpec extends FlatSpec with Matchers {
def asTR64Raw: Long = vb.asInstanceOf[BoxTagRef64].raw
def asVec: Seq[ValueBox] = vb.asInstanceOf[BoxVector].values
}
"The constant pool" should "contain appropriate constant values" in {
def gvb(name: String) = microVM.constantPool.getGlobalVarBox(microVM.globalBundle.globalVarNs(name))
gvb("@TRUE").asUInt(1) shouldBe 1
gvb("@FALSE").asUInt(1) shouldBe 0
gvb("@I32_1").asUInt(32) shouldBe 1
gvb("@I32_2").asUInt(32) shouldBe 2
gvb("@I32_7").asUInt(32) shouldBe 7
gvb("@I64_5").asUInt(64) shouldBe 5
}
......@@ -706,4 +706,55 @@ class UvmInterpreterSpec extends FlatSpec with Matchers {
ca.close()
}
"Branching" should "work" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@branch")
val a0 = ca.putInt("@i64", 0)
val a1 = ca.putInt("@i64", 1)
testFunc(ca, func, Seq(a0)) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) shouldBe "@branch_v1.traptrue"
TrapRebindPassVoid(st)
}
testFunc(ca, func, Seq(a1)) { (ca, th, st, wp) =>
nameOf(ca.currentInstruction(st, 0)) shouldBe "@branch_v1.trapfalse"
TrapRebindPassVoid(st)
}
ca.close()
}
"SWTICH and PHI" should "work" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@switch_phi")
val a0 = ca.putInt("@i64", 0)
val a1 = ca.putInt("@i64", 1)
val a2 = ca.putInt("@i64", 2)
val a3 = ca.putInt("@i64", 3)
def expectFlow(midTrapName: String, phiValue: BigInt): TrapHandlerFunction = { (ca, th, st, wp) =>
val M = midTrapName
nameOf(ca.currentInstruction(st, 0)) match {
case M => {}
case "@switch_phi_v1.trapend" => {
val Seq(phi) = ca.dumpKeepalives(st, 0)
phi.vb.asSInt(64) shouldBe phiValue
}
case trapName => fail("Trap %s should not be reached. Should reach %s.".format(trapName))
}
TrapRebindPassVoid(st)
}
testFunc(ca, func, Seq(a0))(expectFlow("@switch_phi_v1.trapdef", 4))
testFunc(ca, func, Seq(a1))(expectFlow("@switch_phi_v1.trapone", 5))
testFunc(ca, func, Seq(a2))(expectFlow("@switch_phi_v1.traptwo", 6))
testFunc(ca, func, Seq(a3))(expectFlow("@switch_phi_v1.trapthree", 7))
ca.close()
}
}
\ No newline at end of file
......@@ -354,57 +354,57 @@
COMMINST @uvm.thread_exit
}
// .funcsig @branch_sig = @void (@i64)
// .funcdef @branch VERSION @branch_v1 <@branch_sig> (%p0) {
// %entry:
// %cmpz = EQ <@i64> %p0 0
// BRANCH2 %cmpz %iftrue %iffalse
//
// %iftrue:
// %traptrue = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %iffalse:
// %trapfalse = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %exit:
// COMMINST @uvm.thread_exit
// RETVOID // unreachable
// }
//
// .funcsig @switch_phi_sig = @void (@i64)
// .funcdef @switch_phi VERSION @switch_phi_v1 <@switch_phi_sig> (%p0) {
// %entry:
// SWITCH <@i64> %p0 %def {
// 1: %one;
// 2: %two;
// 3: %three;
// }
//
// %def:
// %trapdef = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %one:
// %trapone = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %two:
// %traptwo = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %three:
// %trapthree = TRAP <@void> %exit %exit KEEPALIVE ()
//
// %exit:
// %phi = PHI <@i64> {
// %def: 10;
// %one: 11;
// %two: 12;
// %three: 13;
// }
// %trapend = TRAP <@void> %exit2 %exit2 KEEPALIVE (%phi)
// %exit2:
// COMMINST @uvm.thread_exit
// RETVOID // unreachable
// }
//
.funcsig @branch_sig = @void (@i64)
.funcdef @branch VERSION @branch_v1 <@branch_sig> (%p0) {
%entry:
BRANCH %head
%head:
%cmpz = EQ <@i64> %p0 @I64_0
BRANCH2 %cmpz %iftrue %iffalse
%iftrue:
%traptrue = TRAP <@void>
COMMINST @uvm.thread_exit
%iffalse:
%trapfalse = TRAP <@void>
COMMINST @uvm.thread_exit
}
.funcsig @switch_phi_sig = @void (@i64)
.funcdef @switch_phi VERSION @switch_phi_v1 <@switch_phi_sig> (%p0) {
%entry:
SWITCH <@i64> %p0 %def {
@I64_1: %one;
@I64_2: %two;
@I64_3: %three;
}
%def:
%trapdef = TRAP <@void> EXC(%exit %exit)
%one:
%trapone = TRAP <@void> EXC(%exit %exit)
%two:
%traptwo = TRAP <@void> EXC(%exit %exit)
%three:
%trapthree = TRAP <@void> EXC(%exit %exit)
%exit:
%phi = PHI <@i64> {
%def: @I64_4;
%one: @I64_5;
%two: @I64_6;
%three: @I64_7;
}
%trapend = TRAP <@void> KEEPALIVE (%phi)
COMMINST @uvm.thread_exit
}
// .funcsig @square_sum_sig = @i_ii
// .funcdef @square_sum VERSION @square_sum_v1 <@square_sum_sig> (%a %b) {
// %entry:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment