Skip to content

Commit

Permalink
Don't allocate Val.Zero for reference types (#683)
Browse files Browse the repository at this point in the history
* Don't allocate Val.Zero for reference types

* Update NIR docs with mention of null value
  • Loading branch information
densh committed May 1, 2017
1 parent caa7adf commit 804df93
Show file tree
Hide file tree
Showing 11 changed files with 33 additions and 16 deletions.
7 changes: 4 additions & 3 deletions docs/contrib/nir.rst
Expand Up @@ -532,13 +532,14 @@ Boolean
Corresponds to LLVM's ``true`` and ``false``.

Zero
````
Zero and null
`````````````
.. code-block:: text
null
zero $type
Corresponds to LLVM's ``zeroinitializer``.
Corresponds to LLVM's ``null`` and ``zeroinitializer``.

Integer
```````
Expand Down
2 changes: 2 additions & 0 deletions nir/src/main/scala/scala/scalanative/nir/Show.scala
Expand Up @@ -368,6 +368,8 @@ object Show {
str("true")
case Val.False =>
str("false")
case Val.Null =>
str("null")
case Val.Zero(ty) =>
str("zero[")
type_(ty)
Expand Down
3 changes: 2 additions & 1 deletion nir/src/main/scala/scala/scalanative/nir/Vals.scala
Expand Up @@ -7,6 +7,7 @@ import java.lang.Double.doubleToRawLongBits
sealed abstract class Val {
final def ty: Type = this match {
case Val.None => Type.None
case Val.Null => Type.Ptr
case Val.Zero(ty) => ty
case Val.Undef(ty) => ty
case Val.True | Val.False => Type.Bool
Expand Down Expand Up @@ -34,6 +35,7 @@ object Val {
final case object None extends Val
final case object True extends Val
final case object False extends Val
final case object Null extends Val
final case class Zero(of: nir.Type) extends Val
final case class Undef(of: nir.Type) extends Val
final case class Byte(value: scala.Byte) extends Val
Expand Down Expand Up @@ -63,7 +65,6 @@ object Val {
final case class Chars(value: java.lang.String) extends Val
final case class Local(name: nir.Local, valty: nir.Type) extends Val
final case class Global(name: nir.Global, valty: nir.Type) extends Val
val Null = Zero(Type.Ptr)
def Bool(bool: Boolean) = if (bool) True else False

// high-level
Expand Down
Expand Up @@ -293,7 +293,7 @@ final class BinaryDeserializer(_buffer: => ByteBuffer) {
case T.NoneVal => Val.None
case T.TrueVal => Val.True
case T.FalseVal => Val.False
case T.ZeroVal => Val.Zero(getType)
case T.ZeroVal => getZero()
case T.UndefVal => Val.Undef(getType)
case T.ByteVal => Val.Byte(get)
case T.ShortVal => Val.Short(getShort)
Expand All @@ -311,4 +311,11 @@ final class BinaryDeserializer(_buffer: => ByteBuffer) {
case T.ConstVal => Val.Const(getVal)
case T.StringVal => Val.String(getString)
}
private def getZero(): Val = {
val ty = getType
ty match {
case Type.Ptr | _: Type.RefKind => Val.Null
case _ => Val.Zero(ty)
}
}
}
Expand Up @@ -424,6 +424,7 @@ final class BinarySerializer(buffer: ByteBuffer) {
case Val.None => putInt(T.NoneVal)
case Val.True => putInt(T.TrueVal)
case Val.False => putInt(T.FalseVal)
case Val.Null => putInt(T.ZeroVal); putType(Type.Ptr)
case Val.Zero(ty) => putInt(T.ZeroVal); putType(ty)
case Val.Undef(ty) => putInt(T.UndefVal); putType(ty)
case Val.Byte(v) => putInt(T.ByteVal); put(v)
Expand Down
Expand Up @@ -250,9 +250,8 @@ abstract class NirCodeGen
for (f <- sym.info.decls if f.isField) {
val ty = genType(f.tpe, box = false)
val name = genFieldName(f)
val rhs = if (sym.isExternModule) Val.None else Val.Zero(ty)

curClassDefns += Defn.Var(attrs, name, ty, rhs)
curClassDefns += Defn.Var(attrs, name, ty, Val.None)
}
}

Expand Down Expand Up @@ -643,7 +642,7 @@ abstract class NirCodeGen
case UnitTag =>
Val.Unit
case NullTag =>
Val.Zero(Rt.Object)
Val.Null
case BooleanTag =>
if (value.booleanValue) Val.True else Val.False
case ByteTag =>
Expand Down Expand Up @@ -1323,11 +1322,11 @@ abstract class NirCodeGen
val comp = if (negated) Comp.Ine else Comp.Ieq
right withOp Op.Comp(comp, Rt.Object, left.value, right.value)
} else {
val isnull = left withOp Op.Comp(Comp.Ieq, Rt.Object, left.value, Val.Zero(Rt.Object))
val isnull = left withOp Op.Comp(Comp.Ieq, Rt.Object, left.value, Val.Null)
val cond = ValTree(isnull.value)
val thenp = ContTree { focus =>
val right = genExpr(rightp, focus)
right withOp Op.Comp(Comp.Ieq, Rt.Object, right.value, Val.Zero(Rt.Object))
right withOp Op.Comp(Comp.Ieq, Rt.Object, right.value, Val.Null)
}
val elsep = ContTree { focus =>
genMethodCall(NObjectEqualsMethod, statically = false,
Expand Down
Expand Up @@ -353,6 +353,7 @@ object CodeGen {
def genJustVal(v: Val): Unit = v match {
case Val.True => str("true")
case Val.False => str("false")
case Val.Null => str("null")
case Val.Zero(ty) => str("zeroinitializer")
case Val.Undef(ty) => str("undef")
case Val.Byte(v) => str(v)
Expand Down
3 changes: 2 additions & 1 deletion tools/src/main/scala/scala/scalanative/nir/parser/Val.scala
Expand Up @@ -12,6 +12,7 @@ object Val extends Base[nir.Val] {
val None = P("none".! map (_ => nir.Val.None))
val True = P("true".! map (_ => nir.Val.True))
val False = P("false".! map (_ => nir.Val.False))
val Null = P("null".! map (_ => nir.Val.Null))
val Zero = P("zero[" ~ Type.parser ~ "]" map (nir.Val.Zero(_)))
val Undef = P("undef[" ~ Type.parser ~ "]" map (nir.Val.Undef(_)))
val Byte = P("byte" ~ Base.Byte map (nir.Val.Byte(_)))
Expand Down Expand Up @@ -48,6 +49,6 @@ object Val extends Base[nir.Val] {
val String = P(stringLit map (nir.Val.String(_)))

override val parser: P[nir.Val] =
None | True | False | Zero | Undef | Long | Int | Short | Byte | Double | Float | NoneStruct | Struct | Array | Chars | Local | Global | Unit | Const | String
None | True | False | Null | Zero | Undef | Long | Int | Short | Byte | Double | Float | NoneStruct | Struct | Array | Chars | Local | Global | Unit | Const | String

}
Expand Up @@ -15,7 +15,7 @@ class IsLowering(implicit fresh: Fresh, top: Top) extends Pass {
import buf._

insts.foreach {
case Let(n, Op.Is(_, Val.Zero(_))) =>
case Let(n, Op.Is(_, Val.Null | Val.Zero(_))) =>
let(n, Op.Copy(Val.False))

case Let(n, Op.Is(ty, obj)) =>
Expand All @@ -24,7 +24,7 @@ class IsLowering(implicit fresh: Fresh, top: Top) extends Pass {
val thenL, elseL, contL = fresh()

// check if obj is null
val isnull = let(Op.Comp(Comp.Ieq, Type.Ptr, obj, Val.Zero(Type.Ptr)))
val isnull = let(Op.Comp(Comp.Ieq, Type.Ptr, obj, Val.Null))
branch(isnull, Next(thenL), Next(elseL))
// in case it's null, result is always false
label(thenL)
Expand Down
Expand Up @@ -47,10 +47,9 @@ class ModuleLowering(implicit top: Top, fresh: Fresh) extends Pass {
case Defn.Module(attrs, clsName @ ClassRef(cls), parent, ifaces) =>
val clsDefn = Defn.Class(attrs, clsName, parent, ifaces)
val clsTy = Type.Class(clsName)
val clsNull = Val.Zero(clsTy)

val valueName = clsName member "value"
val valueDefn = Defn.Var(Attrs.None, valueName, clsTy, clsNull)
val valueDefn = Defn.Var(Attrs.None, valueName, clsTy, Val.Null)
val value = Val.Global(valueName, Type.Ptr)

val entry = fresh()
Expand Down Expand Up @@ -79,7 +78,7 @@ class ModuleLowering(implicit top: Top, fresh: Fresh) extends Pass {
Seq(
Inst.Label(entry, Seq()),
Inst.Let(self.name, Op.Load(clsTy, value)),
Inst.Let(cond.name, Op.Comp(Comp.Ine, Rt.Object, self, clsNull)),
Inst.Let(cond.name, Op.Comp(Comp.Ine, Rt.Object, self, Val.Null)),
Inst.If(cond, Next(existing), Next(initialize)),
Inst.Label(existing, Seq()),
Inst.Ret(self),
Expand Down
Expand Up @@ -27,6 +27,11 @@ class ValParserTest extends FlatSpec with Matchers {
result should be(`false`)
}

it should "parse `Val.Null`" in {
val Parsed.Success(result, _) = parser.Val.Null.parse(Val.Null.show)
result should be(Val.Null)
}

it should "parse `Val.Zero`" in {
val zero: Val = Val.Zero(noTpe)
val Parsed.Success(result, _) = parser.Val.Zero.parse(zero.show)
Expand Down

0 comments on commit 804df93

Please sign in to comment.