GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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