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 ...@@ -45,8 +45,15 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
} }
def ctx = stack match { def ctx = stack match {
case None => "(Thred not bound to stack): " 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 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 { private def interpretCurrentInstruction(): Unit = try {
...@@ -321,6 +328,30 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -321,6 +328,30 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
continueNormally() 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. // Indentation guide: Insert more instructions here.
case i @ InstTrap(retTy, excClause, keepAlives) => { case i @ InstTrap(retTy, excClause, keepAlives) => {
...@@ -359,6 +390,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -359,6 +390,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
case "@uvm.thread_exit" => { case "@uvm.thread_exit" => {
threadExit() threadExit()
} }
// Insert more CommInsts here.
case ciName => { case ciName => {
throw new UvmRefImplException("Unimplemented common instruction %s".format(ciName)) throw new UvmRefImplException("Unimplemented common instruction %s".format(ciName))
} }
...@@ -384,7 +418,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -384,7 +418,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
while (cont) { while (cont) {
dest.insts(i) match { dest.insts(i) match {
case phi @ InstPhi(opndTy, cases) => { 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}") throw new UvmRuntimeException(s"Phi node ${phi.repr} does not include the case for source basic block ${curBB.repr}")
} }
val vb = boxOf(caseVal) val vb = boxOf(caseVal)
...@@ -405,6 +439,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -405,6 +439,9 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def continueNormally(): Unit = { def continueNormally(): Unit = {
curInst match { curInst match {
case wp: InstWatchPoint => {
throw new UvmRefImplException("Not Implemented")
}
case h: HasExcClause => h.excClause match { case h: HasExcClause => h.excClause match {
case None => incPC() case None => incPC()
case Some(ec) => { case Some(ec) => {
......
...@@ -224,7 +224,7 @@ case class InstAtomicRMW(var ord: MemoryOrder, var op: AtomicRMWOptr, ...@@ -224,7 +224,7 @@ case class InstAtomicRMW(var ord: MemoryOrder, var op: AtomicRMWOptr,
case class InstFence(var ord: MemoryOrder) extends Instruction 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, case class InstWatchPoint(var wpID: Int, var retTy: Type,
var dis: BasicBlock, var ena: BasicBlock, var exc: Option[BasicBlock], var dis: BasicBlock, var ena: BasicBlock, var exc: Option[BasicBlock],
......
...@@ -74,17 +74,17 @@ class UvmInterpreterSpec extends FlatSpec with Matchers { ...@@ -74,17 +74,17 @@ class UvmInterpreterSpec extends FlatSpec with Matchers {
def asTR64Raw: Long = vb.asInstanceOf[BoxTagRef64].raw def asTR64Raw: Long = vb.asInstanceOf[BoxTagRef64].raw
def asVec: Seq[ValueBox] = vb.asInstanceOf[BoxVector].values def asVec: Seq[ValueBox] = vb.asInstanceOf[BoxVector].values
} }
"The constant pool" should "contain appropriate constant values" in { "The constant pool" should "contain appropriate constant values" in {
def gvb(name: String) = microVM.constantPool.getGlobalVarBox(microVM.globalBundle.globalVarNs(name)) def gvb(name: String) = microVM.constantPool.getGlobalVarBox(microVM.globalBundle.globalVarNs(name))
gvb("@TRUE").asUInt(1) shouldBe 1 gvb("@TRUE").asUInt(1) shouldBe 1
gvb("@FALSE").asUInt(1) shouldBe 0 gvb("@FALSE").asUInt(1) shouldBe 0
gvb("@I32_1").asUInt(32) shouldBe 1 gvb("@I32_1").asUInt(32) shouldBe 1
gvb("@I32_2").asUInt(32) shouldBe 2 gvb("@I32_2").asUInt(32) shouldBe 2
gvb("@I32_7").asUInt(32) shouldBe 7 gvb("@I32_7").asUInt(32) shouldBe 7
gvb("@I64_5").asUInt(64) shouldBe 5 gvb("@I64_5").asUInt(64) shouldBe 5
} }
...@@ -706,4 +706,55 @@ class UvmInterpreterSpec extends FlatSpec with Matchers { ...@@ -706,4 +706,55 @@ class UvmInterpreterSpec extends FlatSpec with Matchers {
ca.close() 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 @@ ...@@ -354,57 +354,57 @@
COMMINST @uvm.thread_exit COMMINST @uvm.thread_exit
} }
// .funcsig @branch_sig = @void (@i64) .funcsig @branch_sig = @void (@i64)
// .funcdef @branch VERSION @branch_v1 <@branch_sig> (%p0) { .funcdef @branch VERSION @branch_v1 <@branch_sig> (%p0) {
// %entry: %entry:
// %cmpz = EQ <@i64> %p0 0 BRANCH %head
// BRANCH2 %cmpz %iftrue %iffalse
// %head:
// %iftrue: %cmpz = EQ <@i64> %p0 @I64_0
// %traptrue = TRAP <@void> %exit %exit KEEPALIVE () BRANCH2 %cmpz %iftrue %iffalse
//
// %iffalse: %iftrue:
// %trapfalse = TRAP <@void> %exit %exit KEEPALIVE () %traptrue = TRAP <@void>
// COMMINST @uvm.thread_exit
// %exit:
// COMMINST @uvm.thread_exit %iffalse:
// RETVOID // unreachable %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: .funcsig @switch_phi_sig = @void (@i64)
// SWITCH <@i64> %p0 %def { .funcdef @switch_phi VERSION @switch_phi_v1 <@switch_phi_sig> (%p0) {
// 1: %one; %entry:
// 2: %two; SWITCH <@i64> %p0 %def {
// 3: %three; @I64_1: %one;
// } @I64_2: %two;
// @I64_3: %three;
// %def: }
// %trapdef = TRAP <@void> %exit %exit KEEPALIVE ()
// %def:
// %one: %trapdef = TRAP <@void> EXC(%exit %exit)
// %trapone = TRAP <@void> %exit %exit KEEPALIVE ()
// %one:
// %two: %trapone = TRAP <@void> EXC(%exit %exit)
// %traptwo = TRAP <@void> %exit %exit KEEPALIVE ()
// %two:
// %three: %traptwo = TRAP <@void> EXC(%exit %exit)
// %trapthree = TRAP <@void> %exit %exit KEEPALIVE ()
// %three:
// %exit: %trapthree = TRAP <@void> EXC(%exit %exit)
// %phi = PHI <@i64> {
// %def: 10; %exit:
// %one: 11; %phi = PHI <@i64> {
// %two: 12; %def: @I64_4;
// %three: 13; %one: @I64_5;
// } %two: @I64_6;
// %trapend = TRAP <@void> %exit2 %exit2 KEEPALIVE (%phi) %three: @I64_7;
// %exit2: }
// COMMINST @uvm.thread_exit %trapend = TRAP <@void> KEEPALIVE (%phi)
// RETVOID // unreachable COMMINST @uvm.thread_exit
// } }
//
// .funcsig @square_sum_sig = @i_ii // .funcsig @square_sum_sig = @i_ii
// .funcdef @square_sum VERSION @square_sum_v1 <@square_sum_sig> (%a %b) { // .funcdef @square_sum VERSION @square_sum_v1 <@square_sum_sig> (%a %b) {
// %entry: // %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