GitLab will be partched to the latest stable version on 15 July 2020 at 2.00pm (AEDT) to 2.30pm (AEDT) due to Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

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 ...@@ -44,17 +44,17 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
/** Write the return value of futex. May be written from FutexManager */ /** Write the return value of futex. May be written from FutexManager */
def futexReturn(rv: Int): Unit = { def futexReturn(rv: Int): Unit = {
// val validInst = curInst match { // val validInst = curInst match {
// case ci: InstCommInst => ci.inst.name.get match { // case ci: InstCommInst => ci.inst.name.get match {
// case "@uvm.futex.wait" => true // case "@uvm.futex.wait" => true
// case "@uvm.futex.wait_timeout" => true // case "@uvm.futex.wait_timeout" => true
// case _ => false // case _ => false
// } // }
// case _ => false // case _ => false
// } // }
// //
// if (!validInst) throw new UvmRefImplException(ctx + "The current instruction is not @uvm.futex.wait or wait_timeout.") // if (!validInst) throw new UvmRefImplException(ctx + "The current instruction is not @uvm.futex.wait or wait_timeout.")
// //
logger.debug(ctx + "Setting futex return value") logger.debug(ctx + "Setting futex return value")
writeIntResult(32, rv, boxOf(curInst)) writeIntResult(32, rv, boxOf(curInst))
continueNormally() continueNormally()
...@@ -75,12 +75,18 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -75,12 +75,18 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
/** Get the value box of an SSA variable in a stack. */ /** Get the value box of an SSA variable in a stack. */
private def boxOf(s: InterpreterStack, v: SSAVariable): ValueBox = v match { private def boxOf(s: InterpreterStack, v: SSAVariable): ValueBox = v match {
case g: GlobalVariable => microVM.constantPool.getGlobalVarBox(g) 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. */ /** Get the value box of an SSA variable in the current stack. */
private def boxOf(v: SSAVariable): ValueBox = boxOf(curStack, v) 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 // Context printing for debugging
/** Make a string to identify the current function version, basic block and instruction 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 ...@@ -93,7 +99,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
} else { } else {
"TID %d, FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(id, top.funcVer.repr, curBB.repr, curInst.repr, curInst match { "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 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 ...@@ -139,10 +145,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = { def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
scalarTy match { scalarTy match {
case TypeInt(l) => doInt(l, b1, b2, br) case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br) case TypeFloat() => doFloat(b1, b2, br)
case TypeDouble() => doDouble(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 ...@@ -197,10 +203,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = { def doScalar(scalarTy: Type, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
scalarTy match { scalarTy match {
case TypeInt(l) => doInt(l, b1, b2, br) case TypeInt(l) => doInt(l, b1, b2, br)
case TypeFloat() => doFloat(b1, b2, br) case TypeFloat() => doFloat(b1, b2, br)
case TypeDouble() => doDouble(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 ...@@ -227,8 +233,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val od = bOpnd.asInstanceOf[BoxInt].value val od = bOpnd.asInstanceOf[BoxInt].value
val result = op match { val result = op match {
case ConvOptr.TRUNC => OpHelper.trunc(od, tl) case ConvOptr.TRUNC => OpHelper.trunc(od, tl)
case ConvOptr.ZEXT => OpHelper.zext(od, fl, tl) case ConvOptr.ZEXT => OpHelper.zext(od, fl, tl)
case ConvOptr.SEXT => OpHelper.sext(od, fl, tl) case ConvOptr.SEXT => OpHelper.sext(od, fl, tl)
} }
br.asInstanceOf[BoxInt].value = result br.asInstanceOf[BoxInt].value = result
} }
...@@ -238,12 +244,12 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -238,12 +244,12 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def fpToI(signed: Boolean): Unit = { def fpToI(signed: Boolean): Unit = {
val tl = scalarToTy match { val tl = scalarToTy match {
case TypeInt(l) => l 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 { 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 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 br.asInstanceOf[BoxInt].value = result
} }
...@@ -251,7 +257,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -251,7 +257,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
def iToFP(signed: Boolean): Unit = { def iToFP(signed: Boolean): Unit = {
val fl = scalarFromTy match { val fl = scalarFromTy match {
case TypeInt(l) => l 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 od = bOpnd.asInstanceOf[BoxInt].value
val extended = if (signed) OpHelper.prepareSigned(od, fl) else OpHelper.prepareUnsigned(od, fl) 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 ...@@ -290,7 +296,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
} }
def refcast(): Unit = (scalarFromTy, scalarToTy) match { 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 (TypeIRef(_), TypeIRef(_)) => br.copyFrom(bOpnd)
case (TypeFunc(_), TypeFunc(_)) => br.copyFrom(bOpnd) case (TypeFunc(_), TypeFunc(_)) => br.copyFrom(bOpnd)
case _ => throw new UvmRuntimeException(ctx + case _ => throw new UvmRuntimeException(ctx +
...@@ -299,8 +305,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -299,8 +305,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
op match { op match {
case ConvOptr.TRUNC => iToI() case ConvOptr.TRUNC => iToI()
case ConvOptr.ZEXT => iToI() case ConvOptr.ZEXT => iToI()
case ConvOptr.SEXT => iToI() case ConvOptr.SEXT => iToI()
case ConvOptr.FPTRUNC => { case ConvOptr.FPTRUNC => {
val od = bOpnd.asInstanceOf[BoxDouble].value val od = bOpnd.asInstanceOf[BoxDouble].value
val result = od.toFloat val result = od.toFloat
...@@ -311,10 +317,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -311,10 +317,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val result = od.toDouble val result = od.toDouble
br.asInstanceOf[BoxDouble].value = result br.asInstanceOf[BoxDouble].value = result
} }
case ConvOptr.FPTOUI => fpToI(signed = false) case ConvOptr.FPTOUI => fpToI(signed = false)
case ConvOptr.FPTOSI => fpToI(signed = true) case ConvOptr.FPTOSI => fpToI(signed = true)
case ConvOptr.UITOFP => iToFP(signed = false) case ConvOptr.UITOFP => iToFP(signed = false)
case ConvOptr.SITOFP => iToFP(signed = true) case ConvOptr.SITOFP => iToFP(signed = true)
case ConvOptr.BITCAST => bitcast() case ConvOptr.BITCAST => bitcast()
case ConvOptr.REFCAST => refcast() case ConvOptr.REFCAST => refcast()
} }
...@@ -756,11 +762,11 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -756,11 +762,11 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val sta = boxOf(s).asInstanceOf[BoxStack].stack.getOrElse { val sta = boxOf(s).asInstanceOf[BoxStack].stack.getOrElse {
throw new UvmRuntimeException(ctx + "Attempt to create new thread on NULL stack.") throw new UvmRuntimeException(ctx + "Attempt to create new thread on NULL stack.")
} }
if (!sta.state.isInstanceOf[StackState.Ready]) { if (!sta.state.isInstanceOf[StackState.Ready]) {
throw new UvmRuntimeException(ctx + "Stack not in READY<T> state. Actual state: %s".format(sta.state)) throw new UvmRuntimeException(ctx + "Stack not in READY<T> state. Actual state: %s".format(sta.state))
} }
val thr = microVM.threadStackManager.newThread(sta) val thr = microVM.threadStackManager.newThread(sta)
boxOf(i).asInstanceOf[BoxThread].thread = Some(thr) boxOf(i).asInstanceOf[BoxThread].thread = Some(thr)
continueNormally() continueNormally()
...@@ -977,7 +983,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -977,7 +983,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
boxOf(i).copyFrom(vBox) boxOf(i).copyFrom(vBox)
continueNormally() continueNormally()
} }
// Insert more CommInsts here. // Insert more CommInsts here.
case ciName => { case ciName => {
...@@ -1005,6 +1011,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -1005,6 +1011,8 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val curBB = this.curBB val curBB = this.curBB
var cont = true var cont = true
var i = 0 var i = 0
// Determine the value of edge-assigned instructions (phis and landingpads), but keep them in their temporary boxes.
while (cont) { while (cont) {
dest.insts(i) match { dest.insts(i) match {
case phi @ InstPhi(opndTy, cases) => { case phi @ InstPhi(opndTy, cases) => {
...@@ -1012,18 +1020,28 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -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}") 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)
val db = boxOf(phi) val db = edgeAssignedBoxOf(phi)
db.copyFrom(vb) db.copyFrom(vb)
i += 1 i += 1
} }
case lp: InstLandingPad => { case lp: InstLandingPad => {
val db = boxOf(lp).asInstanceOf[BoxRef] val db = edgeAssignedBoxOf(lp).asInstanceOf[BoxRef]
db.objRef = excAddr db.objRef = excAddr
i += 1 i += 1
} }
case _ => cont = false 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) jump(dest, i)
} }
...@@ -1069,7 +1087,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -1069,7 +1087,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
maybeFindExceptionHandler(f.curInst) match { maybeFindExceptionHandler(f.curInst) match {
case Some(bb) => (f, bb) case Some(bb) => (f, bb)
case None => f.prev match { 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) case Some(prev) => unwindUntilCatchable(prev)
} }
} }
...@@ -1095,10 +1113,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter ...@@ -1095,10 +1113,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
*/ */
private def maybeFindExceptionHandler(inst: Instruction): Option[BasicBlock] = { private def maybeFindExceptionHandler(inst: Instruction): Option[BasicBlock] = {
inst match { inst match {
case i: InstCall => i.excClause.map(_.exc) case i: InstCall => i.excClause.map(_.exc)
case i: InstTrap => i.excClause.map(_.exc) case i: InstTrap => i.excClause.map(_.exc)
case i: InstWatchPoint => i.exc case i: InstWatchPoint => i.exc
case i: InstSwapStack => i.excClause.map(_.exc) case i: InstSwapStack => i.excClause.map(_.exc)
case _ => { case _ => {
throw new UvmRefImplException(ctx + "Instruction %s (%s) is in a stack frame when an exception is thrown.".format(inst.repr, inst.getClass.getName)) 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 ...@@ -1246,7 +1264,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
*/ */
private def branchToExcDestOr(excClause: Option[ExcClause])(f: => Unit): Unit = { private def branchToExcDestOr(excClause: Option[ExcClause])(f: => Unit): Unit = {
excClause match { excClause match {
case None => f case None => f
case Some(ExcClause(_, excBB)) => branchAndMovePC(excBB, 0L) case Some(ExcClause(_, excBB)) => branchAndMovePC(excBB, 0L)
} }
} }
......
...@@ -55,6 +55,9 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun ...@@ -55,6 +55,9 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame]) { class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame]) {
val boxes = new HashMap[LocalVariable, ValueBox]() val boxes = new HashMap[LocalVariable, ValueBox]()
/** Edge-assigned instructions take values determined at look backedges */
val edgeAssignedBoxes = new HashMap[EdgeAssigned, ValueBox]()
/** Current basic block */ /** Current basic block */
var curBB: BasicBlock = funcVer.entry var curBB: BasicBlock = funcVer.entry
...@@ -101,6 +104,9 @@ class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame]) ...@@ -101,6 +104,9 @@ class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame])
private def putBox(lv: LocalVariable) { private def putBox(lv: LocalVariable) {
val ty = TypeInferer.inferType(lv) val ty = TypeInferer.inferType(lv)
boxes.put(lv, ValueBox.makeBoxForType(ty)) boxes.put(lv, ValueBox.makeBoxForType(ty))
if (lv.isInstanceOf[EdgeAssigned]) {
edgeAssignedBoxes.put(lv.asInstanceOf[EdgeAssigned], ValueBox.makeBoxForType(ty))
}
} }
def curInst: Instruction = try { def curInst: Instruction = try {
......
...@@ -148,6 +148,12 @@ case class PassValue(var argTy: Type, var arg: SSAVariable) extends NewStackActi ...@@ -148,6 +148,12 @@ case class PassValue(var argTy: Type, var arg: SSAVariable) extends NewStackActi
case class PassVoid() extends NewStackAction case class PassVoid() extends NewStackAction
case class ThrowExc(var exc: SSAVariable) 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 /// Concrete instructions
case class InstBinOp(var op: BinOptr, var opndTy: Type, var op1: SSAVariable, var op2: SSAVariable, case class InstBinOp(var op: BinOptr, var opndTy: Type, var op1: SSAVariable, var op2: SSAVariable,
var excClause: Option[ExcClause]) extends HasExcClause var excClause: Option[ExcClause]) extends HasExcClause
...@@ -166,7 +172,7 @@ case class InstBranch2(var cond: SSAVariable, var ifTrue: BasicBlock, var ifFals ...@@ -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, case class InstSwitch(var opndTy: Type, var opnd: SSAVariable, var defDest: BasicBlock,
var cases: Seq[(SSAVariable, BasicBlock)]) extends Instruction 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], case class InstCall(var sig: FuncSig, var callee: SSAVariable, var argList: Seq[SSAVariable],
var excClause: Option[ExcClause], var keepAlives: Seq[LocalVariable] var excClause: Option[ExcClause], var keepAlives: Seq[LocalVariable]
...@@ -180,7 +186,7 @@ case class InstRetVoid() extends AbstractRet ...@@ -180,7 +186,7 @@ case class InstRetVoid() extends AbstractRet
case class InstThrow(var excVal: SSAVariable) extends Instruction 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 case class InstExtractValue(var strTy: TypeStruct, var index: Int, var opnd: SSAVariable) extends Instruction
......
...@@ -705,6 +705,23 @@ class UvmInterpreterSpec extends UvmBundleTesterBase { ...@@ -705,6 +705,23 @@ class UvmInterpreterSpec extends UvmBundleTesterBase {
ca.close() 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 { "CALL and RET" should "work for normal returns" in {
val ca = microVM.newClientAgent() val ca = microVM.newClientAgent()
......
...@@ -408,6 +408,23 @@ ...@@ -408,6 +408,23 @@
COMMINST @uvm.thread_exit 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) { .funcdef @square_sum VERSION @square_sum_v1 <@i_ii> (%a %b) {
%entry: %entry:
%a2 = MUL <@i64> %a %a %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