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()
......@@ -75,12 +75,18 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
/** Get the value box of an SSA variable in a stack. */
private def boxOf(s: InterpreterStack, v: SSAVariable): ValueBox = v match {
case g: GlobalVariable => microVM.constantPool.getGlobalVarBox(g)
case l: LocalVariable => s.top.boxes(l)
case l: LocalVariable => s.top.boxes(l)
}
/** 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. */
......@@ -93,7 +99,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
} else {
"TID %d, FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(id, top.funcVer.repr, curBB.repr, curInst.repr, curInst match {
case ci: InstCommInst => ci.inst.name.get
case _ => curInst.getClass.getSimpleName()
case _ => curInst.getClass.getSimpleName()
})
}
}
......@@ -139,10 +145,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
scalarTy match {
case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br)
case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br)
case TypeDouble() => doDouble(b1, b2, br)
case _ => throw new UvmRuntimeException(ctx + "BinOp not suitable for type %s".format(opndTy))
case _ => throw new UvmRuntimeException(ctx + "BinOp not suitable for type %s".format(opndTy))
}
}
......@@ -197,10 +203,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
scalarTy match {
case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br)
case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br)
case TypeDouble() => doDouble(b1, b2, br)
case _ => throw new UvmRuntimeException(ctx + "Comparison not suitable for type %s".format(opndTy))
case _ => throw new UvmRuntimeException(ctx + "Comparison not suitable for type %s".format(opndTy))
}
}
......@@ -227,8 +233,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val od = bOpnd.asInstanceOf[BoxInt].value
val result = op match {
case ConvOptr.TRUNC => OpHelper.trunc(od, tl)
case ConvOptr.ZEXT => OpHelper.zext(od, fl, tl)
case ConvOptr.SEXT => OpHelper.sext(od, fl, tl)
case ConvOptr.ZEXT => OpHelper.zext(od, fl, tl)
case ConvOptr.SEXT => OpHelper.sext(od, fl, tl)
}
br.asInstanceOf[BoxInt].value = result
}
......@@ -238,12 +244,12 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def fpToI(signed: Boolean): Unit = {
val tl = scalarToTy match {
case TypeInt(l) => l
case _ => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(scalarToTy))
case _ => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(scalarToTy))
}
val result = scalarFromTy match {
case TypeFloat() => OpHelper.floatToI(bOpnd.asInstanceOf[BoxFloat].value, tl, signed)
case TypeFloat() => OpHelper.floatToI(bOpnd.asInstanceOf[BoxFloat].value, tl, signed)
case TypeDouble() => OpHelper.doubleToI(bOpnd.asInstanceOf[BoxDouble].value, tl, signed)
case _ => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
case _ => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
}
br.asInstanceOf[BoxInt].value = result
}
......@@ -251,7 +257,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def iToFP(signed: Boolean): Unit = {
val fl = scalarFromTy match {
case TypeInt(l) => l
case _ => throw new UvmRuntimeException(ctx + "Expect integer source type. Found %s".format(scalarFromTy))
case _ => throw new UvmRuntimeException(ctx + "Expect integer source type. Found %s".format(scalarFromTy))
}
val od = bOpnd.asInstanceOf[BoxInt].value
val extended = if (signed) OpHelper.prepareSigned(od, fl) else OpHelper.prepareUnsigned(od, fl)
......@@ -290,7 +296,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
}
def refcast(): Unit = (scalarFromTy, scalarToTy) match {
case (TypeRef(_), TypeRef(_)) => br.copyFrom(bOpnd)
case (TypeRef(_), TypeRef(_)) => br.copyFrom(bOpnd)
case (TypeIRef(_), TypeIRef(_)) => br.copyFrom(bOpnd)
case (TypeFunc(_), TypeFunc(_)) => br.copyFrom(bOpnd)
case _ => throw new UvmRuntimeException(ctx +
......@@ -299,8 +305,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
op match {
case ConvOptr.TRUNC => iToI()
case ConvOptr.ZEXT => iToI()
case ConvOptr.SEXT => iToI()
case ConvOptr.ZEXT => iToI()
case ConvOptr.SEXT => iToI()
case ConvOptr.FPTRUNC => {
val od = bOpnd.asInstanceOf[BoxDouble].value
val result = od.toFloat
......@@ -311,10 +317,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val result = od.toDouble
br.asInstanceOf[BoxDouble].value = result
}
case ConvOptr.FPTOUI => fpToI(signed = false)
case ConvOptr.FPTOSI => fpToI(signed = true)
case ConvOptr.UITOFP => iToFP(signed = false)
case ConvOptr.SITOFP => iToFP(signed = true)
case ConvOptr.FPTOUI => fpToI(signed = false)
case ConvOptr.FPTOSI => fpToI(signed = true)
case ConvOptr.UITOFP => iToFP(signed = false)
case ConvOptr.SITOFP => iToFP(signed = true)
case ConvOptr.BITCAST => bitcast()
case ConvOptr.REFCAST => refcast()
}
......@@ -756,11 +762,11 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val sta = boxOf(s).asInstanceOf[BoxStack].stack.getOrElse {
throw new UvmRuntimeException(ctx + "Attempt to create new thread on NULL stack.")
}
if (!sta.state.isInstanceOf[StackState.Ready]) {
throw new UvmRuntimeException(ctx + "Stack not in READY<T> state. Actual state: %s".format(sta.state))
}
val thr = microVM.threadStackManager.newThread(sta)
boxOf(i).asInstanceOf[BoxThread].thread = Some(thr)
continueNormally()
......@@ -977,7 +983,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
boxOf(i).copyFrom(vBox)
continueNormally()
}
// Insert more CommInsts here.
case ciName => {
......@@ -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)
}
......@@ -1069,7 +1087,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
maybeFindExceptionHandler(f.curInst) match {
case Some(bb) => (f, bb)
case None => f.prev match {
case None => throw new UvmRuntimeException(ctx + "Exception is thrown out of the bottom frame.")
case None => throw new UvmRuntimeException(ctx + "Exception is thrown out of the bottom frame.")
case Some(prev) => unwindUntilCatchable(prev)
}
}
......@@ -1095,10 +1113,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
*/
private def maybeFindExceptionHandler(inst: Instruction): Option[BasicBlock] = {
inst match {
case i: InstCall => i.excClause.map(_.exc)
case i: InstTrap => i.excClause.map(_.exc)
case i: InstCall => i.excClause.map(_.exc)
case i: InstTrap => i.excClause.map(_.exc)
case i: InstWatchPoint => i.exc
case i: InstSwapStack => i.excClause.map(_.exc)
case i: InstSwapStack => i.excClause.map(_.exc)
case _ => {
throw new UvmRefImplException(ctx + "Instruction %s (%s) is in a stack frame when an exception is thrown.".format(inst.repr, inst.getClass.getName))
}
......@@ -1246,7 +1264,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
*/
private def branchToExcDestOr(excClause: Option[ExcClause])(f: => Unit): Unit = {
excClause match {
case None => f
case None => f
case Some(ExcClause(_, excBB)) => branchAndMovePC(excBB, 0L)
}
}
......
......@@ -55,6 +55,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
......
......@@ -705,6 +705,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