From ff7b5f60cce79cbd99bb098e3f64eb4a6e2af3dd Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 4 Nov 2024 17:45:26 -0500 Subject: [PATCH] [norm] Simplify int normalizations by removing endianness configurability (#295) --- aeneas/src/ir/IntNormalizer.v3 | 27 ++---- aeneas/src/ir/Reachability.v3 | 4 +- aeneas/src/ir/TypeNorm.v3 | 41 +++------ aeneas/src/mach/MachLowering.v3 | 4 +- aeneas/src/main/Version.v3 | 2 +- aeneas/test/IntNormalizerTest.v3 | 142 +++++-------------------------- 6 files changed, 49 insertions(+), 171 deletions(-) diff --git a/aeneas/src/ir/IntNormalizer.v3 b/aeneas/src/ir/IntNormalizer.v3 index 6d3f10685..0d209bb02 100644 --- a/aeneas/src/ir/IntNormalizer.v3 +++ b/aeneas/src/ir/IntNormalizer.v3 @@ -3,7 +3,7 @@ // See LICENSE for details of Apache 2.0 license. // Normalizes integers by scattering/gathering the bits to/from multiple integers. -class IntNormalizer(width: byte, bigEndian: bool) { +class IntNormalizer(width: byte) { def intMask = (1 << width) - 1; def cache = TypeUtil.newTypeMap(); def word = Int.getType(false, width); @@ -18,13 +18,11 @@ class IntNormalizer(width: byte, bigEndian: bool) { var negative = tt.signed && v < 0; for (i < words) { var bits = Int.box(v & intMask); - if (bigEndian) array[index + words - i] = bits; - else array[index + i] = bits; + array[index + i] = bits; v = v >>> width; } if (negative) v = v | -1 << width; - if (bigEndian) array[index] = Int.box(v); - else array[index + words] = Int.box(v); + array[index + words] = Int.box(v); } // Normalize a long value into an array of values. def normLongIntoArray(tt: IntType, v: long, array: Array, index: int) { @@ -34,13 +32,8 @@ class IntNormalizer(width: byte, bigEndian: bool) { } if (width == 32) { var t = Long.split(v), high = Int.box(t.0), low = Int.box(t.1); - if (bigEndian) { - array[index] = high; - array[index + 1] = low; - } else { - array[index] = low; - array[index + 1] = high; - } + array[index] = low; + array[index + 1] = high; return; } // XXX: general case of normalizing a long is ugly and slow! @@ -49,13 +42,11 @@ class IntNormalizer(width: byte, bigEndian: bool) { var negative = tt.signed && v < 0; for (i < words) { var bits = box(v & mask); - if (bigEndian) array[index + words - i] = bits; - else array[index + i] = bits; + array[index + i] = bits; v = v >>> width; } if (negative) v = v | (-1L << width); - if (bigEndian) array[index] = box(v); - else array[index + words] = box(v); + array[index + words] = box(v); } def normType(t: Type) -> IntNorm { if (!IntType.?(t)) return null; @@ -70,9 +61,9 @@ class IntNormalizer(width: byte, bigEndian: bool) { var sub = Array.new(words + 1); for (i < sub.length) sub[i] = word; var bigEnd = Int.getType(oldType.signed, oldType.width - words * width); - sub[if(bigEndian, 0, sub.length - 1)] = bigEnd; + sub[if(false, 0, sub.length - 1)] = bigEnd; var newType = Tuple.newType(Lists.fromArray(sub)); - nt = IntNorm.new(oldType, newType, sub, bigEndian); + nt = IntNorm.new(oldType, newType, sub); cache[oldType] = nt; } return nt; diff --git a/aeneas/src/ir/Reachability.v3 b/aeneas/src/ir/Reachability.v3 index a1f705a2b..13167cd9e 100644 --- a/aeneas/src/ir/Reachability.v3 +++ b/aeneas/src/ir/Reachability.v3 @@ -864,8 +864,8 @@ class VariantComparatorGen(context: SsaContext, root: IrClass, receiver: IrClass } // Globally shareable normalizers. component IntNormalizers { - def I32LE = IntNormalizer.new(32, false); - def I64LE = IntNormalizer.new(64, false); + def I32LE = IntNormalizer.new(32); + def I64LE = IntNormalizer.new(64); } // Reports code that is neither used during initialization nor reachable from main(). class DeadCodeAnalyzer(ra: ReachabilityAnalyzer) { diff --git a/aeneas/src/ir/TypeNorm.v3 b/aeneas/src/ir/TypeNorm.v3 index 97df5bec4..5724a3e14 100644 --- a/aeneas/src/ir/TypeNorm.v3 +++ b/aeneas/src/ir/TypeNorm.v3 @@ -32,53 +32,38 @@ class TypeNorm(oldType: Type, newType: Type, sub: Array) { } // Integer types might be split into multiple words for target machines < 64 bit. class IntNorm extends TypeNorm { - def bigEndian: bool; - new(oldType: Type, newType: Type, sub: Array, bigEndian) + new(oldType: Type, newType: Type, sub: Array) super(oldType, newType, sub) { } def bigEndIndex() -> int { - return if(bigEndian, 0, size - 1); + return if(false, 0, size - 1); } def littleEndIndex() -> int { - return if(bigEndian, size - 1, 0); + return if(false, size - 1, 0); } // Select {n} items from {input} corresponding to the low-order words. def getLowestN(inputs: Array, n: int) -> Array { - if (bigEndian) return Arrays.range(inputs, inputs.length - n, inputs.length); // [big,vN,...,v0] - else return Arrays.range(inputs, 0, n); // [v0,...,vN,big] + return Arrays.range(inputs, 0, n); // [v0,...,vN,big] } // Create a new array of {n} items, copying the low order words from {inputs} and // extending the upper words with {extend}. def growToN(inputs: Array, n: int, extend: T) -> Array { var result = Array.new(n); - if (bigEndian) { - var d = n - 1; - for (i = inputs.length - 1; i >= 0; i--) result[d--] = inputs[i]; - while (d >= 0) result[d--] = extend; - } else { - var d = 0; - for (i = 0; i < size; i++) result[d++] = inputs[i]; - while (d < result.length) result[d++] = extend; - } + var d = 0; + for (i = 0; i < size; i++) result[d++] = inputs[i]; + while (d < result.length) result[d++] = extend; return result; } // Simulate a shift left by {n} words, filling in the vacant entries with {extend}. def shiftLeft(inputs: Array, n: int, extend: T) { - shift(true, inputs, n, extend); + var i = size - 1; + while (i >= n) { inputs[i] = inputs[i - n]; i--; } + while (i >= 0) { inputs[i] = extend; i--; } } // Simulate a shift right by {n} words, filling in the vacant entries with {extend}. def shiftRight(inputs: Array, n: int, extend: T) { - shift(false, inputs, n, extend); - } - def shift(left: bool, inputs: Array, n: int, extend: T) { - if (left == bigEndian) { - var i = 0; - while (i < size - n) { inputs[i] = inputs[i + n]; i++; } - while (i < size) { inputs[i] = extend; i++; } - } else { - var i = size - 1; - while (i >= n) { inputs[i] = inputs[i - n]; i--; } - while (i >= 0) { inputs[i] = extend; i--; } - } + var i = 0; + while (i < size - n) { inputs[i] = inputs[i + n]; i++; } + while (i < size) { inputs[i] = extend; i++; } } } // Arrays of tuples may be represented as a tuple of arrays or mixed elements, or a diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index 3e11923b5..6a06aafde 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -666,7 +666,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo var op = if(i == tn.littleEndIndex(), infixL, infixH)(tt); var i_cmp = apply(i_old.source, op, [i_a, i_b]); var i_eq = apply(i_old.source, tt.opEq(), [i_a, i_b]); - var next = i + if(mach.intNorm.bigEndian, 1, -1); + var next = i + if(false, 1, -1); var i_sub = genIntCmpRec(i_old, tn, ai_new, next, infixH, infixL); var i_and = apply(i_old.source, V3Op.opBoolAnd, [i_eq, i_sub]); return apply(i_old.source, V3Op.opBoolOr, [i_cmp, i_and]); @@ -2121,7 +2121,7 @@ def decomposeByteArrayAccess(mach: MachProgram, config: MachLoweringConfig, fiel var intType = Int.getType(false, width); var tn = mach.intNorm.makeType(intType), sub = tn.sub; var accesses = Array.new(sub.length); - if (mach.intNorm.bigEndian != (fieldOrder == ByteOrder.BIG_ENDIAN)) { + if (fieldOrder == ByteOrder.BIG_ENDIAN) { for (i = sub.length - 1; i >= 0; i--) { var compound = compoundAccess(mach, sub[i], fieldOrder, offset); accesses[i] = compound; diff --git a/aeneas/src/main/Version.v3 b/aeneas/src/main/Version.v3 index b0f415ca0..324bc3f8b 100644 --- a/aeneas/src/main/Version.v3 +++ b/aeneas/src/main/Version.v3 @@ -3,6 +3,6 @@ // Updated by VCS scripts. DO NOT EDIT. component Version { - def version: string = "III-7.1766"; + def version: string = "III-7.1767"; var buildData: string; } diff --git a/aeneas/test/IntNormalizerTest.v3 b/aeneas/test/IntNormalizerTest.v3 index 37fa4ddae..ca9006faa 100644 --- a/aeneas/test/IntNormalizerTest.v3 +++ b/aeneas/test/IntNormalizerTest.v3 @@ -45,21 +45,10 @@ private class IntNormalizerTester(t: Tester) { } def test_32(t: IntNormalizerTester) { - def le_norm = IntNormalizer.new(32, false); - def be_norm = IntNormalizer.new(32, true); + def le_norm = IntNormalizer.new(32); def testType = t.testType; def base = ut(32); - testType(be_norm, [it(1), base], it(33)); - testType(be_norm, [ut(2), base], ut(34)); - testType(be_norm, [it(13), base], it(45)); - testType(be_norm, [ut(6), base], ut(38)); - testType(be_norm, [it(16), base], it(48)); - testType(be_norm, [ut(16), base], ut(48)); - testType(be_norm, [it(31), base], it(63)); - testType(be_norm, [ut(31), base], ut(63)); - testType(be_norm, [it(32), base], it(64)); - testType(be_norm, [ut(32), base], ut(64)); testType(le_norm, [base, it(1)], it(33)); testType(le_norm, [base, ut(2)], ut(34)); @@ -96,9 +85,6 @@ def test_32(t: IntNormalizerTester) { t.i(x, Int.unbox(array[1])); t.i(y, Int.unbox(array[0])); - be_norm.normLongIntoArray(ul, lval, array, 0); - t.i(x, Int.unbox(array[0])); - t.i(y, Int.unbox(array[1])); } } } @@ -107,23 +93,10 @@ def test_32(t: IntNormalizerTester) { def test_16(t: IntNormalizerTester) { - var be_norm = IntNormalizer.new(16, true); - var le_norm = IntNormalizer.new(16, false); + var le_norm = IntNormalizer.new(16); def testType = t.testType; def base = ut(16); - testType(be_norm, [it(16), base], it(32)); - testType(be_norm, [ut(16), base], ut(32)); - testType(be_norm, [it(11), base], it(27)); - testType(be_norm, [ut(11), base], ut(27)); - testType(be_norm, [it(13), base, base], it(45)); - testType(be_norm, [ut(6), base, base], ut(38)); - testType(be_norm, [it(16), base, base], it(48)); - testType(be_norm, [ut(16), base, base], ut(48)); - testType(be_norm, [it(15), base, base, base], it(63)); - testType(be_norm, [ut(15), base, base, base], ut(63)); - testType(be_norm, [it(16), base, base, base], it(64)); - testType(be_norm, [ut(16), base, base, base], ut(64)); testType(le_norm, [base, it(16)], it(32)); testType(le_norm, [base, ut(16)], ut(32)); @@ -158,9 +131,6 @@ def test_16(t: IntNormalizerTester) { for (x in tests) { var array: Array; array = [Bool.TRUE, Bool.TRUE, Bool.TRUE, Bool.TRUE]; - be_norm.normIntIntoArray(nat, x.0, array, 0); - t.i(x.1.0, Int.unbox(array[0])); - t.i(x.1.1, Int.unbox(array[1])); array = [Bool.TRUE, Bool.TRUE, Bool.TRUE, Bool.TRUE]; le_norm.normIntIntoArray(nat, x.0, array, 0); @@ -188,12 +158,6 @@ def test_16(t: IntNormalizerTester) { var ul = ut(64); var array = Array.new(8); for (x in tests64) { - be_norm.normLongIntoArray(ul, x.0, array, 0); - t.i(x.1.0, Int.unbox(array[0])); - t.i(x.1.1, Int.unbox(array[1])); - t.i(x.1.2, Int.unbox(array[2])); - t.i(x.1.3, Int.unbox(array[3])); - le_norm.normLongIntoArray(ul, x.0, array, 0); t.i(x.1.0, Int.unbox(array[3])); t.i(x.1.1, Int.unbox(array[2])); @@ -201,39 +165,15 @@ def test_16(t: IntNormalizerTester) { t.i(x.1.3, Int.unbox(array[0])); } - be_norm.normIntIntoArray(Int.TYPE, -9, array, 0); - t.i(-1, Int.unbox(array[0])); - le_norm.normIntIntoArray(Int.TYPE, -11, array, 0); t.i(-1, Int.unbox(array[1])); } def test_8(t: IntNormalizerTester) { - var be_norm = IntNormalizer.new(8, true); - var le_norm = IntNormalizer.new(8, false); + var le_norm = IntNormalizer.new(8); def testType = t.testType; def base = ut(8); - testType(be_norm, [it(1), base], it(9)); - testType(be_norm, [ut(2), base], ut(10)); - testType(be_norm, [it(7), base], it(15)); - testType(be_norm, [ut(8), base], ut(16)); - testType(be_norm, [it(3), base, base], it(19)); - testType(be_norm, [ut(6), base, base], ut(22)); - testType(be_norm, [it(8), base, base], it(24)); - testType(be_norm, [ut(8), base, base], ut(24)); - testType(be_norm, [it(4), base, base, base], it(28)); - testType(be_norm, [ut(5), base, base, base], ut(29)); - testType(be_norm, [it(6), base, base, base], it(30)); - testType(be_norm, [ut(7), base, base, base], ut(31)); - testType(be_norm, [it(8), base, base, base], it(32)); - testType(be_norm, [ut(8), base, base, base], ut(32)); - testType(be_norm, [ut(7), base, base, base, base], ut(39)); - testType(be_norm, [it(8), base, base, base, base], it(40)); - testType(be_norm, [ut(8), base, base, base, base], ut(40)); - testType(be_norm, [ut(7), base, base, base, base, base, base, base], ut(63)); - testType(be_norm, [it(8), base, base, base, base, base, base, base], it(64)); - testType(be_norm, [ut(8), base, base, base, base, base, base, base], ut(64)); testType(le_norm, [base, it(1)], it(9)); testType(le_norm, [base, ut(2)], ut(10)); @@ -276,11 +216,6 @@ def test_8(t: IntNormalizerTester) { for (x in tests) { var array: Array; array = [Bool.TRUE, Bool.TRUE, Bool.TRUE, Bool.TRUE]; - be_norm.normIntIntoArray(nat, x.0, array, 0); - t.i(x.1.0, Int.unbox(array[0])); - t.i(x.1.1, Int.unbox(array[1])); - t.i(x.1.2, Int.unbox(array[2])); - t.i(x.1.3, Int.unbox(array[3])); array = [Bool.TRUE, Bool.TRUE, Bool.TRUE, Bool.TRUE]; le_norm.normIntIntoArray(nat, x.0, array, 0); @@ -311,16 +246,6 @@ def test_8(t: IntNormalizerTester) { var ul = ut(64); var array = Array.new(8); for (x in tests64) { - be_norm.normLongIntoArray(ul, x.0, array, 0); - t.i(x.1.0, Int.unbox(array[0])); - t.i(x.1.1, Int.unbox(array[1])); - t.i(x.1.2, Int.unbox(array[2])); - t.i(x.1.3, Int.unbox(array[3])); - t.i(x.1.4, Int.unbox(array[4])); - t.i(x.1.5, Int.unbox(array[5])); - t.i(x.1.6, Int.unbox(array[6])); - t.i(x.1.7, Int.unbox(array[7])); - le_norm.normLongIntoArray(ul, x.0, array, 0); t.i(x.1.0, Int.unbox(array[7])); t.i(x.1.1, Int.unbox(array[6])); @@ -332,36 +257,30 @@ def test_8(t: IntNormalizerTester) { t.i(x.1.7, Int.unbox(array[0])); } - be_norm.normIntIntoArray(Int.TYPE, -9, array, 0); - t.i(-1, Int.unbox(array[0])); - le_norm.normIntIntoArray(Int.TYPE, -11, array, 0); t.i(-1, Int.unbox(array[3])); } def test_getNormalType(test: IntNormalizerTester) { - for (bigEndian in [false, true]) { - for (base = 1; base <= Int.MAX_WIDTH; base++) { - var norm = IntNormalizer.new(byte.!(base), bigEndian); - var bt = ut(base); - for (t in [it, ut]) { - for (width = 1; width <= Int.MAX_WIDTH; width++) { - var tt = t(width); - var nt = norm.makeType(tt).newType; - if (width <= base) { - test.t.assert_eq(tt, nt); - continue; - } - test.t.assert_eq(Kind.TUPLE, nt.typeCon.kind); - var types = nt.nested; - if (bigEndian) types = test.testRemainder(tt.signed, width, base, types); - for (w = width; w > base; w = w - base) { - test.t.assert_eq(bt, types.head); - types = types.tail; - } - if (!bigEndian) types = test.testRemainder(tt.signed, width, base, types); - test.t.assert_eq(null, types); + for (base = 1; base <= Int.MAX_WIDTH; base++) { + var norm = IntNormalizer.new(byte.!(base)); + var bt = ut(base); + for (t in [it, ut]) { + for (width = 1; width <= Int.MAX_WIDTH; width++) { + var tt = t(width); + var nt = norm.makeType(tt).newType; + if (width <= base) { + test.t.assert_eq(tt, nt); + continue; } + test.t.assert_eq(Kind.TUPLE, nt.typeCon.kind); + var types = nt.nested; + for (w = width; w > base; w = w - base) { + test.t.assert_eq(bt, types.head); + types = types.tail; + } + types = test.testRemainder(tt.signed, width, base, types); + test.t.assert_eq(null, types); } } } @@ -369,24 +288,7 @@ def test_getNormalType(test: IntNormalizerTester) { def test_shifts(t: IntNormalizerTester) { { - def n4 = IntNormalizer.new(8, true).normType(ut(32)); - var array = [0, 1, 2, 3]; - n4.shiftLeft(array, 1, -1); - t.ai([1, 2, 3, -1], array); - n4.shiftLeft(array, 2, -2); - t.ai([3, -1, -2, -2], array); - n4.shiftLeft(array, 2, -5); - t.ai([-2, -2, -5, -5], array); - - n4.shiftRight(array, 3, 9); - t.ai([9, 9, 9, -2], array); - n4.shiftRight(array, 1, 4); - t.ai([4, 9, 9, 9], array); - n4.shiftRight(array, 2, 5); - t.ai([5, 5, 4, 9], array); - } - { - def n6 = IntNormalizer.new(8, false).normType(ut(48)); + def n6 = IntNormalizer.new(8).normType(ut(48)); var array = [0, 1, 2, 3, 4, 5]; n6.shiftLeft(array, 2, -1); t.ai([-1, -1, 0, 1, 2, 3], array);