Skip to content

Commit

Permalink
[unboxing] Fix bugs with enum sets (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer authored Nov 20, 2024
1 parent 55de933 commit d47da35
Show file tree
Hide file tree
Showing 17 changed files with 437 additions and 3 deletions.
9 changes: 8 additions & 1 deletion aeneas/src/ir/Normalization.v3
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ class NormalizerConfig {
if (maxr < MaxReturnValues) MaxReturnValues = maxr;
}
}
def getB32Or64(width: byte) -> Scalar.set {
return if(width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64);
}
def defaultGetScalar(compiler: Compiler, prog: Program, t: Type) -> Scalar.set {
match (t) {
x: IntType => return if(x.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: EnumType => return getB32Or64(x.enumDecl.tagType.width);
x: EnumSetType => return getB32Or64(x.repType.width);
x: IntType => return getB32Or64(x.width);
x: FloatType => return if(x.is64, Scalar.F64, Scalar.F32);
x: BoolType => return Scalar.B32 | Scalar.B64;
_ => return Scalar.Ref;
Expand All @@ -35,6 +40,8 @@ def defaultGetScalar(compiler: Compiler, prog: Program, t: Type) -> Scalar.set {
def defaultGetBitWidth(compiler: Compiler, prog: Program, t: Type) -> byte {
var target = compiler.target;
match (t) {
x: EnumType => return x.enumDecl.tagType.width;
x: EnumSetType => return x.repType.width;
x: IntType => return x.width;
x: FloatType => return x.total_width;
x: BoolType => return 1;
Expand Down
6 changes: 6 additions & 0 deletions aeneas/src/jvm/JvmTarget.v3
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ class JvmTarget extends Target {
match (t) {
x: BoolType => return Scalar.B32 | Scalar.B64;
x: IntType => return if(x.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64);
x: EnumType => {
return Scalar.B32 | Scalar.B64;
}
x: EnumSetType => {
return if(x.repType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64);
}
x: FloatType => return if(x.is64, Scalar.F64, Scalar.F32);
_ => return Scalar.Ref;
}
Expand Down
5 changes: 5 additions & 0 deletions aeneas/src/os/Linux.v3
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ class LinuxTarget extends Target {
match (t) {
x: BoolType => return Scalar.B32 | Scalar.B64;
x: IntType => return if(x.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R64, once packed refs
x: EnumSetType => {
return if(x.repType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R64, once packed refs
}
x: FloatType => return if(x.is64, Scalar.F64 | Scalar.B64, Scalar.F32 | Scalar.B32);
_ => return Scalar.R32;
}
} else {
match (t) {
x: BoolType => return Scalar.B64;
x: EnumType,
x: EnumSetType,
x: IntType => return Scalar.B64; // XXX: Scalar.R64, once packed refs
x: FloatType => return Scalar.F64 | Scalar.B64;
_ => return Scalar.R64;
Expand Down
4 changes: 2 additions & 2 deletions aeneas/src/v3/V3Enum.v3
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class EnumType extends Type {
return names;
}
def byteSize() -> int {
return IntType.!(enumDecl.tagType).byteSize();
return enumDecl.tagType.byteSize();
}
def packedByteSize() -> int {
return IntType.!(enumDecl.tagType).packedByteSize();
return enumDecl.tagType.packedByteSize();
}
}
// The type for user-declared enums' sets.
Expand Down
2 changes: 2 additions & 0 deletions aeneas/src/wasm/WasmTarget.v3
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class WasmTarget extends Target {
private def getScalar(compiler: Compiler, prog: Program, t: Type) -> Scalar.set {
var none: Scalar.set;
match (t) {
x: EnumType => return if(x.enumDecl.tagType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: EnumSetType => return if(x.repType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: BoolType => return Scalar.B32 | Scalar.B64;
x: IntType => return if(x.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R64, once packed refs
x: FloatType => return if(x.is64, Scalar.F64 | Scalar.B64, Scalar.F32 | Scalar.B32);
Expand Down
2 changes: 2 additions & 0 deletions aeneas/src/x86-64/X86_64Darwin.v3
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class X86_64DarwinTarget extends Target {
}
private def getScalar(compiler: Compiler, prog: Program, t: Type) -> Scalar.set {
match (t) {
x: EnumType => return Scalar.B64;
x: EnumSetType => return Scalar.B64;
x: BoolType => return Scalar.B64;
x: IntType => return Scalar.B64; // XXX: Scalar.R64, once packed refs
x: FloatType => return Scalar.F64 | Scalar.B64;
Expand Down
4 changes: 4 additions & 0 deletions aeneas/src/x86/X86Darwin.v3
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class X86DarwinTarget extends Target {
}
private def getScalar(compiler: Compiler, prog: Program, t: Type) -> Scalar.set {
match (t) {
x: EnumType => return if(x.enumDecl.tagType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: EnumSetType => return if(x.repType.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: BoolType => return Scalar.B32 | Scalar.B64;
x: IntType => return if(x.width <= 32, Scalar.B32 | Scalar.B64, Scalar.B64); // XXX: Scalar.R32, once packed refs
x: FloatType => return if(x.is64, Scalar.F64 | Scalar.B64, Scalar.F32 | Scalar.B32);
Expand All @@ -32,6 +34,8 @@ class X86DarwinTarget extends Target {
private def getBitWidth(compiler: Compiler, prog: Program, t: Type) -> byte {
match (t) {
x: BoolType => return 1;
x: EnumSetType => return x.repType.width;
x: EnumType => return x.enumDecl.tagType.width;
x: IntType => return x.width;
x: FloatType => return x.total_width;
_ => return 32;
Expand Down
26 changes: 26 additions & 0 deletions test/variants/unboxed_enum_set00.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf
}

type T(s: E.set) #unboxed {
def intersect(that: T) -> T {
return T(this.s & that.s);
}
}

def mask = T(E.A0 | E.B0 | E.B8);

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T(x).intersect(mask);
var r: int;
for (e in t.s) {
r |= (1 << e.tag);
}
return r;
}
27 changes: 27 additions & 0 deletions test/variants/unboxed_enum_set01.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf,
C0
}

type T(s: E.set) #unboxed {
def intersect(that: T) -> T {
return T(this.s & that.s);
}
}

def mask = T(E.A0 | E.B0 | E.B8);

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T(x).intersect(mask);
var r: int;
for (e in t.s) {
r |= (1 << e.tag);
}
return r;
}
29 changes: 29 additions & 0 deletions test/variants/unboxed_enum_set02.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf,
C0
}

class C { }

type T(c: C, s: E.set) #unboxed {
def intersect(that: T) -> T {
return T(C.new(), this.s & that.s);
}
}

def mask = T(C.new(), E.A0 | E.B0 | E.B8);

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T(C.new(), x).intersect(mask);
var r: int;
for (e in t.s) {
r |= (1 << e.tag);
}
return r;
}
44 changes: 44 additions & 0 deletions test/variants/unboxed_enum_set03.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf,
C0
}

class C { }

type T #unboxed {
case None(c0: C, c1: C);
case Set(c0: C, s: E.set);

def intersect(that: T) -> T {
match (this) {
None => return this;
Set(c0, set0) => match (that) {
None => return that;
Set(_, set1) => return T.Set(c0, set0 & set1);
}
}
}
def set() -> E.set {
return if(T.Set.?(this), T.Set.!(this).s);
}
}



def mask = T.Set(C.new(), E.A0 | E.B0 | E.B8);

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T.Set(C.new(), x).intersect(mask);
if (a == 9999) t = T.None(C.new(), C.new());
var r: int;
for (e in t.set()) {
r |= (1 << e.tag);
}
return r;
}
44 changes: 44 additions & 0 deletions test/variants/unboxed_enum_set04.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf,
C0
}

class C { }

type T #unboxed {
case None(c0: C, c1: C);
case Set(c0: C, s: E.set);

def intersect(that: T) -> T {
match (this) {
None(c0, c1) => return if(c0 == c1, this, this);
Set(c0, set0) => match (that) {
None => return that;
Set(_, set1) => return T.Set(c0, set0 & set1);
}
}
}
def set() -> E.set {
return if(T.Set.?(this), T.Set.!(this).s);
}
}



def mask = T.Set(C.new(), E.A0 | E.B0 | E.B8);

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T.Set(C.new(), x).intersect(mask);
if (a == 9999) t = T.None(C.new(), C.new());
var r: int;
for (e in t.set()) {
r |= (1 << e.tag);
}
return r;
}
51 changes: 51 additions & 0 deletions test/variants/unboxed_enum_set05.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf,
C0
}

class C { }

type T #unboxed {
case None(c0: C);
case Set(s: E.set);

def intersect(that: T) -> T {
match (this) {
None(c0) => return this;
Set(s0) => match (that) {
None => return that;
Set(s1) => return T.Set(s0 & s1);
}
}
}
def set() -> E.set {
return if(T.Set.?(this), T.Set.!(this).s);
}
def bits() -> int {
if (T.None.?(this)) return 0;
var s = T.Set.!(this).s;
var r: int;
for (e in s) r |= (1 << e.tag);
return r;
}
}



def some = [T.Set(E.A0 | E.B0 | E.B8), T.None(C.new())];

def make(a: int) -> E.set {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
return x;
}

def main(a: int) -> int {
var x = make(a);
var t = T.Set(x).intersect(some[0]);
return t.bits();
}
42 changes: 42 additions & 0 deletions test/variants/unboxed_enum_set06.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//@execute 0=0; -1=16842753; 16842753=16842753
enum E {
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, Aa, Ab, Ac, Ad, Ae, Af,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, Ba, Bb, Bc, Bd, Be, Bf
}

class C { }

type T #unboxed {
case None(c0: C, c1: C);
case Set(c0: C, s: E.set);

def intersect(that: T) -> T {
match (this) {
None(c0, c1) => return if(c0 == c1, this, this);
Set(c0, set0) => match (that) {
None => return that;
Set(_, set1) => return T.Set(c0, set0 & set1);
}
}
}
def set() -> E.set {
return if(T.Set.?(this), T.Set.!(this).s);
}
}



def some = [T.Set(C.new(), E.A0 | E.B0 | E.B8), T.None(C.new(), C.new())];

def main(a: int) -> int {
var x: E.set;
for (e in E) {
if ((a & (1 << e.tag)) != 0) x |= e;
}
var t = T.Set(C.new(), x).intersect(some[0]);
var r: int;
for (e in t.set()) {
r |= (1 << e.tag);
}
return r;
}
Loading

0 comments on commit d47da35

Please sign in to comment.