Commit ebe76f0d authored by Kunshan Wang's avatar Kunshan Wang

Migrated "futex" and "simple" tests.

parent 566eec26
FN=$1
sed -i 's/newClientAgent/newContext/g' $FN
sed -i 's/\bca\b/ctx/g' $FN
sed -i 's/ctx\.close()/ctx.closeContext()/g' $FN
sed -i 's/putInt("@i32",/i32(/g' $FN
sed -i 's/putInt("@i64",/i64(/g' $FN
sed -i 's/putConstant/handleFromConst/g' $FN
sed -i 's/putGlobal/handleFromGlobal/g' $FN
sed -i 's/putFunction/handleFromFunc/g' $FN
sed -i 's/toInt(\(\w\+\),\s*signExt\s*=\s*true)/handleToSInt(\1.asInstanceOf[MuIntValue])/g' $FN
sed -i 's/currentInstruction/curInst/g' $FN
sed -i 's/TrapRebindPassVoid/returnFromTrap/g' $FN
sed -i 's/TrapRebindPassValue(\(\w\+\),\s*\(\w\+\)\s*)/Rebind(\1, PassValues(Seq(\2)))/g' $FN
FN=$1
sed -i 's/\(%\w\+\)\s*=\s*TRAP/[\1] TRAP/g' $FN
sed -i 's/NEWSTACK\s*<\(@\w\+\)>\s*\(@\w\+\)/COMMINST @uvm.new_stack <[\1]> (\2)/g' $FN
sed -i 's/COMMINST\s*@uvm\.new_thread\s*(\([@%]\w\+\))/NEWTHREAD \1 PASS_VALUES /g' $FN
sed -i 's/TRAP\s*<@void>/TRAP <>/g' $FN
sed -i 's/noparamsnoret/v_v/g' $FN
sed -i 's/@void\s*(\([^)]*\))/(\1) -> ()/g' $FN
......@@ -694,16 +694,21 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
val newStack = boxOf(stack).asInstanceOf[BoxStack].stack.getOrElse {
throw new UvmRuntimeException(ctx + "Attempt to bind to a NULL stack.")
}
newStackAction match {
val newThread = newStackAction match {
case PassValues(argTys, args) => {
val argBoxes = args.map(boxOf)
rebindPassValues(newStack, argBoxes)
microVM.threadStackManager.newThread(newStack, HowToResume.PassValues(argBoxes))
}
case ThrowExc(exc) => {
val excBox = boxOf(exc)
rebindThrowExc(newStack, excBox)
val excAddr = excBox.asInstanceOf[BoxRef].objRef
microVM.threadStackManager.newThread(newStack, HowToResume.ThrowExc(excAddr))
}
}
resultBox(0).asInstanceOf[BoxThread].thread = Some(newThread)
continueNormally()
}
case i @ InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepAlives) => {
......
......@@ -144,7 +144,7 @@ trait InterpreterActions extends InterpreterThreadState {
/** Write the return value of futex. May be written from FutexManager */
def futexReturn(rv: Int): Unit = {
assert(curInst.isInstanceOf[InstCommInst])
assert(Seq("@uvm.futex.wait", "@uvm.futex.wait_timeout") contains
assert(Seq("@uvm.futex.wait", "@uvm.futex.wait_timeout", "@uvm.futex.wake", "@uvm.futex.cmp_requeue") contains
curInst.asInstanceOf[InstCommInst].inst.name.get)
logger.debug(ctx + "Setting futex return value")
......
......@@ -229,6 +229,9 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
* @return true if the interpreter should increment the PC by continueNormally().
*/
def rebindPassValues(args: Seq[ValueBox]): Boolean = {
if(!state.isInstanceOf[FrameState.Ready]) {
throw new UvmRuntimeException("Attempt to bind to a stack not in the ready state. Actual state: %s".format(state))
}
top match {
case mf: MuFrame => {
mf.resumeNormally(args)
......
......@@ -14,6 +14,8 @@ import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
import ch.qos.logback.classic.{ Logger => LLogger }
import ch.qos.logback.classic.Level
import uvm.refimpl.TrapHandlerResult.Rebind
import uvm.refimpl.HowToResume.PassValues
object UvmBundleTesterBase {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -98,4 +100,6 @@ abstract class UvmBundleTesterBase extends FlatSpec with Matchers {
def i64(num: BigInt) = ctx.handleFromInt(num, 64)
def func(id: Int) = ctx.handleFromFunc(id)
}
def returnFromTrap(st: MuStackRefValue) = Rebind(st, PassValues(Seq()))
}
\ No newline at end of file
......@@ -12,6 +12,8 @@ import AtomicRMWOptr._
import uvm.refimpl.mem.TypeSizes.Word
import ch.qos.logback.classic.Level._
import uvm.refimpl.UvmBundleTesterBase
import uvm.refimpl.TrapHandlerResult.{ ThreadExit, Rebind }
import uvm.refimpl.HowToResume.{ PassValues, ThrowExc }
class UvmInterpreterFutexTests extends UvmBundleTesterBase {
setLogLevels(
......@@ -22,150 +24,150 @@ class UvmInterpreterFutexTests extends UvmBundleTesterBase {
"tests/uvm-refimpl-test/futex-tests.uir")
"Futex" should "wake up the waiting thread" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@futex_setter")
val func = ctx.handleFromFunc("@futex_setter")
var trapWaiterReached = false
var trapSetterReached = false
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@futex_waiter_v1.entry.trap_waiter" => {
val Seq(rv, sv) = ca.dumpKeepalives(st, 0)
val Seq(rv, sv) = ctx.dumpKeepalives(st, 0)
ca.toInt(rv, signExt = true) shouldBe 0
ca.toInt(sv, signExt = true) shouldBe 42
ctx.handleToSInt(rv.asInstanceOf[MuIntValue]) shouldBe 0
ctx.handleToSInt(sv.asInstanceOf[MuIntValue]) shouldBe 42
trapWaiterReached = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@futex_setter_v1.wait_exit.trap_setter" => {
trapSetterReached = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
trapWaiterReached shouldBe true
trapSetterReached shouldBe true
}
"Futex" should "wake up if not explicitly woken within the give timeout" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@futex_delayer")
val func = ctx.handleFromFunc("@futex_delayer")
var trapDelayerReached = false
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@futex_delayer_v1.entry.trap_delayer" => {
val Seq(rv) = ca.dumpKeepalives(st, 0)
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ca.toInt(rv, signExt = true) shouldBe -3
ctx.handleToSInt(rv.asInstanceOf[MuIntValue]) shouldBe -3
trapDelayerReached = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
trapDelayerReached shouldBe true
}
"Futex" should "not sleep if the memory location does not hold the expected value" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@futex_no_sleep")
val func = ctx.handleFromFunc("@futex_no_sleep")
var trapNoSleepReached = false
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@futex_no_sleep_v1.entry.trap_no_sleep" => {
val Seq(rv) = ca.dumpKeepalives(st, 0)
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ca.toInt(rv, signExt = true) shouldBe -1
ctx.handleToSInt(rv.asInstanceOf[MuIntValue]) shouldBe -1
trapNoSleepReached = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
trapNoSleepReached shouldBe true
}
"Futex" should "wake up requeued threads" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@futex_requeue_test")
val func = ctx.handleFromFunc("@futex_requeue_test")
var mainExit = false
var subExit = 0
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@futex_requeue_waiter_v1.entry.trap_requeue_waiter" => {
val Seq(rv) = ca.dumpKeepalives(st, 0)
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ca.toInt(rv, signExt = true) shouldBe 0
ctx.handleToSInt(rv.asInstanceOf[MuIntValue]) shouldBe 0
subExit += 1
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@futex_requeue_test_v1.wait_body.trap_wait" => {
val Seq(nt, nt2) = ca.dumpKeepalives(st, 0)
val Seq(nt, nt2) = ctx.dumpKeepalives(st, 0)
val nthr = nt.vb.asThread.get
val nthr2 = nt2.vb.asThread.get
if (nthr.isFutexWaiting && nthr2.isFutexWaiting) {
val one = ca.putInt("@i32", 1)
TrapRebindPassValue(st, one)
val one = ctx.i32(1)
Rebind(st, PassValues(Seq(one)))
} else {
val zero = ca.putInt("@i32", 0)
TrapRebindPassValue(st, zero)
val zero = ctx.i32(0)
Rebind(st, PassValues(Seq(zero)))
}
}
case "@futex_requeue_test_v1.wait_exit.trap_setter" => {
val Seq(nwakes, nwakes2) = ca.dumpKeepalives(st, 0)
val Seq(nwakes, nwakes2) = ctx.dumpKeepalives(st, 0)
ca.toInt(nwakes, signExt = true) shouldBe 1
ca.toInt(nwakes2, signExt = true) shouldBe 1
ctx.handleToSInt(nwakes.asInstanceOf[MuIntValue]) shouldBe 1
ctx.handleToSInt(nwakes2.asInstanceOf[MuIntValue]) shouldBe 1
mainExit = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
mainExit shouldBe true
subExit shouldBe 2
......@@ -185,60 +187,60 @@ class UvmInterpreterFutexTests extends UvmBundleTesterBase {
}
"Futex" should "work across GC" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@futex_with_gc")
val func = ctx.handleFromFunc("@futex_with_gc")
var mainExit = false
var subExit = false
verboseGC {
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@futex_gc_waiter_v1.entry.trap_gc_waiter" => {
val Seq(rv) = ca.dumpKeepalives(st, 0)
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ca.toInt(rv, signExt = true) shouldBe 0
ctx.handleToSInt(rv.asInstanceOf[MuIntValue]) shouldBe 0
subExit = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@futex_with_gc_v1.wait_body.trap_wait" => {
val Seq(nt) = ca.dumpKeepalives(st, 0)
val Seq(nt) = ctx.dumpKeepalives(st, 0)
val nthr = nt.vb.asThread.get
if (nthr.isFutexWaiting) {
val one = ca.putInt("@i32", 1)
TrapRebindPassValue(st, one)
val one = ctx.i32(1)
Rebind(st, PassValues(Seq(one)))
} else {
val zero = ca.putInt("@i32", 0)
TrapRebindPassValue(st, zero)
val zero = ctx.i32(0)
Rebind(st, PassValues(Seq(zero)))
}
}
case "@futex_with_gc_v1.wait_exit.trap_gc" => {
gc()
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@futex_with_gc_v1.wait_exit.trap_exit" => {
val Seq(nwakes) = ca.dumpKeepalives(st, 0)
val Seq(nwakes) = ctx.dumpKeepalives(st, 0)
ca.toInt(nwakes, signExt = true) shouldBe 1
ctx.handleToSInt(nwakes.asInstanceOf[MuIntValue]) shouldBe 1
mainExit = true
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
}
mainExit shouldBe true
......
......@@ -22,110 +22,110 @@ class UvmInterpreterSimpleTests extends UvmBundleTesterBase {
"tests/uvm-refimpl-test/simple-tests.uir")
"Factorial functions" should "work" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@test_fac")
val func = ctx.handleFromFunc("@test_fac")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val Seq(r1, r2, r3) = ca.dumpKeepalives(st, 0)
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val Seq(r1, r2, r3) = ctx.dumpKeepalives(st, 0)
r1.vb.asInt shouldEqual 3628800
r2.vb.asInt shouldEqual 3628800
r3.vb.asInt shouldEqual 3628800
TrapRebindPassVoid(st)
returnFromTrap(st)
}
ca.close()
ctx.closeContext()
}
"Fibonacci functions" should "work" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@test_fib")
val func = ctx.handleFromFunc("@test_fib")
val watch = true
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@fibonacci_mat_v1.head.watch" => {
if (watch) {
val vhs = ca.dumpKeepalives(st, 0)
val vhs = ctx.dumpKeepalives(st, 0)
val vs = vhs.map(_.vb.asInt)
println("watch " + vs)
}
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@test_fib_v1.entry.checktrap" => {
val Seq(r1, r2) = ca.dumpKeepalives(st, 0)
val Seq(r1, r2) = ctx.dumpKeepalives(st, 0)
r1.vb.asInt shouldEqual 55
r2.vb.asInt shouldEqual 55
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
}
"Coroutine test" should "work" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@test_coroutine")
val func = ctx.handleFromFunc("@test_coroutine")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@test_coroutine_v1.body.trap_body" => {
val Seq(v) = ca.dumpKeepalives(st, 0)
val Seq(v) = ctx.dumpKeepalives(st, 0)
println(v.vb.asSInt(64))
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case "@test_coroutine_v1.exit.trap_exit" => {
val Seq(exc) = ca.dumpKeepalives(st, 0)
val Seq(exc) = ctx.dumpKeepalives(st, 0)
val hsi = ca.putGlobal("@StopIteration")
val hrsi = ca.load(MemoryOrder.NOT_ATOMIC, hsi)
val hsi = ctx.handleFromGlobal("@StopIteration")
val hrsi = ctx.load(MemoryOrder.NOT_ATOMIC, hsi)
exc.vb.asRef shouldEqual hrsi.vb.asRef
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
}
"Multi-threading test" should "work" in {
val ca = microVM.newClientAgent()
val ctx = microVM.newContext()
val func = ca.putFunction("@test_multithreading")
val func = ctx.handleFromFunc("@test_multithreading")
testFunc(ca, func, Seq()) { (ca, th, st, wp) =>
val trapName = nameOf(ca.currentInstruction(st, 0))
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
val trapName = nameOf(ctx.curInst(st, 0))
trapName match {
case "@test_multithreading_v1.getresult.trap_result" => {
val Seq(v) = ca.dumpKeepalives(st, 0)
val Seq(v) = ctx.dumpKeepalives(st, 0)
v.vb.asSInt(64) shouldEqual 4950
TrapRebindPassVoid(st)
returnFromTrap(st)
}
case _ => fail("Should not hit " + trapName)
}
}
ca.close()
ctx.closeContext()
}
}
\ No newline at end of file
......@@ -5,26 +5,24 @@
.global @the_futex <@i32>
.const @I64_42 <@i64> = 42
.const @I32_0 <@i32> = 0
.const @I32_1 <@i32> = 1
.funcdef @futex_waiter VERSION @futex_waiter_v1 <@noparamsnoret> {
.funcdef @futex_waiter VERSION @futex_waiter_v1 <@v_v> {
%entry():
%rv = COMMINST @uvm.futex.wait <@i32> (@the_futex @I32_0)
%sv = LOAD <@i64> @shared_value1
%trap_waiter = TRAP <@void> KEEPALIVE(%rv %sv)
[%trap_waiter] TRAP <> KEEPALIVE(%rv %sv)
COMMINST @uvm.thread_exit
}
.funcdef @futex_setter VERSION @futex_setter_v1 <@noparamsnoret> {
.funcdef @futex_setter VERSION @futex_setter_v1 <@v_v> {
%entry():
STORE <@i64> @shared_value1 @I64_0
STORE <@i64> @shared_value2 @I64_0
STORE <@i32> @the_futex @I32_0
%ns = NEWSTACK <@noparamsnoret> @futex_waiter ()
%nt = COMMINST @uvm.new_thread (%ns)
%ns = COMMINST @uvm.new_stack <[@v_v]> (@futex_waiter)
%nt = NEWTHREAD %ns PASS_VALUES <> ()
STORE <@i64> @shared_value1 @I64_42
......@@ -36,94 +34,94 @@
BRANCH2 %is_1 %wait_exit() %wait_body()
%wait_exit():
%trap_setter = TRAP <@void>
[%trap_setter] TRAP <>
COMMINST @uvm.thread_exit
}
.const @I64_ONE_SECOND <@i64> = 1000000000
.funcdef @futex_delayer VERSION @futex_delayer_v1 <@noparamsnoret> {
.funcdef @futex_delayer VERSION @futex_delayer_v1 <@v_v> {
%entry():
STORE <@i32> @the_futex @I32_0
%rv = COMMINST @uvm.futex.wait_timeout <@i32> (@the_futex @I32_0 @I64_ONE_SECOND)
%trap_delayer = TRAP <@void> KEEPALIVE(%rv)
[%trap_delayer] TRAP <> KEEPALIVE(%rv)
COMMINST @uvm.thread_exit
}
.funcdef @futex_no_sleep VERSION @futex_no_sleep_v1 <@noparamsnoret> {
.funcdef @futex_no_sleep VERSION @futex_no_sleep_v1 <@v_v> {
%entry():
STORE <@i32> @the_futex @I32_0
%rv = COMMINST @uvm.futex.wait <@i32> (@the_futex @I32_1)
%trap_no_sleep = TRAP <@void> KEEPALIVE(%rv)
[%trap_no_sleep] TRAP <> KEEPALIVE(%rv)
COMMINST @uvm.thread_exit
}
.global @the_other_futex <@i32>
.funcdef @futex_requeue_waiter VERSION @futex_requeue_waiter_v1 <@noparamsnoret> {
.funcdef @futex_requeue_waiter VERSION @futex_requeue_waiter_v1 <@v_v> {
%entry():
%rv = COMMINST @uvm.futex.wait <@i32> (@the_futex @I32_0)
%trap_requeue_waiter = TRAP <@void> KEEPALIVE(%rv)
[%trap_requeue_waiter] TRAP <> KEEPALIVE(%rv)
COMMINST @uvm.thread_exit
}
.funcdef @futex_requeue_test VERSION @futex_requeue_test_v1 <@noparamsnoret> {
.funcdef @futex_requeue_test VERSION @futex_requeue_test_v1 <@v_v> {
%entry():
STORE <@i32> @the_futex @I32_0
STORE <@i32> @the_other_futex @I32_0
%ns = NEWSTACK <@noparamsnoret> @futex_requeue_waiter ()
%nt = COMMINST @uvm.new_thread (%ns)
%ns = COMMINST @uvm.new_stack <[@v_v]> (@futex_requeue_waiter)
%nt = NEWTHREAD %ns PASS_VALUES <> ()
%ns2 = NEWSTACK <@noparamsnoret> @futex_requeue_waiter ()
%nt2 = COMMINST @uvm.new_thread (%ns2)
%ns2 = COMMINST @uvm.new_stack <[@v_v]> (@futex_requeue_waiter)
%nt2 = NEWTHREAD %ns2 PASS_VALUES <> ()
BRANCH %wait_body(%nt %nt2)
%wait_body(<@thread> %nt <@thread> %nt2):
%trap_wait = TRAP <@i32> KEEPALIVE (%nt %nt2)
%is_1 = EQ <@i32> %trap_wait @I32_1
%rv = [%trap_wait] TRAP <@i32> KEEPALIVE (%nt %nt2)
%is_1 = EQ <@i32> %rv @I32_1
BRANCH2 %is_1 %wait_exit() %wait_body()
%wait_exit():
%nwakes = COMMINST @uvm.futex.cmp_requeue <@i32> (@the_futex @the_other_futex @I32_0 @I32_1)
%nwakes2 = COMMINST @uvm.futex.wake <@i32> (@the_other_futex @I32_1)
%trap_setter = TRAP <@void> KEEPALIVE (%nwakes %nwakes2)
[%trap_setter] TRAP <> KEEPALIVE (%nwakes %nwakes2)
COMMINST @uvm.thread_exit
}
.typedef @refi32 = ref<@i32>
.typedef @irefi32 = iref<@i32>
.funcsig @futex_gc_waiter_sig = @void (@refi32)
.funcsig @futex_gc_waiter_sig = (@refi32) -> ()
.funcdef @futex_gc_waiter VERSION @futex_gc_waiter_v1 <@futex_gc_waiter_sig> {
%entry(<@refi32> %ref):
%ir = GETIREF <@i32> %ref
%rv = COMMINST @uvm.futex.wait <@i32> (%ir @I32_0)
%trap_gc_waiter = TRAP <@void> KEEPALIVE(%rv)
[%trap_gc_waiter] TRAP <> KEEPALIVE(%rv)
COMMINST @uvm.thread_exit
}
.funcdef @futex_with_gc VERSION @futex_with_gc_v1 <@noparamsnoret> {
.funcdef @futex_with_gc VERSION @futex_with_gc_v1 <@v_v> {
%entry():
%obj = NEW <@i64>
%ir = GETIREF <@i64> %obj
STORE <@i32> %ir @I32_0
%ns = NEWSTACK <@noparamsnoret> @futex_gc_waiter (%obj)
%nt = COMMINST @uvm.new_thread (%ns)
%ns = COMMINST @uvm.new_stack <[@futex_gc_waiter_sig]> (@futex_gc_waiter)
%nt = NEWTHREAD %ns PASS_VALUES <@refi32> (%obj)
BRANCH %wait_body(%ir %nt)
%wait_body(<@irefi64> %ir <@thread> %nt):
%trap_wait = TRAP <@i32> KEEPALIVE (%nt)
%is_1 = EQ <@i32> %trap_wait @I32_1
%rv = [%trap_wait] TRAP <@i32> KEEPALIVE (%nt)
%is_1 = EQ <@i32> %rv @I32_1
BRANCH2 %is_1 %wait_exit(%ir) %wait_body(%ir %nt)
%wait_exit(<@irefi64> %ir):
%trap_gc = TRAP<@void>
[%trap_gc] TRAP <>
%nwakes = COMMINST @uvm.futex.wake <@i32> (%ir @I32_1)
%trap_exit = TRAP <@void> KEEPALIVE (%nwakes)
[%trap_exit] TRAP <> KEEPALIVE (%nwakes)
COMMINST @uvm.thread_exit
}
// require primitives.uir
// require "primitives.uir"
// Factorial
......@@ -37,7 +37,7 @@
RET %prod
}
.funcdef @factorial_tailrec VERSION @factorial_tailrec_v1 <@i_ii> {
.funcdef @factorial_tailrec VERSION @factorial_tailrec_v1 <@ii_i> {