Commit bc1bd06d authored by Kunshan Wang's avatar Kunshan Wang

More static checks

Now checks memory operations and function call argument types.
parent f2aac08e
......@@ -7,6 +7,7 @@ import com.typesafe.scalalogging.Logger
import uvm._
import uvm.ssavariables._
import uvm.types._
import uvm.clientsupport.text.Inst.GetIRef
object BundleChecker {
val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -433,11 +434,23 @@ class BundleChecker {
case i: InstWPBranch => Seq(i.dis, i.ena).map(d => (d, true))
case i: HasExcClause => i.excClause.map(e => Seq((e.nor, true), (e.exc, false))).getOrElse(Seq())
}
def checkInst(fv: FuncVer, bb: BasicBlock, i: Instruction): Unit = {
implicit val _fv = fv
implicit val _bb = bb
implicit val _inst = i
def checkPtrAndOpnd(ptr: Boolean, opndType: Type): Unit = {
(ptr, opndType) match {
case (false, _: TypeIRef) =>
case (true, _: TypeUPtr) =>
case (true, ty: TypeIRef) => throw errorFBI(s"Expected uptr, but operand has iref type: ${ty}")
case (false, ty: TypeUPtr) => throw errorFBI(s"Expected iref, but operand has uptr type: ${ty}")
case (_, ty) =>
throw errorFBI(s"Unexpected operand type ${ty}. Expected iref or uptr type")
}
}
i match {
case i: MaybeTerminator if i.canTerminate =>
throw errorFBI("Instruction %s is a terminator and must be the last instruction of a basic block."
......@@ -461,6 +474,14 @@ class BundleChecker {
.format(i.repr, nargs, nparams, i.toString),
pretty = Seq(i, i.sig))
}
for (((sigTy, arg), i) <- (i.sig.paramTys zip i.argList).zipWithIndex) {
val argTy = arg.inferredType
if (!(sigTy shallowEq argTy)) {
throw errorFBI(s"The ${i}-th argument's actual type ${argTy} does not match the signature's ${i}-th type: ${sigTy}",
pretty = Seq(sigTy, arg))
}
}
}
case i: InstBinOp => {
import BinOptr._
......@@ -553,6 +574,104 @@ class BundleChecker {
throw errorFBI(s"RHS ${i.op1} has type ${i.op1.inferredType}, which does not match the operand type ${i.opndTy}")
}
}
case i: FixedAlloc => { // NEW, ALLOCA
i.allocTy match {
case ty: TypeHybrid => {
throw errorFBI(s"NEW and ALLOCA can only allocate fixed type. Hybrid found: ${ty}")
}
case _ =>
}
}
case i: HybridAlloc => { // NEWHYBRID, ALLOCAHYBRID
i.allocTy match {
case _: TypeHybrid =>
case ty => {
throw errorFBI(s"NEWHYBRID and ALLOCAHYBRID can only allocate hybrid type. Fixed type found: ${ty}")
}
}
i.lenTy match {
case TypeInt(_) =>
case ty => {
throw errorFBI(s"The length type must be an int. Found ${ty.repr} ${ty}")
}
}
if (!(i.length.inferredType shallowEq i.lenTy)) {
throw errorFBI(s"The actual length argument (type ${i.length.inferredType} does not match the annotated type ${i.lenTy.repr} ${i.lenTy}")
}
}
case i: InstGetIRef => {
i.opnd.inferredType match {
case TypeRef(_) =>
case ty => {
throw errorFBI(s"The operand must have ref type. Actual type: ${ty}")
}
}
}
case i: InstGetFieldIRef => {
checkPtrAndOpnd(i.ptr, i.opnd.inferredType)
i.referentTy match {
case _: AbstractStructType =>
case ty => {
throw errorFBI(s"The referent must have struct or hybrid type. Actual type: ${ty}")
}
}
}
case i: InstGetElemIRef => {
checkPtrAndOpnd(i.ptr, i.opnd.inferredType)
i.referentTy match {
case _: AbstractSeqType =>
case ty => {
throw errorFBI(s"The Referent must have array or vector type. Actual type: ${ty}")
}
}
}
case i: InstShiftIRef => {
checkPtrAndOpnd(i.ptr, i.opnd.inferredType)
}
case i: InstGetVarPartIRef => {
checkPtrAndOpnd(i.ptr, i.opnd.inferredType)
i.referentTy match {
case _: TypeHybrid =>
case ty => {
throw errorFBI(s"The Referent must have hybrid type. Actual type: ${ty}")
}
}
}
case i: InstLoad => {
checkPtrAndOpnd(i.ptr, i.loc.inferredType)
i.ord match {
case MemoryOrder.RELEASE | MemoryOrder.ACQ_REL => {
throw errorFBI(s"LOAD cannot have RELEASE order. Found: ${i.ord}")
}
case _ =>
}
}
case i: InstStore => {
checkPtrAndOpnd(i.ptr, i.loc.inferredType)
i.ord match {
case MemoryOrder.ACQUIRE | MemoryOrder.ACQ_REL => {
throw errorFBI(s"STORE cannot have ACQUIRE order. Found: ${i.ord}")
}
case _ =>
}
}
case i: InstCmpXchg => {
import MemoryOrder._
checkPtrAndOpnd(i.ptr, i.loc.inferredType)
(i.ordSucc, i.ordFail) match {
case (NOT_ATOMIC, _) | (_, NOT_ATOMIC) => throw errorFBI(s"CMPXCHG cannot have NOT_ATOMIC order")
case (_, RELEASE) | (_, ACQ_REL) => throw errorFBI(s"Cannot have RELEASE order when failed")
case _ =>
}
}
case i: InstAtomicRMW => {
checkPtrAndOpnd(i.ptr, i.loc.inferredType)
i.ord match {
case MemoryOrder.NOT_ATOMIC => throw errorFBI(s"ATOMICRMW cannot have NOT_ATOMIC order")
case _ =>
}
}
case _ =>
}
}
......
......@@ -29,19 +29,13 @@ class GetFieldIRefTest extends UvmBundleTesterBase {
"uvm.refimpl.misc" -> DEBUG,
"uvm.refimpl.itpr" -> DEBUG)
preloadBundles("tests/uvm-refimpl-test/primitives.uir", "tests/uvm-refimpl-test/getfieldireftest.uir")
preloadBundles("tests/uvm-refimpl-test/primitives.uir")
"GetFieldIRef" should "not work if the argument is a ref" in {
val ctx = microVM.newContext()
val func = ctx.handleFromFunc("@main")
var exceptionCaught: Boolean = false
try {
testFunc(ctx, func, Seq()) { (ctx, th, st, wp) =>
returnFromTrap(st)
}
preloadBundles("tests/uvm-refimpl-test/getfieldireftest.uir")
} catch {
case e: Exception => {
logger.info("Caught exception. This is expected.", e)
......@@ -52,7 +46,5 @@ class GetFieldIRefTest extends UvmBundleTesterBase {
if (!exceptionCaught) {
fail("Exception expected, but not caught")
}
ctx.closeContext()
}
}
\ No newline at end of file
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