Commit 86fe9958 authored by Kunshan Wang's avatar Kunshan Wang

Trap handler and the TRAP instruction.

parent 3dd5c9cd
......@@ -22,7 +22,7 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
val constantPool = new ConstantPool(this)
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize, this)
val threadStackManager = new ThreadStackManager(this)
//val trapManager = new TrapManager(this)
val trapManager = new TrapManager(this)
val clientAgents = new HashSet[ClientAgent]()
val irReader = new UIRTextReader(new IDFactory())
......
......@@ -247,11 +247,11 @@ class ClientAgent(microVM: MicroVM) {
val nb = uty match {
case TypeInt(l) =>
val bi: BigInt = l match {
case 8 => MemorySupport.loadByte(iRef)
case 8 => MemorySupport.loadByte(iRef)
case 16 => MemorySupport.loadShort(iRef)
case 32 => MemorySupport.loadInt(iRef)
case 64 => MemorySupport.loadLong(iRef)
case _ => throw new UnimplementedOprationException("Loading int of length %d is not supported".format(l))
case _ => throw new UnimplementedOprationException("Loading int of length %d is not supported".format(l))
}
BoxInt(OpHelper.unprepare(bi, l))
case _: TypeFloat =>
......@@ -310,11 +310,11 @@ class ClientAgent(microVM: MicroVM) {
case TypeInt(l) =>
val bi = nvb.asInstanceOf[BoxInt].value
l match {
case 8 => MemorySupport.storeByte(iRef, bi.byteValue)
case 8 => MemorySupport.storeByte(iRef, bi.byteValue)
case 16 => MemorySupport.storeShort(iRef, bi.shortValue)
case 32 => MemorySupport.storeInt(iRef, bi.intValue)
case 64 => MemorySupport.storeLong(iRef, bi.longValue)
case _ => throw new UnimplementedOprationException("Storing int of length %d is not supported".format(l))
case _ => throw new UnimplementedOprationException("Storing int of length %d is not supported".format(l))
}
BoxInt(OpHelper.unprepare(bi, l))
case _: TypeFloat =>
......@@ -483,7 +483,7 @@ class ClientAgent(microVM: MicroVM) {
def newStack(func: Handle, args: Seq[Handle]): Handle = {
val fv = func.vb.asInstanceOf[BoxFunc].func match {
case None => throw new UvmRuntimeException("Stack-bottom function must not be NULL")
case None => throw new UvmRuntimeException("Stack-bottom function must not be NULL")
case Some(v) => v
}
......@@ -576,4 +576,18 @@ class ClientAgent(microVM: MicroVM) {
newHandle(InternalTypes.TAGREF64, box)
}
// Internal methods for µVM
def putThread(thr: Option[InterpreterThread]): Handle = {
val t = InternalTypes.THREAD
val box = BoxThread(thr)
newHandle(t, box)
}
def putStack(sta: Option[InterpreterStack]): Handle = {
val t = InternalTypes.STACK
val box = BoxStack(sta)
newHandle(t, box)
}
}
\ No newline at end of file
......@@ -71,7 +71,7 @@ object TypeInferer {
case i: InstSelect => i.opndTy
case i: InstBranch => VOID
case i: InstBranch2 => VOID
case i: InstSelect => i.opndTy
case i: InstSwitch => VOID
case i: InstPhi => i.opndTy
case i: InstCall => i.sig.retTy
case i: InstTailCall => VOID
......
......@@ -16,10 +16,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
interpretCurrentInstruction()
}
def sta = stack.get
def top = sta.top
def curStack = stack.get
def top = curStack.top
def curBB = top.curBB
def inst = top.curInst
def curInst = top.curInst
def incPC(): Unit = top.incPC()
def jump(bb: BasicBlock, ix: Int): Unit = top.jump(bb, ix)
......@@ -50,12 +50,15 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
jump(dest, i)
}
def continueNormally(excClause: Option[ExcClause]): Unit = {
excClause match {
case None => incPC()
case Some(ec) => {
branchAndMovePC(ec.nor)
def continueNormally(): Unit = {
curInst match {
case h: HasExcClause => h.excClause match {
case None => incPC()
case Some(ec) => {
branchAndMovePC(ec.nor)
}
}
case _ => incPC()
}
}
......@@ -64,10 +67,10 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
case l: LocalVariable => top.boxes(l)
}
def ctx = "FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(top.funcVer, curBB, inst)
def ctx = "FuncVer %s, BasicBlock %s, Instruction %s (%s): ".format(top.funcVer, curBB, curInst)
private def interpretCurrentInstruction(): Unit = {
inst match {
curInst match {
case i @ InstBinOp(op, opndTy, op1, op2, excClause) => {
def doInt(l: Int, b1: ValueBox, b2: ValueBox, br: ValueBox): Unit = {
val op1v = b1.asInstanceOf[BoxInt].value
......@@ -121,7 +124,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
}
case scalarTy => doScalar(scalarTy, boxOf(op1), boxOf(op2), boxOf(i))
}
continueNormally(excClause)
continueNormally()
} catch {
case e: UvmDivisionByZeroException => excClause match {
case None => throw e
......@@ -183,12 +186,12 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
case scalarTy => doScalar(scalarTy, boxOf(op1), boxOf(op2), boxOf(i))
}
incPC()
continueNormally()
}
case i @ InstConv(op, fromTy, toTy, opnd) => {
def doScalar(bOpnd: ValueBox, br: ValueBox): Unit = {
def iToI(): Unit = (fromTy, toTy) match {
def doScalar(scalarFromTy: Type, scalarToTy: Type, bOpnd: ValueBox, br: ValueBox): Unit = {
def iToI(): Unit = (scalarFromTy, scalarToTy) match {
case (TypeInt(fl), TypeInt(tl)) => {
val od = bOpnd.asInstanceOf[BoxInt].value
val result = op match {
......@@ -198,30 +201,30 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
}
br.asInstanceOf[BoxInt].value = result
}
case _ => throw new UvmRuntimeException(ctx + "Expect integer source and dest type. Found %s and %s".format(fromTy, toTy))
case _ => throw new UvmRuntimeException(ctx + "Expect integer source and dest type. Found %s and %s".format(scalarFromTy, scalarToTy))
}
def fpToI(signed: Boolean): Unit = {
val tl = toTy match {
val tl = scalarToTy match {
case TypeInt(l) => l
case _ => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(toTy))
case _ => throw new UvmRuntimeException(ctx + "Expect integer dest type. Found %s".format(scalarToTy))
}
val result = fromTy match {
val result = scalarFromTy match {
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(fromTy))
case _ => throw new UvmRuntimeException(ctx + "Expect FP source type. Found %s.".format(scalarFromTy))
}
br.asInstanceOf[BoxInt].value = result
}
def iToFP(signed: Boolean): Unit = {
val fl = fromTy match {
val fl = scalarFromTy match {
case TypeInt(l) => l
case _ => throw new UvmRuntimeException(ctx + "Expect integer source type. Found %s".format(fromTy))
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)
toTy match {
scalarToTy match {
case TypeFloat() => {
val result = extended.toFloat
br.asInstanceOf[BoxFloat].value = result
......@@ -230,11 +233,11 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
val result = extended.toDouble
br.asInstanceOf[BoxDouble].value = result
}
case _ => throw new UvmRuntimeException(ctx + "Expect FP dest type. Found %s.".format(toTy))
case _ => throw new UvmRuntimeException(ctx + "Expect FP dest type. Found %s.".format(scalarToTy))
}
}
def bitcast(): Unit = (fromTy, toTy) match {
def bitcast(): Unit = (scalarFromTy, scalarToTy) match {
case (TypeInt(32), TypeFloat()) => {
val result = java.lang.Float.intBitsToFloat(bOpnd.asInstanceOf[BoxInt].value.intValue)
br.asInstanceOf[BoxFloat].value = result
......@@ -252,15 +255,15 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
br.asInstanceOf[BoxInt].value = result
}
case _ => throw new UvmRuntimeException(ctx +
"BITCAST can only convert between int and FP types of the same size. Found %s and %s.".format(fromTy, toTy))
"BITCAST can only convert between int and FP types of the same size. Found %s and %s.".format(scalarFromTy, scalarToTy))
}
def refcast(): Unit = (fromTy, toTy) match {
def refcast(): Unit = (scalarFromTy, scalarToTy) match {
case (TypeFunc(_), TypeFunc(_)) => br.copyFrom(bOpnd)
case (TypeThread(), TypeThread()) => br.copyFrom(bOpnd)
case (TypeStack(), TypeStack()) => br.copyFrom(bOpnd)
case _ => throw new UvmRuntimeException(ctx +
"REFCAST can only convert between two types both of which are func, thread or stack. Found %s and %s.".format(fromTy, toTy))
"REFCAST can only convert between two types both of which are func, thread or stack. Found %s and %s.".format(scalarFromTy, scalarToTy))
}
op match {
......@@ -285,9 +288,134 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
case ConvOptr.REFCAST => refcast()
}
}
(fromTy, toTy) match {
case (TypeVector(scalarFromTy, sz), TypeVector(scalarToTy, sz2)) => {
if (sz != sz2) throw new UvmRefImplException(ctx + "The source and dest vector types must have the same length")
val bOpnds = boxOf(opnd).asInstanceOf[BoxVector].values
val rBs = boxOf(i).asInstanceOf[BoxVector].values
for ((bOpnd, br) <- (bOpnds zip rBs)) {
doScalar(scalarFromTy, scalarToTy, bOpnd, br)
}
}
case _ => doScalar(fromTy, toTy, boxOf(opnd), boxOf(i))
}
incPC()
}
case i @ InstSelect(opndTy, condTy, cond, ifTrue, ifFalse) => {
def doScalar(bCond: ValueBox, bTrue: ValueBox, bFalse: ValueBox, br: ValueBox): Unit = {
val c = bCond.asInstanceOf[BoxInt].value
if (c == 1) {
br.copyFrom(bTrue)
} else {
br.copyFrom(bFalse)
}
}
condTy match {
case TypeVector(TypeInt(1), sz) => {
val bConds = boxOf(cond).asInstanceOf[BoxVector].values
val bTrues = boxOf(ifTrue).asInstanceOf[BoxVector].values
val bFalses = boxOf(ifFalse).asInstanceOf[BoxVector].values
val bResults = boxOf(i).asInstanceOf[BoxVector].values
for ((((bCond, bTrue), bFalse), br) <- bConds.zip(bTrues).zip(bFalses).zip(bResults)) {
doScalar(bCond, bTrue, bFalse, br)
}
}
case TypeInt(1) => {
doScalar(boxOf(cond), boxOf(ifTrue), boxOf(ifFalse), boxOf(i))
}
case _ => throw new UvmRefImplException(ctx + "Condition must be either int<1> or a vector of int<1>")
}
continueNormally()
}
// Indentation guide: Insert more instructions here.
case i @ InstTrap(retTy, excClause, keepAlives) => {
val ca = microVM.newClientAgent()
val hThread = ca.putThread(Some(this))
val hStack = ca.putStack(Some(curStack))
unbind(retTy)
val res = microVM.trapManager.trapHandler.handleTrap(ca, hThread, hStack, 0)
res match {
case TrapExit() => {
isRunning = false
}
case TrapRebindPassValue(newStack, value) => {
rebindPassValue(newStack.vb.asInstanceOf[BoxStack].stack, value.vb)
}
case TrapRebindPassVoid(newStack) => {
rebindPassVoid(newStack.vb.asInstanceOf[BoxStack].stack)
}
case TrapRebindThrowExc(newStack, exc) => {
rebindThrowExc(newStack.vb.asInstanceOf[BoxStack].stack, exc.vb)
}
}
ca.close()
}
// Indentation guide: Insert more instructions here.
}
}
def unbind(readyType: Type): Unit = {
curStack.state = StackState.Ready(readyType)
stack = None
}
def rebindPassValue(newStack: Option[InterpreterStack], value: ValueBox): Unit = {
if (newStack == None) throw new UvmRuntimeException(ctx + "Rebinding to NULL stack. This does not make sense.")
stack = newStack
try {
boxOf(curInst).copyFrom(value)
} catch {
case e: Exception => {
throw new UvmRuntimeException(ctx + "Error during rebinding while assigning the value passed to a stack " +
"to the instruction waiting for rebinding. This is usually caused by the mismatching between the type of " +
"READY<T> and the actual value type. The passed value box is a %s.".format(value.getClass.getName), e)
}
}
continueNormally()
}
def rebindPassVoid(newStack: Option[InterpreterStack]): Unit = {
if (newStack == None) throw new UvmRuntimeException(ctx + "Rebinding to NULL stack. This does not make sense.")
stack = newStack
continueNormally()
}
def rebindThrowExc(newStack: Option[InterpreterStack], exc: ValueBox): Unit = {
if (newStack == None) throw new UvmRuntimeException(ctx + "Rebinding to NULL stack. This does not make sense.")
val excObjRef = exc.asInstanceOf[BoxRef].objRef
stack = newStack
catchException(excObjRef)
}
/**
* Attempt to catch exception in the current frame. Will repeatedly unwind the stack until the exception can be
* handled. Stack underflow is an undefined behaviour.
*/
def catchException(exc: Word): Unit = {
throw new UvmRefImplException("Not implemented.")
}
}
package uvm.refimpl.itpr
import uvm.refimpl._
class TrapManager(microVM: MicroVM) {
var trapHandler: TrapHandler = DefaultTrapHandler
var undefinedFunctionHandler: UndefinedFunctionHandler = DefaultUndefinedFunctionHandler
object DefaultTrapHandler extends TrapHandler {
def handleTrap(ca: ClientAgent, thread: Handle, stack: Handle, watchPointID: Int): TrapHandlerResult = {
val thr = thread.vb.asInstanceOf[BoxThread].thread.get
val thrID = thr.id
val funcVerID = ca.currentFuncVer(stack, 0)
val funcVer = microVM.globalBundle.funcVerNs(funcVerID)
val instID = ca.currentInstruction(stack, 0)
val inst = microVM.globalBundle.varNs(instID)
throw new UvmRuntimeException("Unhandled trap. Thread %d, funcver %s, trap inst %s, watch point ID %d".format(
thr.id, funcVer.repr, inst.repr, watchPointID))
}
}
object DefaultUndefinedFunctionHandler extends UndefinedFunctionHandler {
def handleUndefinedFunction(functionID: Int): Unit = {
val func = microVM.globalBundle.funcNs(functionID)
throw new UvmRuntimeException("Unhandled undefined function. Function %s.".format(func.repr))
}
}
}
......@@ -217,20 +217,6 @@
COMMINST @uvm.thread_exit
}
.funcsig @select_sig = @noparamsnoret
.funcdef @select VERSION @select_v1 <@select_sig> () {
%entry:
%sel1 = SELECT <@i64> @TRUE 2 3
%sel2 = SELECT <@i64> @FALSE 2 3
%trap = TRAP <@void> KEEPALIVE (
%sel1 %sel2
)
%exit:
COMMINST @uvm.thread_exit
}
.funcsig @conv_sig = @void (@i32 @i64 @float @double)
.funcdef @conv VERSION @conv_v1 <@conv_sig> (%p0 %p1 %p2 %p3) {
%entry:
......@@ -256,488 +242,502 @@
COMMINST @uvm.thread_exit
}
.funcsig @branch_sig = @void (@i64)
.funcdef @branch VERSION @branch_v1 <@branch_sig> (%p0) {
%entry:
%cmpz = EQ <@i64> %p0 0
BRANCH2 %cmpz %iftrue %iffalse
%iftrue:
%traptrue = TRAP <@void> %exit %exit KEEPALIVE ()
%iffalse:
%trapfalse = TRAP <@void> %exit %exit KEEPALIVE ()
%exit:
COMMINST @uvm.thread_exit
RETVOID // unreachable
}
.funcsig @switch_phi_sig = @void (@i64)
.funcdef @switch_phi VERSION @switch_phi_v1 <@switch_phi_sig> (%p0) {
%entry:
SWITCH <@i64> %p0 %def {
1: %one;
2: %two;
3: %three;
}
%def:
%trapdef = TRAP <@void> %exit %exit KEEPALIVE ()
%one:
%trapone = TRAP <@void> %exit %exit KEEPALIVE ()
%two:
%traptwo = TRAP <@void> %exit %exit KEEPALIVE ()
%three:
%trapthree = TRAP <@void> %exit %exit KEEPALIVE ()
%exit:
%phi = PHI <@i64> {
%def: 10;
%one: 11;
%two: 12;
%three: 13;
}
%trapend = TRAP <@void> %exit2 %exit2 KEEPALIVE (%phi)
%exit2:
COMMINST @uvm.thread_exit
RETVOID // unreachable
}
.funcsig @square_sum_sig = @i_ii
.funcdef @square_sum VERSION @square_sum_v1 <@square_sum_sig> (%a %b) {
%entry:
%a2 = MUL <@i64> %a %a
%b2 = MUL <@i64> %b %b
%s = ADD <@i64> %a2 %b2
RET <@i64> %s
}
.funcsig @call_ret_sig = @i_ii
.funcdef @call_ret VERSION @call_ret_v1 <@call_ret_sig> (%a %b) {
%entry:
%ss = CALL <@i_ii> @square_sum (%a %b)
%trap = TRAP <@void> KEEPALIVE (%ss)
%exit:
COMMINST @uvm.thread_exit
}
.funcsig @thrower_sig = @noparamsnoret
.funcdef @thrower VERSION @thrower_v1 <@thrower_sig> () {
%entry:
THROW @NULLREF
}
.funcsig @invoke_landingpad_sig = @noparamsnoret
.funcdef @invoke_landingpad VERSION @invoke_landingpad_v1 <@invoke_landingpad_sig> () {
%entry:
%ss = INVOKE <@noparamsnoret> @thrower () %nor %exc
%nor:
%trapnor = TRAP <@void> %exit %exit KEEPALIVE ()
%exc:
%lp = LANDINGPAD
%trapexc = TRAP <@void> %exit %exit KEEPALIVE (%lp)
%exit:
COMMINST @uvm.thread_exit
}
// Some simple struct constants
.typedef @StructFoo = struct <@i32 @i64 @float @double>
.const @STRUCT_FOO <@StructFoo> = {1 2 3.0f 4.0d}
.funcsig @aggregate_sig = @noparamsnoret
.funcdef @aggregate VERSION @aggregate_v1 <@aggregate_sig> () {
%entry:
%f1 = EXTRACTVALUE <@StructFoo 1> @STRUCT_FOO
%s2 = INSERTVALUE <@StructFoo 1> @STRUCT_FOO 222
%f12 = EXTRACTVALUE <@StructFoo 1> %s2
%trapnor = TRAP <@void> KEEPALIVE (%f1 %f12)
%exit:
COMMINST @uvm.thread_exit
}
.typedef @refi64 = ref<@i64>
.typedef @irefi64 = iref<@i64>
.typedef @weakrefi64 = weakref<@i64>
.typedef @StructBar = struct <
@i64 @i32 @i16 @i8 @float @double
@refi64 @irefi64 @weakrefi64
>
.typedef @refBar = ref<@StructBar>
.typedef @irefBar = iref<@StructBar>
.typedef @hCharArray = hybrid<@i64 @i8>
.funcsig @allocs_sig = @void (@i64)
.funcdef @allocs VERSION @allocs_v1 <@allocs_sig> (%sz) {
%entry:
%new = NEW <@StructBar>
%newhybrid = NEWHYBRID <@hCharArray> %sz
%alloca = ALLOCA <@StructBar>
%allocahybrid = ALLOCAHYBRID <@hCharArray> %sz
%trap = TRAP <@void> KEEPALIVE (%new %newhybrid %alloca %allocahybrid)
%exit:
COMMINST @uvm.thread_exit
}
.typedef @ArrayBaz = array <@i16 1024>
.const @THREE <@i64> = 3
.typedef @JavaLikeByteArray = hybrid <@i32 @i8>
.const @I64_1024 <@i64> = 1024
.funcsig @memAddressing_sig = @noparamsnoret
.funcdef @memAddressing VERSION @memAddressing_v1 <@memAddressing_sig> () {
%entry:
%bar_ref = NEW <@StructBar>
%bar_iref = GETIREF <@StructBar> %bar_ref
%bar_3 = GETFIELDIREF <@StructBar 3> %bar_iref
%baz_iref = ALLOCA <@ArrayBaz>
%baz_3 = GETELEMIREF <@ArrayBaz> %baz_iref @THREE
%baz_6 = SHIFTIREF <@i16> %baz_3 @THREE
%ja_ref = NEWHYBRID <@JavaLikeByteArray> @I64_1024
%ja_iref = GETIREF <@JavaLikeByteArray> %ja_ref
%ja_fix = GETFIXEDPARTIREF <@JavaLikeByteArray> %ja_iref
%ja_var = GETVARPARTIREF <@JavaLikeByteArray> %ja_iref
%trap = TRAP <@void> KEEPALIVE (%bar_ref %bar_iref %bar_3
%baz_iref %baz_3 %baz_6 %ja_ref %ja_iref %ja_fix %ja_var)
%exit:
COMMINST @uvm.thread_exit
}
.global @g_i8 <@i8>
.global @g_i16 <@i16>
.global @g_i32 <@i32>
.global @g_i64 <@i64>
.global @g_f <@float>
.global @g_d <@double>
.global @g_r <@refvoid>
.global @g_ir <@irefvoid>
.global @g_wr <@weakrefvoid>
.global @g_func <@funcdumb>
.global @g_thr <@thread>
.global @g_sta <@stack>
.global @g_tr64 <@tagref64>
.funcsig @memAccessing_sig = @noparamsnoret
.funcdef @memAccessing VERSION @memAccessing_v1 <@memAccessing_sig> () {
%entry:
STORE <@i8> @g_i8 41
STORE <@i16> @g_i16 42
STORE <@i32> @g_i32 43
STORE <@i64> @g_i64 44
STORE <@float> @g_f 45.0f
STORE <@double> @g_d 46.0d
%void_r = NEW <@void>
%void_ir = ALLOCA <@void>
STORE <@refvoid> @g_r %void_r
STORE <@irefvoid> @g_ir %void_ir
STORE <@weakrefvoid> @g_wr %void_r
STORE <@funcdumb> @g_func @memAccessing
%li8 = LOAD <@i8> @g_i8
%li16 = LOAD <@i16> @g_i16
%li32 = LOAD <@i32> @g_i32
%li64 = LOAD <@i64> @g_i64
%lf = LOAD <@float> @g_f
%ld = LOAD <@double> @g_d
%lr = LOAD <@refvoid> @g_r
%lir = LOAD <@irefvoid> @g_ir
%lwr = LOAD <@weakrefvoid> @g_wr
%lfunc = LOAD <@funcdumb> @g_func
%trap = TRAP <@void> KEEPALIVE (%void_r %void_ir %li8 %li16
%li32 %li64 %lf %ld %lr %lir %lwr %lfunc)
%exit:
COMMINST @uvm.thread_exit
}
.funcsig @memAccessingAtomic_sig = @noparamsnoret
.funcdef @memAccessingAtomic VERSION @memAccessingAtomic_v1 <@memAccessingAtomic_sig> () {
%entry:
STORE SEQ_CST <@i32> @g_i32 43
STORE SEQ_CST <@i64> @g_i64 44
%void_r = NEW <@void>
%void_r2 = NEW <@void>
%void_r3 = NEW <@void>
STORE <@refvoid> @g_r %void_r
%cx32_1 = CMPXCHG SEQ_CST UNORDERED <@i32> @g_i32 43 53
%cx32_2 = CMPXCHG SEQ_CST UNORDERED <@i32> @g_i32 43 63
%cx64_1 = CMPXCHG SEQ_CST UNORDERED <@i64> @g_i64 44 54
%cx64_2 = CMPXCHG SEQ_CST UNORDERED <@i64> @g_i64 44 64
%l32 = LOAD SEQ_CST <@i32> @g_i32
%l64 = LOAD SEQ_CST <@i64> @g_i64
%cxr_1 = CMPXCHG SEQ_CST UNORDERED <@refvoid> @g_r %void_r %void_r2
%cxr_2 = CMPXCHG SEQ_CST UNORDERED <@refvoid> @g_r %void_r %void_r3
%lr = LOAD <@refvoid> @g_r
STORE <@i64> @g_i64 1
%rmw0 = ATOMICRMW SEQ_CST XCHG <@i64> @g_i64 0x55ab // 1 -> 0x55ab
%rmw1 = ATOMICRMW SEQ_CST ADD <@i64> @g_i64 3 // 0x55ab -> 0x55ae
%rmw2 = ATOMICRMW SEQ_CST SUB <@i64> @g_i64 4 // 0x55ae -> 0x55aa
%rmw3 = ATOMICRMW SEQ_CST AND <@i64> @g_i64 0x5a5a // 0x55aa -> 0x500a
%rmw4 = ATOMICRMW SEQ_CST NAND <@i64> @g_i64 0x5a5a // 0x500a -> ~0x500a
%rmw5 = ATOMICRMW SEQ_CST OR <@i64> @g_i64 0x5000 // ~0x500a -> ~0x000a
%rmw6 = ATOMICRMW SEQ_CST XOR <@i64> @g_i64 0x55aa // ~0x000a -> ~0x55a0
%rmw7 = ATOMICRMW SEQ_CST MIN <@i64> @g_i64 -0x7fffffffffffffde // ~0x55a0 -> -0x7fffffffffffffde
%rmw8 = ATOMICRMW SEQ_CST MAX <@i64> @g_i64 42 // -0x7fffffffffffffde -> 42
%rmw9 = ATOMICRMW SEQ_CST UMIN <@i64> @g_i64 11 // 42 -> 11
%rmwA = ATOMICRMW SEQ_CST UMAX <@i64> @g_i64 0xffffffffffffffde // 11 -> 0xffffffffffffffde
%l64_2 = LOAD SEQ_CST <@i64> @g_i64
%trap = TRAP <@void> KEEPALIVE (%void_r %void_r2 %void_r3
%cx32_1 %cx32_2 %cx64_1 %cx64_2 %l32 %l64 %cxr_1 %cxr_2 %lr
%rmw0 %rmw1 %rmw2 %rmw3 %rmw4 %rmw5 %rmw6 %rmw7 %rmw8 %rmw9 %rmwA %l64_2)
%exit:
COMMINST @uvm.thread_exit
}
.funcsig @watchpointtest_sig = @noparamsnoret
.funcdef @watchpointtest VERSION @watchpointtest_v1 <@watchpointtest_sig> () {
%entry:
BRANCH %head
%head:
%wp = WATCHPOINT 42 <@i64> %dis %ena %enaexc KEEPALIVE ()
%dis:
%trapdis = TRAP <@void> %exit %exit KEEPALIVE ()
%ena:
%trapena = TRAP <@void> %exit %exit KEEPALIVE (%wp)
%enaexc:
%exc = LANDINGPAD
%trapena = TRAP <@void> %exit %exit KEEPALIVE (%exc)
%exit:
COMMINST @uvm.thread_exit
}
.funcsig @testswapstack_sig = @noparamsnoret
.funcdef @testswapstack VERSION @testswapstack_v1 <@testswapstack_sig> () {
%entry:
%valueret = ALLOCA <@i64>
%shouldstop = ALLOCA <@i64> // initially zeroed
%thisstack = COMMINST @uvm.current_stack ()
%iter = NEWSTACK <@itersig> @rangeiter (3 %thisstack %valueret %shouldstop)
COMMINST @uvm.swap_stack (%iter)
BRANCH %head
%head: