operationHelpers.scala 29 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1 2
package uvm.refimpl.itpr

3 4
import java.nio.charset.Charset

5 6
import uvm.Function
import uvm.ir.irbuilder.IRBuilder
Kunshan Wang's avatar
Kunshan Wang committed
7
import uvm.refimpl._
8
import uvm.refimpl.integerize._
9
import uvm.refimpl.mem.MemorySupport
10 11 12 13 14
import uvm.refimpl.mem.Mutator
import uvm.refimpl.mem.TypeSizes._
import uvm.ssavariables._
import uvm.ssavariables.AtomicRMWOptr._
import uvm.types._
Kunshan Wang's avatar
Kunshan Wang committed
15
import uvm.refimpl.nat.NativeMemoryAccessHelper
16
import InterpreterThread.logger
Kunshan Wang's avatar
Kunshan Wang committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

object OpHelper {

  val ONE = BigInt(1)

  def mask(n: Int): BigInt = {
    (ONE << n) - ONE
  }

  def truncFromBigInt(n: BigInt, len: Int): BigInt = n & mask(len)

  def zextToBigInt(n: BigInt, len: Int): BigInt = n & mask(len)

  def sextToBigInt(n: BigInt, len: Int): BigInt = {
    val bit = n.testBit(len - 1)
    if (bit) {
      n | (~mask(len - 1))
    } else {
      n & (mask(len - 1))
    }
  }

39 40 41 42 43
  // The BigInt in a BoxInt is always truncated to len bits.
  //
  // "prepare" means sign- or zero-extend the content to get the real math value.
  // "unprepare" means truncating a math value to len bits to be stored in a BoxInt.

Kunshan Wang's avatar
Kunshan Wang committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  def prepareUnsigned(n: BigInt, len: Int): BigInt = truncFromBigInt(n, len)

  def prepareSigned(n: BigInt, len: Int): BigInt = {
    sextToBigInt(truncFromBigInt(n, len), len)
  }

  def unprepare(n: BigInt, len: Int): BigInt = truncFromBigInt(n, len)

  def trunc(n: BigInt, toLen: Int): BigInt = truncFromBigInt(n, toLen)

  def zext(n: BigInt, fromLen: Int, toLen: Int): BigInt = truncFromBigInt(n, fromLen)

  def sext(n: BigInt, fromLen: Int, toLen: Int): BigInt = {
    truncFromBigInt(sextToBigInt(n, fromLen), toLen)
  }

  def maxSInt(l: Int): BigInt = (BigInt(1) << (l - 1)) - 1
  def minSIntAbs(l: Int): BigInt = BigInt(1) << (l - 1)
  def maxUInt(l: Int): BigInt = (BigInt(1) << l) - 1

  /**
   * Convert a float to an integer. The result only has the lowest iLen binary digits.
   */
  def floatToI(n: Float, iLen: Int, signed: Boolean): BigInt = {
    val lExp = Math.getExponent(n)
    val rExp = lExp - 23
    val frac = (java.lang.Float.floatToRawIntBits(n) & 0x7fffff) | 0x800000;

    if (java.lang.Float.isNaN(n)) 0
    else if (signed) {
      if (java.lang.Float.isInfinite(n)) { if (n > 0.0F) maxSInt(iLen) else minSIntAbs(iLen) }
      else {
        if (lExp >= (iLen - 1)) if (n > 0.0F) maxSInt(iLen) else minSIntAbs(iLen)
        else if (lExp < 0) 0
        else {
          val abs = BigInt(frac) << rExp
          unprepare(if (n < 0.0F) -abs else abs, iLen)
        }
      }
    } else {
      if (n < 0.0F) 0
      else if (java.lang.Float.isInfinite(n)) maxUInt(iLen)
      else {
        if (lExp >= iLen) maxUInt(iLen)
        else if (lExp < 0) 0
        else unprepare(BigInt(frac) << rExp, iLen)
      }
    }
  }

  /**
   * Convert a float to an integer. The result only has the lowest iLen binary digits.
   */
  def doubleToI(n: Double, iLen: Int, signed: Boolean): BigInt = {
    val lExp = Math.getExponent(n)
    val rExp = lExp - 52
    val frac = (java.lang.Double.doubleToRawLongBits(n) & 0xfffffffffffffL) | 0x10000000000000L;
101

Kunshan Wang's avatar
Kunshan Wang committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    if (java.lang.Double.isNaN(n)) 0
    else if (signed) {
      if (java.lang.Double.isInfinite(n)) { if (n > 0.0D) maxSInt(iLen) else minSIntAbs(iLen) }
      else {
        if (lExp >= (iLen - 1)) if (n > 0.0D) maxSInt(iLen) else minSIntAbs(iLen)
        else if (lExp < 0) 0
        else {
          val abs = BigInt(frac) << rExp
          unprepare(if (n < 0.0D) -abs else abs, iLen)
        }
      }
    } else {
      if (n < 0.0D) 0
      else if (java.lang.Double.isInfinite(n)) maxUInt(iLen)
      else {
        if (lExp >= iLen) maxUInt(iLen)
        else if (lExp < 0) 0
        else unprepare(BigInt(frac) << rExp, iLen)
      }
    }
  }

124 125 126 127 128 129
  /**
   * Test if opnd, a tagref64 value, represents an integer.
   * 
   * A tagref64 represents integer if it has the bit pattern ?111 1111 1111 ???? ???? ... ???? ???1,
   * that is, a NaN with the lowest bit of the fraction being 1.
   */
Kunshan Wang's avatar
Kunshan Wang committed
130 131 132 133
  def tr64IsInt(opnd: Long): Boolean = {
    (opnd & 0x7ff0000000000001L) == 0x7ff0000000000001L
  }

134 135 136 137 138
  /**
   * Test if opnd, a tagref64 value, represents an IEEE754 double-precision floating point number (double).
   * 
   * A tagref64 represents a double if it is neither a ref nor an integer.
   */
139
  def tr64IsFP(opnd: Long): Boolean = {
140
    !tr64IsInt(opnd) && !tr64IsRef(opnd)
Kunshan Wang's avatar
Kunshan Wang committed
141 142
  }

143 144 145 146 147 148
  /**
   * Test if opnd, a tagref64 value, represents a reference.
   * 
   * A tagref64 represents a ref if the bit pattern is ?111 1111 1111 ???? ???? .... ???? ??10,
   * that is, a NaN with the 2 lowest bits of the fraction being 10.
   */
Kunshan Wang's avatar
Kunshan Wang committed
149 150 151 152
  def tr64IsRef(opnd: Long): Boolean = {
    (opnd & 0x7ff0000000000003L) == 0x7ff0000000000002L
  }

153 154 155 156 157 158 159
  /**
   * Converts a 52-bit integer into a tagref64.
   * 
   * Int:      abbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb
   * 
   * tagref64: a111 1111 1111 bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbbb bbb1
   */
Kunshan Wang's avatar
Kunshan Wang committed
160 161 162 163 164
  def intToTr64(opnd: Long): Long = {
    (0x7ff0000000000001L | ((opnd & 0x7ffffffffffffL) << 1) |
      ((opnd & 0x8000000000000L) << 12))
  }

165 166 167 168 169 170 171 172 173
  /**
   * Converts a double into a tagref64
   * 
   * If it is not a NaN, return as is; otherwise return one of the four "canonical" NaN values:
   * 
   * s111 1111 1111 1q00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100
   * 
   * where s (sign bit) and q (quiet/signalling) are preserved.
   */
Kunshan Wang's avatar
Kunshan Wang committed
174
  def fpToTr64(opnd: Double): Long = {
175 176 177 178 179
    val doubleBits = java.lang.Double.doubleToRawLongBits(opnd)
    val resultBits = if (java.lang.Double.isNaN(opnd)) {
      doubleBits & 0xfff8000000000000L | 0x0000000000000008L
    } else {
      doubleBits
Kunshan Wang's avatar
Kunshan Wang committed
180
    }
181
    resultBits
Kunshan Wang's avatar
Kunshan Wang committed
182 183
  }

184 185 186 187 188 189
  /**
   * Converts a ref and a tag into a tagref64.
   * 
   * NOTE: All objects are 8-byte aligned. The current Mu spec's design only
   * allows 48-bit effective address. which x86_64 currently implements.
   * 
190
   * ref:      0000 0000 0000 0000 rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr r000
191
   * 
192
   * tag: abbbbc
193
   * 
194
   * tagref64: a111 1111 1111 bbbb rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rc10
195
   */
Kunshan Wang's avatar
Kunshan Wang committed
196
  def refToTr64(opnd: Long, tag: Long): Long = {
197 198 199
    (0x7ff0000000000002L | (opnd & 0xfffffffffff8L) |
      ((tag & 0x20L) << (63 - 5)) |
      ((tag & 0x1eL) << (48 - 1)) |
Kunshan Wang's avatar
Kunshan Wang committed
200 201 202
      ((tag & 0x1) << 2))
  }

203 204 205
  /**
   * Assume the tagref64 opnd represents an integer, and extract that integer.
   */
Kunshan Wang's avatar
Kunshan Wang committed
206
  def tr64ToInt(opnd: Long): Long = {
207 208
    (((opnd & 0xffffffffffffeL) >>> 1) |
    		((opnd & 0x8000000000000000L) >>> 12))
Kunshan Wang's avatar
Kunshan Wang committed
209
  }
210 211 212 213 214 215
  
  /**
   * Assume the tagref64 opnd represents a double, and extract that double.
   * 
   * Non-NaN doubles are represented as is. NaNs are canonicalized, but are still NaNs.
   */
216
  def tr64ToFP(opnd: Long): Double = java.lang.Double.longBitsToDouble(opnd)
Kunshan Wang's avatar
Kunshan Wang committed
217

218 219 220 221 222 223 224
  /**
   * Assume the tagref64 opnd represents a ref and a tag, and extract the ref.
   * 
   * tagref64: s??? ???? ???? ???? ?rrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr r???
   * 
   * ref:      ssss ssss ssss ssss srrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr rrrr r000
   */
Kunshan Wang's avatar
Kunshan Wang committed
225
  def tr64ToRef(opnd: Long): Long = {
226
    (opnd & 0xfffffffffff8L)
Kunshan Wang's avatar
Kunshan Wang committed
227 228
  }

229 230 231
  /**
   * Assume the tagref64 opnd represents a ref and a tag, and extract the tag.
   * 
232
   * tagref64: a??? ???? ???? bbbb ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ?c??
233 234 235
   * 
   * tag: aaaaab
   */
Kunshan Wang's avatar
Kunshan Wang committed
236
  def tr64ToTag(opnd: Long): Long = {
237
    (((opnd & 0x8000000000000000L) >>> (63 - 5) | (opnd & 0x000f000000000000L) >>> (48 - 1)) | ((opnd & 0x4) >>> 2))
Kunshan Wang's avatar
Kunshan Wang committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
  }
}

object PrimOpHelpers {
  @throws(classOf[UvmDivisionByZeroException])
  def intBinOp(op: BinOptr.BinOptr, l: Int, op1v: BigInt, op2v: BigInt, ctx: => String): BigInt = {
    def pu(v: BigInt): BigInt = OpHelper.prepareUnsigned(v, l)
    def ps(v: BigInt): BigInt = OpHelper.prepareSigned(v, l)
    def up(v: BigInt): BigInt = OpHelper.unprepare(v, l)
    def shiftMask = {
      var i = 1
      while (i < l) { i <<= 1 }
      i - 1
    }
    def checkDivByZero(): Unit = {
      if (op2v == 0) throw new UvmDivisionByZeroException(ctx + "Division by zero.")
    }

256
    logger.debug("op1: " + op1v + " op2: " + op2v)
Kunshan Wang's avatar
Kunshan Wang committed
257
    up(op match {
258 259 260
      case BinOptr.ADD  => pu(op1v) + pu(op2v)
      case BinOptr.SUB  => pu(op1v) - pu(op2v)
      case BinOptr.MUL  => pu(op1v) * pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
261 262 263 264
      case BinOptr.UDIV => { checkDivByZero(); pu(op1v) / pu(op2v) }
      case BinOptr.SDIV => { checkDivByZero(); ps(op1v) / ps(op2v) }
      case BinOptr.UREM => { checkDivByZero(); pu(op1v) % pu(op2v) }
      case BinOptr.SREM => { checkDivByZero(); ps(op1v) % ps(op2v) }
265
      case BinOptr.SHL  => pu(op1v) << (op2v.intValue & shiftMask)
Kunshan Wang's avatar
Kunshan Wang committed
266 267
      case BinOptr.LSHR => pu(op1v) >> (op2v.intValue & shiftMask)
      case BinOptr.ASHR => ps(op1v) >> (op2v.intValue & shiftMask)
268 269 270 271
      case BinOptr.AND  => pu(op1v) & pu(op2v)
      case BinOptr.OR   => pu(op1v) | pu(op2v)
      case BinOptr.XOR  => pu(op1v) ^ pu(op2v)
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for integer.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
272 273 274
    })
  }

Kunshan Wang's avatar
Kunshan Wang committed
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  def intBinOpFlags(op: BinOptr.BinOptr, l: Int, op1v: BigInt, op2v: BigInt, resv: BigInt, ctx: => String): (Boolean, Boolean, Boolean, Boolean) = {
    def pu(v: BigInt): BigInt = OpHelper.prepareUnsigned(v, l)
    def ps(v: BigInt): BigInt = OpHelper.prepareSigned(v, l)
    def up(v: BigInt): BigInt = OpHelper.unprepare(v, l)

    val (op1u, op1s) = (pu(op1v), ps(op1v))
    val (op2u, op2s) = (pu(op2v), ps(op2v))
    val (resu, ress) = (pu(resv), ps(resv))
    
    val n = ress < 0
    val z = resu == 0

    val (c, v) = op match {
      case BinOptr.ADD => (resu != op1u + op2u, ress != op1s + op2s)
      case BinOptr.SUB => (resu != op1u - op2u, ress != op1s - op2s)
      case BinOptr.MUL => (resu != op1u * op2u, ress != op1s * op2s)
      case _           => (false, false)
    }

    (n, z, c, v)
  }

Kunshan Wang's avatar
Kunshan Wang committed
297 298 299 300 301 302 303
  def floatBinOp(op: BinOptr.BinOptr, op1v: Float, op2v: Float, ctx: => String): Float = {
    op match {
      case BinOptr.FADD => op1v + op2v
      case BinOptr.FSUB => op1v - op2v
      case BinOptr.FMUL => op1v * op2v
      case BinOptr.FDIV => op1v / op2v
      case BinOptr.FREM => Math.IEEEremainder(op1v, op2v).toFloat
304
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
305 306 307 308 309 310 311 312 313 314
    }
  }

  def doubleBinOp(op: BinOptr.BinOptr, op1v: Double, op2v: Double, ctx: => String): Double = {
    op match {
      case BinOptr.FADD => op1v + op2v
      case BinOptr.FSUB => op1v - op2v
      case BinOptr.FMUL => op1v * op2v
      case BinOptr.FDIV => op1v / op2v
      case BinOptr.FREM => Math.IEEEremainder(op1v, op2v)
315
      case _            => throw new UvmRuntimeException(ctx + "Binary operator %s is not suitable for double.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
316 317 318 319 320 321 322
    }
  }

  def intCmp(op: CmpOptr.CmpOptr, l: Int, op1v: BigInt, op2v: BigInt, ctx: => String): Boolean = {
    def pu(v: BigInt): BigInt = OpHelper.prepareUnsigned(v, l)
    def ps(v: BigInt): BigInt = OpHelper.prepareSigned(v, l)

323
    logger.debug("op1: " + op1v + " op2: " + op2v)
Kunshan Wang's avatar
Kunshan Wang committed
324
    op match {
325 326
      case CmpOptr.EQ  => pu(op1v) == pu(op2v)
      case CmpOptr.NE  => pu(op1v) != pu(op2v)
Kunshan Wang's avatar
Kunshan Wang committed
327 328 329 330 331 332 333 334
      case CmpOptr.UGT => pu(op1v) > pu(op2v)
      case CmpOptr.UGE => pu(op1v) >= pu(op2v)
      case CmpOptr.ULT => pu(op1v) < pu(op2v)
      case CmpOptr.ULE => pu(op1v) <= pu(op2v)
      case CmpOptr.SGT => ps(op1v) > ps(op2v)
      case CmpOptr.SGE => ps(op1v) >= ps(op2v)
      case CmpOptr.SLT => ps(op1v) < ps(op2v)
      case CmpOptr.SLE => ps(op1v) <= ps(op2v)
335
      case _           => throw new UvmRuntimeException(ctx + "Comparison operator %s not suitable for integers".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
336 337 338 339 340 341 342 343
    }
  }

  def floatCmp(op: CmpOptr.CmpOptr, op1v: Float, op2v: Float, ctx: => String): Boolean = {
    import java.lang.Float.isNaN
    def ord = !isNaN(op1v) && !isNaN(op2v)
    def uno = isNaN(op1v) || isNaN(op2v)
    op match {
344
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
345
      case CmpOptr.FFALSE => false
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
      case CmpOptr.FOEQ   => ord && op1v == op2v
      case CmpOptr.FONE   => ord && op1v != op2v
      case CmpOptr.FOGT   => ord && op1v > op2v
      case CmpOptr.FOGE   => ord && op1v >= op2v
      case CmpOptr.FOLT   => ord && op1v < op2v
      case CmpOptr.FOLE   => ord && op1v <= op2v
      case CmpOptr.FORD   => ord
      case CmpOptr.FUEQ   => uno || op1v == op2v
      case CmpOptr.FUNE   => uno || op1v != op2v
      case CmpOptr.FUGT   => uno || op1v > op2v
      case CmpOptr.FUGE   => uno || op1v >= op2v
      case CmpOptr.FULT   => uno || op1v < op2v
      case CmpOptr.FULE   => uno || op1v <= op2v
      case CmpOptr.FUNO   => uno
      case _              => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for float.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
361 362 363 364 365 366 367 368
    }
  }

  def doubleCmp(op: CmpOptr.CmpOptr, op1v: Double, op2v: Double, ctx: => String): Boolean = {
    import java.lang.Double.isNaN
    def ord = !isNaN(op1v) && !isNaN(op2v)
    def uno = isNaN(op1v) || isNaN(op2v)
    op match {
369
      case CmpOptr.FTRUE  => true
Kunshan Wang's avatar
Kunshan Wang committed
370
      case CmpOptr.FFALSE => false
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
      case CmpOptr.FOEQ   => ord && op1v == op2v
      case CmpOptr.FONE   => ord && op1v != op2v
      case CmpOptr.FOGT   => ord && op1v > op2v
      case CmpOptr.FOGE   => ord && op1v >= op2v
      case CmpOptr.FOLT   => ord && op1v < op2v
      case CmpOptr.FOLE   => ord && op1v <= op2v
      case CmpOptr.FORD   => ord
      case CmpOptr.FUEQ   => uno || op1v == op2v
      case CmpOptr.FUNE   => uno || op1v != op2v
      case CmpOptr.FUGT   => uno || op1v > op2v
      case CmpOptr.FUGE   => uno || op1v >= op2v
      case CmpOptr.FULT   => uno || op1v < op2v
      case CmpOptr.FULE   => uno || op1v <= op2v
      case CmpOptr.FUNO   => uno
      case _              => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for double.".format(op))
Kunshan Wang's avatar
Kunshan Wang committed
386 387
    }
  }
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422

  def refCmp(op: CmpOptr.CmpOptr, op1v: Word, op2v: Word, ctx: => String): Boolean = {
    op match {
      case CmpOptr.EQ => op1v == op2v
      case CmpOptr.NE => op1v != op2v
      case _          => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for ref.".format(op))
    }
  }

  def irefCmp(op: CmpOptr.CmpOptr, op1b: Word, op1o: Word, op2b: Word, op2o: Word, ctx: => String): Boolean = {
    val a1 = op1b + op1o
    val a2 = op2b + op2o

    def warnDiffObj() = if (op1b != op2b) throw new UvmRuntimeException(
      ctx + "Attempt to compare order of irefs in two different objects. lhs: 0x%x+0x%x rhs: 0x%x+0x%x".format(
        op1b, op1o, op2b, op2o))

    op match {
      case CmpOptr.EQ  => a1 == a2
      case CmpOptr.NE  => a1 != a2
      case CmpOptr.ULT => { warnDiffObj(); a1 < a2 }
      case CmpOptr.ULE => { warnDiffObj(); a1 <= a2 }
      case CmpOptr.UGT => { warnDiffObj(); a1 > a2 }
      case CmpOptr.UGE => { warnDiffObj(); a1 >= a2 }
      case _           => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for iref.".format(op))
    }
  }

  def objCmp[T <: AnyRef](op: CmpOptr.CmpOptr, obj1: T, obj2: T, kind: String, ctx: => String): Boolean = {
    op match {
      case CmpOptr.EQ => obj1 eq obj2
      case CmpOptr.NE => obj1 ne obj2
      case _          => throw new UvmRuntimeException(ctx + "Comparison operator %s is not suitable for %s.".format(op, kind))
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
423
}
Kunshan Wang's avatar
Kunshan Wang committed
424

425
object MemoryOperations {
426 427 428 429 430 431 432 433 434

  def addressOf(ptr: Boolean, vb: ValueBox): Word = {
    if (ptr) {
      vb.asInstanceOf[BoxPointer].addr
    } else {
      val lb = vb.asInstanceOf[BoxIRef]
      lb.objRef + lb.offset
    }
  }
435

436 437 438
  @inline
  private def noAccessViaPointer(ptr: Boolean, ty: Type)(implicit microVM: MicroVM) {
    if (microVM.enforceRefTypeNoPointerAccess && ptr) {
439 440 441 442 443
      throw new UvmIllegalMemoryAccessException("Cannot access type %s via pointer".format(ty.repr))
    }
  }

  def load(ptr: Boolean, ty: Type, loc: Word, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
444 445
    def loadScalar(ty: Type, loc: Word, br: ValueBox): Unit = {
      def loadEntity[T: CanBeIntegerized](): Unit = {
446
        noAccessViaPointer(ptr, ty)
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
        val obj = memorySupport.loadEntity[T](loc)
        br.asInstanceOf[BoxOpaque[T]].obj = obj
      }
      ty match {
        case TypeInt(l) =>
          val bi: BigInt = l match {
            case 8  => memorySupport.loadByte(loc, !ptr)
            case 16 => memorySupport.loadShort(loc, !ptr)
            case 32 => memorySupport.loadInt(loc, !ptr)
            case 64 => memorySupport.loadLong(loc, !ptr)
            case 128 => {
              val lowWord = memorySupport.loadLong(loc, !ptr)
              val highWord = memorySupport.loadLong(loc + 8, !ptr)
              (BigInt(highWord) << 64) + lowWord
            }
            case _ => throw new UvmUnimplementedOperationException(
Kunshan Wang's avatar
Kunshan Wang committed
463
              "Loading int of length %d is not supported".format(l))
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
          }
          br.asInstanceOf[BoxInt].value = OpHelper.unprepare(bi, l)
        case _: TypeFloat =>
          val fv = memorySupport.loadFloat(loc, !ptr)
          br.asInstanceOf[BoxFloat].value = fv
        case _: TypeDouble =>
          val dv = memorySupport.loadDouble(loc, !ptr)
          br.asInstanceOf[BoxDouble].value = dv
        case _: AbstractPointerType =>
          val addr = memorySupport.loadLong(loc, !ptr)
          br.asInstanceOf[BoxPointer].addr = addr
        case _: TypeRef =>
          noAccessViaPointer(ptr, ty)
          val addr = memorySupport.loadLong(loc)
          br.asInstanceOf[BoxRef].objRef = addr
        case _: TypeIRef =>
          noAccessViaPointer(ptr, ty)
          val base = memorySupport.loadLong(loc)
          val offset = memorySupport.loadLong(loc + WORD_SIZE_BYTES)
          br.asInstanceOf[BoxIRef].oo = (base, offset)
        case _: TypeTagRef64 =>
          noAccessViaPointer(ptr, ty)
          val raw = memorySupport.loadLong(loc)
          br.asInstanceOf[BoxTagRef64].raw = raw
        case _: TypeFuncRef        => loadEntity[Function]()
        case _: TypeThreadRef      => loadEntity[InterpreterThread]()
        case _: TypeStackRef       => loadEntity[InterpreterStack]()
        case _: TypeFrameCursorRef => loadEntity[FrameCursor]()
        case _: TypeIRBuilderRef   => loadEntity[IRBuilder]()
Kunshan Wang's avatar
Kunshan Wang committed
493 494
        case _ => throw new UvmUnimplementedOperationException(
          "Loading of type %s is not supported".format(ty.getClass.getName))
Kunshan Wang's avatar
Kunshan Wang committed
495
      }
496 497 498 499
    }

    ty match {
      case TypeVector(ety, len) =>
Kunshan Wang's avatar
Kunshan Wang committed
500
        val brs = br.asInstanceOf[BoxSeq].values
501 502 503 504 505 506 507 508
        val elemSkip = alignUp(sizeOf(ety), alignOf(ety))
        for ((brElem, i) <- brs.zipWithIndex) {
          loadScalar(ety, loc + elemSkip * i, brElem)
        }
      case sty => loadScalar(sty, loc, br)
    }
  }

509
  def store(ptr: Boolean, ty: Type, loc: Word, nvb: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
510 511
    def storeScalar(ty: Type, loc: Word, nvb: ValueBox): Unit = {
      def storeEntity[T: CanBeIntegerized](): Unit = {
512
        noAccessViaPointer(ptr, ty)
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
        val obj = nvb.asInstanceOf[BoxOpaque[T]].obj
        memorySupport.storeEntity[T](loc, obj)
      }
      ty match {
        case TypeInt(l) =>
          val bi = nvb.asInstanceOf[BoxInt].value
          l match {
            case 8  => memorySupport.storeByte(loc, bi.byteValue, !ptr)
            case 16 => memorySupport.storeShort(loc, bi.shortValue, !ptr)
            case 32 => memorySupport.storeInt(loc, bi.intValue, !ptr)
            case 64 => memorySupport.storeLong(loc, bi.longValue, !ptr)
            case 128 => {
              memorySupport.storeLong(loc, (bi & 0xffffffffffffffffL).longValue, !ptr)
              memorySupport.storeLong(loc + 8, (bi >> 64).longValue, !ptr)
            }
            case _ => throw new UvmUnimplementedOperationException(
Kunshan Wang's avatar
Kunshan Wang committed
529
              "Storing int of length %d is not supported".format(l))
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
          }
        case _: TypeFloat =>
          val fv = nvb.asInstanceOf[BoxFloat].value
          memorySupport.storeFloat(loc, fv, !ptr)
        case _: TypeDouble =>
          val dv = nvb.asInstanceOf[BoxDouble].value
          memorySupport.storeDouble(loc, dv, !ptr)
        case _: AbstractPointerType =>
          val addr = nvb.asInstanceOf[BoxPointer].addr
          memorySupport.storeLong(loc, addr, !ptr)
        case _: TypeRef =>
          noAccessViaPointer(ptr, ty)
          val addr = nvb.asInstanceOf[BoxRef].objRef
          memorySupport.storeLong(loc, addr)
        case _: TypeIRef =>
          noAccessViaPointer(ptr, ty)
          val BoxIRef(base, offset) = nvb.asInstanceOf[BoxIRef]
          memorySupport.storeLong(loc, base)
          memorySupport.storeLong(loc + WORD_SIZE_BYTES, offset)
        case _: TypeTagRef64 =>
          noAccessViaPointer(ptr, ty)
          val raw = nvb.asInstanceOf[BoxTagRef64].raw
          memorySupport.storeLong(loc, raw)
        case _: TypeFuncRef        => storeEntity[Function]()
        case _: TypeThreadRef      => storeEntity[InterpreterThread]()
        case _: TypeStackRef       => storeEntity[InterpreterStack]()
        case _: TypeFrameCursorRef => storeEntity[FrameCursor]()
        case _: TypeIRBuilderRef   => storeEntity[IRBuilder]()
Kunshan Wang's avatar
Kunshan Wang committed
558 559
        case _ => throw new UvmUnimplementedOperationException(
          "Storing of type %s is not supported".format(ty.getClass.getName))
Kunshan Wang's avatar
Kunshan Wang committed
560
      }
561 562 563 564
    }

    ty match {
      case TypeVector(ety, len) =>
Kunshan Wang's avatar
Kunshan Wang committed
565
        val nvbs = nvb.asInstanceOf[BoxSeq].values
566
        val elemSkip = alignUp(sizeOf(ety), alignOf(ety))
Kunshan Wang's avatar
Kunshan Wang committed
567 568
        for ((nvbElem, i) <- nvbs.zipWithIndex) {
          storeScalar(ety, loc + elemSkip * i, nvbElem)
569
        }
Kunshan Wang's avatar
Kunshan Wang committed
570
      case sty => storeScalar(sty, loc, nvb)
571 572 573 574 575 576
    }
  }

  /**
   * Compare exchange. The result (the old value) is written into br. Return true if successful, false otherwise.
   */
577
  def cmpXchg(ptr: Boolean, ty: Type, loc: Word, eb: ValueBox, db: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Boolean = {
578 579 580 581 582 583 584 585
    def cmpXchgEntity[T: CanBeIntegerized](): Boolean = {
      noAccessViaPointer(ptr, ty)
      val eObj = eb.asInstanceOf[BoxOpaque[T]].obj
      val dObj = db.asInstanceOf[BoxOpaque[T]].obj
      val (succ, rObj) = memorySupport.cmpXchgEntity(loc, eObj, dObj)
      br.asInstanceOf[BoxOpaque[T]].obj = rObj
      succ
    }
586 587 588 589 590 591
    ty match {
      case TypeInt(l) =>
        val ebi = eb.asInstanceOf[BoxInt].value
        val dbi = db.asInstanceOf[BoxInt].value
        val (succ, rbi) = l match {
          case 32 => {
592
            val (succ2, rv) = memorySupport.cmpXchgInt(loc, ebi.intValue, dbi.intValue, !ptr)
593 594 595
            (succ2, BigInt(rv))
          }
          case 64 => {
596
            val (succ2, rv) = memorySupport.cmpXchgLong(loc, ebi.longValue, dbi.longValue, !ptr)
597 598
            (succ2, BigInt(rv))
          }
599
          case _ => throw new UvmUnimplementedOperationException("CmpXchg on int of length %d is not supported".format(l))
600 601 602
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(rbi, l)
        succ
603 604 605 606 607 608
      case _: AbstractPointerType =>
        val el = eb.asInstanceOf[BoxPointer].addr
        val dl = db.asInstanceOf[BoxPointer].addr
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl, !ptr)
        br.asInstanceOf[BoxPointer].addr = rl
        succ
609
      case _: TypeRef =>
610
        noAccessViaPointer(ptr, ty)
611 612
        val el = eb.asInstanceOf[BoxRef].objRef
        val dl = db.asInstanceOf[BoxRef].objRef
613
        val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
614 615 616
        br.asInstanceOf[BoxRef].objRef = rl
        succ
      case _: TypeIRef =>
617
        noAccessViaPointer(ptr, ty)
618 619
        val BoxIRef(el, eh) = eb.asInstanceOf[BoxIRef]
        val BoxIRef(dl, dh) = db.asInstanceOf[BoxIRef]
620
        val (succ, (rl, rh)) = memorySupport.cmpXchgI128(loc, (el, eh), (dl, dh))
621 622
        br.asInstanceOf[BoxIRef].oo = (rl, rh)
        succ
623 624 625 626 627 628 629
      case _: TypeFuncRef        => cmpXchgEntity[Function]()
      case _: TypeThreadRef      => cmpXchgEntity[InterpreterThread]()
      case _: TypeStackRef       => cmpXchgEntity[InterpreterStack]()
      case _: TypeFrameCursorRef => cmpXchgEntity[FrameCursor]()
      case _: TypeIRBuilderRef   => cmpXchgEntity[IRBuilder]()
      case _ => throw new UvmUnimplementedOperationException(
        "CmpXchg of type %s is not suppored".format(ty.getClass.getName))
630 631 632
    }
  }

633
  def atomicRMW(ptr: Boolean, ty: Type, op: AtomicRMWOptr, loc: Word, ob: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
634 635 636 637
    ty match {
      case TypeInt(l) =>
        val obi = ob.asInstanceOf[BoxInt].value
        val rbi: BigInt = l match {
638 639
          case 32 => memorySupport.atomicRMWInt(op, loc, obi.intValue, !ptr)
          case 64 => memorySupport.atomicRMWLong(op, loc, obi.longValue, !ptr)
640
          case _  => throw new UvmUnimplementedOperationException("AtomicRMW on int of length %d is not supported".format(l))
641 642 643 644
        }
        br.asInstanceOf[BoxInt].value = OpHelper.unprepare(rbi, l)
      case _ =>
        if (op != XCHG) {
645
          throw new UvmUnimplementedOperationException("AtomicRMW operation other than XCHG only supports int. %s found.".format(ty.getClass.getName))
646
        } else {
647 648 649 650 651 652
          def xchgEntity[T: CanBeIntegerized](): Unit = {
            noAccessViaPointer(ptr, ty)
            val obj = ob.asInstanceOf[BoxOpaque[T]].obj
            val oldObj = memorySupport.xchgEntity(loc, obj)
            br.asInstanceOf[BoxOpaque[T]].obj = oldObj
          }
653
          ty match {
654 655 656 657
            case _: AbstractPointerType =>
              val ol = ob.asInstanceOf[BoxPointer].addr
              val rl = memorySupport.atomicRMWLong(op, loc, ol, !ptr)
              br.asInstanceOf[BoxPointer].addr = rl
658
            case _: TypeRef =>
659
              noAccessViaPointer(ptr, ty)
660
              val ol = ob.asInstanceOf[BoxRef].objRef
661
              val rl = memorySupport.atomicRMWLong(op, loc, ol)
662 663
              br.asInstanceOf[BoxRef].objRef = rl
            case _: TypeIRef =>
664
              noAccessViaPointer(ptr, ty)
665
              val BoxIRef(ol, oh) = ob.asInstanceOf[BoxIRef]
666
              val (rl, rh) = memorySupport.xchgI128(loc, (ol, oh))
667
              br.asInstanceOf[BoxIRef].oo = (rl, rh)
668 669 670 671 672
            case _: TypeFuncRef        => xchgEntity[Function]()
            case _: TypeThreadRef      => xchgEntity[InterpreterThread]()
            case _: TypeStackRef       => xchgEntity[InterpreterStack]()
            case _: TypeFrameCursorRef => xchgEntity[FrameCursor]()
            case _: TypeIRBuilderRef   => xchgEntity[IRBuilder]()
673
            case _ =>
674
              throw new UvmUnimplementedOperationException("AtomicRMW XCHG of type %s is not supporing".format(ty.getClass.getName))
675 676 677
          }
        }
    }
Kunshan Wang's avatar
Kunshan Wang committed
678
  }
Kunshan Wang's avatar
Kunshan Wang committed
679 680 681 682

  /**
   * Check if a memory location still holds a particular value. Used by futex.
   */
683
  def cmpInt(len: Int, loc: Word, expected: BigInt)(implicit memorySupport: MemorySupport): Boolean = len match {
Kunshan Wang's avatar
Kunshan Wang committed
684
    case 64 => {
685
      val expNum = OpHelper.prepareSigned(expected, len).longValue
686
      val actualNum = memorySupport.loadLong(loc)
Kunshan Wang's avatar
Kunshan Wang committed
687 688 689
      expNum == actualNum
    }
    case 32 => {
690
      val expNum = OpHelper.prepareSigned(expected, len).intValue
691
      val actualNum = memorySupport.loadInt(loc)
Kunshan Wang's avatar
Kunshan Wang committed
692 693
      expNum == actualNum
    }
694
    case _ => throw new UvmUnimplementedOperationException("Futex of %d bit int is not supported".format(len))
Kunshan Wang's avatar
Kunshan Wang committed
695
  }
696 697 698 699 700 701 702 703 704 705 706 707

  val US_ASCII = Charset.forName("US-ASCII")

  /**
   * Read an ASCII string from the memory.
   *
   * @param loc A ref to a @uvm.meta.bytes object.
   */
  def bytesToStr(loc: Word)(implicit memorySupport: MemorySupport): String = {
    // It is a hybrid<@i64 @i8> object. The length is determined by the fixed part. 
    val len = memorySupport.loadLong(loc)
    val bytes = new Array[Byte](len.toInt)
708
    val begin = loc + WORD_SIZE_BYTES
709 710 711 712 713 714 715 716 717 718 719
    memorySupport.loadBytes(begin, bytes, 0, len, true)

    val result = new String(bytes, US_ASCII)
    result
  }

  /**
   * Create a Mu @uvm.meta.bytes object to hold an ASCII string.
   *
   * @return The address of the allocated object.
   */
720
  def strToBytes(str: String)(implicit microVM: MicroVM, memorySupport: MemorySupport, mutator: Mutator): Word = {
721 722
    val bytes = str.getBytes(US_ASCII)
    val len = bytes.length
723
    val loc = mutator.newHybrid(microVM.staticAnalyzer.predefinedEntities.BYTES, len)
724
    memorySupport.storeLong(loc, bytes.length.toLong)
725
    val begin = loc + WORD_SIZE_BYTES
726
    memorySupport.storeBytes(begin, bytes, 0, len, true)
727

728 729
    loc
  }
Kunshan Wang's avatar
Kunshan Wang committed
730

731 732 733
  /**
   * Load irnoderef value from the memory. Use fake value from microVM.irNodeRegistry
   */
Kunshan Wang's avatar
Kunshan Wang committed
734 735
  def loadIRBuilder(loc: Word)(implicit microVM: MicroVM, memorySupport: MemorySupport): Option[IRBuilder] = {
    memorySupport.loadEntity[IRBuilder](loc)
736 737 738 739 740
  }

  /**
   * Store irnoderef value into the memory. Use fake value from microVM.irNodeRegistry
   */
Kunshan Wang's avatar
Kunshan Wang committed
741 742
  def storeIRBuilder(loc: Word, maybeIRBuilder: Option[IRBuilder])(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
    memorySupport.storeEntity(loc, maybeIRBuilder)
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
  }

  def loadInt32Array(base: Word, len: Word)(implicit memorySupport: MemorySupport): IndexedSeq[Int] = {
    if (base == 0L) {
      IndexedSeq[Int]()
    } else {
      for (i <- 0L until len) yield {
        val addr = base + i * 4L
        val v = memorySupport.loadInt(addr)
        v
      }
    }
  }

  def loadInt64Array(base: Word, len: Word)(implicit memorySupport: MemorySupport): IndexedSeq[Long] = {
    if (base == 0L) {
      IndexedSeq[Long]()
    } else {
      for (i <- 0L until len) yield {
Kunshan Wang's avatar
Kunshan Wang committed
762
        val addr = base + i * 8L
763 764 765 766 767
        val v = memorySupport.loadLong(addr)
        v
      }
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
768 769
}