GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). 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 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> {
%entry(<@i64> %n <@i64> %prod):
%zero = EQ <@i64> %n @I64_1
BRANCH2 %zero %iszero(%prod) %notzero(%n %prod)
......@@ -48,15 +48,15 @@
%notzero(<@i64> %n <@i64> %prod):
%nm1 = SUB <@i64> %n @I64_1
%mul = MUL <@i64> %n %prod
TAILCALL <@i_ii> @factorial_tailrec (%nm1 %mul)
TAILCALL <@ii_i> @factorial_tailrec (%nm1 %mul)
}