Commit 9bcf64aa authored by Kunshan Wang's avatar Kunshan Wang

Fixed phi-nodes and landingpads.

Phi-nodes and landingpads, which are now collectively called
"edge-assigned" instructions, in the basic block are now evaluated
together in the loop backedge rather than evaluated one at a time. This
mirrors the LLVM's behaviour.
parent ca9e751e
......@@ -44,17 +44,17 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
/** Write the return value of futex. May be written from FutexManager */
def futexReturn(rv: Int): Unit = {
// val validInst = curInst match {
// case ci: InstCommInst => ci.inst.name.get match {
// case "@uvm.futex.wait" => true
// case "@uvm.futex.wait_timeout" => true
// case _ => false
// }
// case _ => false
// }
//
// if (!validInst) throw new UvmRefImplException(ctx + "The current instruction is not @uvm.futex.wait or wait_timeout.")
//
// val validInst = curInst match {
// case ci: InstCommInst => ci.inst.name.get match {
// case "@uvm.futex.wait" => true
// case "@uvm.futex.wait_timeout" => true
// case _ => false
// }
// case _ => false
// }
//
// if (!validInst) throw new UvmRefImplException(ctx + "The current instruction is not @uvm.futex.wait or wait_timeout.")
//
logger.debug(ctx + "Setting futex return value")
writeIntResult(32, rv, boxOf(curInst))
continueNormally()
......@@ -81,6 +81,12 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
/** Get the value box of an SSA variable in the current stack. */
private def boxOf(v: SSAVariable): ValueBox = boxOf(curStack, v)
/** Get the edge-assigned value box of an edge-assigned instruction in a stack. */
private def edgeAssignedBoxOf(s: InterpreterStack, ea: EdgeAssigned): ValueBox = s.top.edgeAssignedBoxes(ea)
/** Get the edge-assigned value box of an edge-assigned instruction in the current stack. */
private def edgeAssignedBoxOf(ea: EdgeAssigned): ValueBox = edgeAssignedBoxOf(curStack, ea)
// Context printing for debugging
/** Make a string to identify the current function version, basic block and instruction for debugging. */
......@@ -1005,6 +1011,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val curBB = this.curBB
var cont = true
var i = 0
// Determine the value of edge-assigned instructions (phis and landingpads), but keep them in their temporary boxes.
while (cont) {
dest.insts(i) match {
case phi @ InstPhi(opndTy, cases) => {
......@@ -1012,18 +1020,28 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
throw new UvmRuntimeException(s"Phi node ${phi.repr} does not include the case for source basic block ${curBB.repr}")
}
val vb = boxOf(caseVal)
val db = boxOf(phi)
val db = edgeAssignedBoxOf(phi)
db.copyFrom(vb)
i += 1
}
case lp: InstLandingPad => {
val db = boxOf(lp).asInstanceOf[BoxRef]
val db = edgeAssignedBoxOf(lp).asInstanceOf[BoxRef]
db.objRef = excAddr
i += 1
}
case _ => cont = false
}
}
// Copy the values of edge-assigned instructions (phis and landingpads) to their canonical boxes.
for (j <- 0 until i) {
val destInst = dest.insts(j)
val sb = edgeAssignedBoxOf(destInst.asInstanceOf[EdgeAssigned])
val db = boxOf(destInst)
db.copyFrom(sb)
}
// Continue execution
jump(dest, i)
}
......
......@@ -56,6 +56,9 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame]) {
val boxes = new HashMap[LocalVariable, ValueBox]()
/** Edge-assigned instructions take values determined at look backedges */
val edgeAssignedBoxes = new HashMap[EdgeAssigned, ValueBox]()
/** Current basic block */
var curBB: BasicBlock = funcVer.entry
......@@ -101,6 +104,9 @@ class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame])
private def putBox(lv: LocalVariable) {
val ty = TypeInferer.inferType(lv)
boxes.put(lv, ValueBox.makeBoxForType(ty))
if (lv.isInstanceOf[EdgeAssigned]) {
edgeAssignedBoxes.put(lv.asInstanceOf[EdgeAssigned], ValueBox.makeBoxForType(ty))
}
}
def curInst: Instruction = try {
......
......@@ -148,6 +148,12 @@ case class PassValue(var argTy: Type, var arg: SSAVariable) extends NewStackActi
case class PassVoid() extends NewStackAction
case class ThrowExc(var exc: SSAVariable) extends NewStackAction
/**
* An EdgeAssigned instruction is evaluated at control flow edges rather than sequentially when the PC
* reaches that instruction. Currently PHI and LANDINGPAD are the only two such instructions.
*/
trait EdgeAssigned extends Instruction
/// Concrete instructions
case class InstBinOp(var op: BinOptr, var opndTy: Type, var op1: SSAVariable, var op2: SSAVariable,
var excClause: Option[ExcClause]) extends HasExcClause
......@@ -166,7 +172,7 @@ case class InstBranch2(var cond: SSAVariable, var ifTrue: BasicBlock, var ifFals
case class InstSwitch(var opndTy: Type, var opnd: SSAVariable, var defDest: BasicBlock,
var cases: Seq[(SSAVariable, BasicBlock)]) extends Instruction
case class InstPhi(var opndTy: Type, var cases: Seq[(BasicBlock, SSAVariable)]) extends Instruction
case class InstPhi(var opndTy: Type, var cases: Seq[(BasicBlock, SSAVariable)]) extends Instruction with EdgeAssigned
case class InstCall(var sig: FuncSig, var callee: SSAVariable, var argList: Seq[SSAVariable],
var excClause: Option[ExcClause], var keepAlives: Seq[LocalVariable]
......@@ -180,7 +186,7 @@ case class InstRetVoid() extends AbstractRet
case class InstThrow(var excVal: SSAVariable) extends Instruction
case class InstLandingPad() extends Instruction
case class InstLandingPad() extends Instruction with EdgeAssigned
case class InstExtractValue(var strTy: TypeStruct, var index: Int, var opnd: SSAVariable) extends Instruction
......
......@@ -706,6 +706,23 @@ class UvmInterpreterSpec extends UvmBundleTesterBase {
ca.close()
}
"PHI instructions in a basic block" should "be assigned at the same time in CFG edges" in {
val ca = microVM.newClientAgent()
val func = ca.putFunction("@phi_cyclic_dep_test")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val Seq(x, y) = ca.dumpKeepalives(st, 0)
ca.toInt(x, signExt=true) shouldEqual 2
ca.toInt(y, signExt=true) shouldEqual 1
TrapRebindPassVoid(st)
}
ca.close()
}
"CALL and RET" should "work for normal returns" in {
val ca = microVM.newClientAgent()
......
......@@ -408,6 +408,23 @@
COMMINST @uvm.thread_exit
}
.funcdef @phi_cyclic_dep_test VERSION @phi_cyclic_dep_test_v1 <@noparamsnoret> () {
%entry:
BRANCH %head
%head:
%x = PHI <@i64> { %entry: @I64_1; %head: %y; }
%y = PHI <@i64> { %entry: @I64_2; %head: %x; }
%i = PHI <@i64> { %entry: @I64_0; %head: %i2; }
%i2 = ADD <@i64> %i @I64_1
%lt = SLT <@i64> %i @I64_1
BRANCH2 %lt %head %end
%end:
%trap = TRAP <@void> KEEPALIVE (%x %y)
COMMINST @uvm.thread_exit
}
.funcdef @square_sum VERSION @square_sum_v1 <@i_ii> (%a %b) {
%entry:
%a2 = MUL <@i64> %a %a
......
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