From df201406b2e7cd51c74055321c088d4421f75b7a Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Thu, 31 Oct 2024 23:39:31 -0400 Subject: [PATCH] [layouts] Implement #big-endian layouts and fields (#294) --- aeneas/src/core/Eval.v3 | 38 ++--- aeneas/src/core/Opcode.v3 | 12 +- aeneas/src/core/Operator.v3 | 35 ++--- aeneas/src/ir/SsaNormalizer.v3 | 64 +++------ aeneas/src/jvm/SsaJvmGen.v3 | 48 ++++--- aeneas/src/mach/MachLowering.v3 | 242 +++++++++++++++++++++----------- aeneas/src/mach/MachProgram.v3 | 22 +++ aeneas/src/main/Version.v3 | 2 +- aeneas/src/ssa/SsaBuilder.v3 | 8 +- aeneas/src/ssa/VstSsaGen.v3 | 6 +- aeneas/src/v3/Ref.v3 | 51 ++++--- aeneas/src/vst/Parser.v3 | 1 + aeneas/src/vst/Verifier.v3 | 25 ++-- aeneas/src/vst/Vst.v3 | 3 + aeneas/src/vst/VstPrinter.v3 | 20 ++- bin/virgil-mode.el | 1 + doc/aeneas-issues.txt | 10 +- rt/jvm/bin/V3S_System.class | Bin 10805 -> 13825 bytes rt/jvm/src/V3S_System.java | 153 ++++++++++++++++++++ test/layout/big_endian00.v3 | 12 ++ test/layout/big_endian01.v3 | 12 ++ test/layout/big_endian02.v3 | 12 ++ test/layout/big_endian03.v3 | 13 ++ test/layout/big_endian04.v3 | 14 ++ test/layout/big_endian05.v3 | 13 ++ test/layout/big_endian06.v3 | 17 +++ test/layout/big_endian07.v3 | 17 +++ test/layout/big_endian08.v3 | 55 ++++++++ test/layout/big_endian09.v3 | 22 +++ test/layout/big_endian10.v3 | 22 +++ test/layout/big_endian11.v3 | 22 +++ test/layout/big_endian12.v3 | 22 +++ test/layout/big_endian13.v3 | 14 ++ test/layout/big_endian14.v3 | 32 +++++ test/layout/big_endian15.v3 | 32 +++++ test/layout/big_endian16.v3 | 32 +++++ test/layout/big_endian17.v3 | 36 +++++ test/layout/big_endian18.v3 | 36 +++++ test/layout/big_endian19.v3 | 16 +++ test/layout/big_endian20.v3 | 20 +++ test/layout/big_endian21.v3 | 20 +++ test/layout/big_endian22.v3 | 20 +++ test/layout/big_endian23.v3 | 13 ++ test/layout/big_endian24.v3 | 13 ++ test/layout/big_endian25.v3 | 14 ++ test/layout/big_endian26.v3 | 14 ++ test/layout/big_endian27.v3 | 14 ++ test/layout/big_endian28.v3 | 14 ++ test/layout/big_endian29.v3 | 14 ++ test/layout/big_endian30.v3 | 14 ++ test/layout/big_endian31.v3 | 14 ++ test/layout/big_endian32.v3 | 27 ++++ test/layout/big_endian33.v3 | 27 ++++ test/layout/little_endian24.v3 | 13 ++ 54 files changed, 1205 insertions(+), 238 deletions(-) create mode 100644 test/layout/big_endian00.v3 create mode 100644 test/layout/big_endian01.v3 create mode 100644 test/layout/big_endian02.v3 create mode 100644 test/layout/big_endian03.v3 create mode 100644 test/layout/big_endian04.v3 create mode 100644 test/layout/big_endian05.v3 create mode 100644 test/layout/big_endian06.v3 create mode 100644 test/layout/big_endian07.v3 create mode 100644 test/layout/big_endian08.v3 create mode 100644 test/layout/big_endian09.v3 create mode 100644 test/layout/big_endian10.v3 create mode 100644 test/layout/big_endian11.v3 create mode 100644 test/layout/big_endian12.v3 create mode 100644 test/layout/big_endian13.v3 create mode 100644 test/layout/big_endian14.v3 create mode 100644 test/layout/big_endian15.v3 create mode 100644 test/layout/big_endian16.v3 create mode 100644 test/layout/big_endian17.v3 create mode 100644 test/layout/big_endian18.v3 create mode 100644 test/layout/big_endian19.v3 create mode 100644 test/layout/big_endian20.v3 create mode 100644 test/layout/big_endian21.v3 create mode 100644 test/layout/big_endian22.v3 create mode 100644 test/layout/big_endian23.v3 create mode 100644 test/layout/big_endian24.v3 create mode 100644 test/layout/big_endian25.v3 create mode 100644 test/layout/big_endian26.v3 create mode 100644 test/layout/big_endian27.v3 create mode 100644 test/layout/big_endian28.v3 create mode 100644 test/layout/big_endian29.v3 create mode 100644 test/layout/big_endian30.v3 create mode 100644 test/layout/big_endian31.v3 create mode 100644 test/layout/big_endian32.v3 create mode 100644 test/layout/big_endian33.v3 create mode 100644 test/layout/little_endian24.v3 diff --git a/aeneas/src/core/Eval.v3 b/aeneas/src/core/Eval.v3 index 4eb1fc674..571196b0e 100644 --- a/aeneas/src/core/Eval.v3 +++ b/aeneas/src/core/Eval.v3 @@ -863,13 +863,13 @@ def evalOp(op: Operator, args: Arguments) -> Result { if (ref == null) return ByteArrayOffset.new(null, offset); return ByteArrayOffset.new(ref.array, ref.offset + offset); } - RefLayoutGetField(offset) => { + RefLayoutGetField(offset, order) => { var ref = args.ref(0); - return doRefLayoutGetField(args, args.getTypeArg(1), ref, offset); + return doRefLayoutGetField(args, args.getTypeArg(1), ref, offset, order); } - RefLayoutSetField(offset) => { + RefLayoutSetField(offset, order) => { var ref = args.ref(0); - return doRefLayoutSetField(args, args.getTypeArg(1), ref, offset, args.vals[1]); + return doRefLayoutSetField(args, args.getTypeArg(1), ref, offset, order, args.vals[1]); } RefLayoutAtRepeatedField(offset, scale, max) => { var ref = args.ref(0); @@ -879,29 +879,29 @@ def evalOp(op: Operator, args: Arguments) -> Result { if (ref == null) return ByteArrayOffset.new(null, noffset); return ByteArrayOffset.new(ref.array, ref.offset + noffset); } - RefLayoutGetRepeatedField(offset, scale, max) => { + RefLayoutGetRepeatedField(offset, scale, max, order) => { var ref = args.ref(0); var index = args.i(1); if (u32.view(index) >= u32.view(max)) return args.throw(V3Exception.BoundsCheck, null); - return doRefLayoutGetField(args, args.getTypeArg(1), ref, offset + scale * index); + return doRefLayoutGetField(args, args.getTypeArg(1), ref, offset + scale * index, order); } - RefLayoutSetRepeatedField(offset, scale, max) => { + RefLayoutSetRepeatedField(offset, scale, max, order) => { var ref = args.ref(0); var index = args.i(1); if (u32.view(index) >= u32.view(max)) return args.throw(V3Exception.BoundsCheck, null); - return doRefLayoutSetField(args, args.getTypeArg(1), ref, offset + scale * index, args.vals[2]); + return doRefLayoutSetField(args, args.getTypeArg(1), ref, offset + scale * index, order, args.vals[2]); } - ByteArrayGetField(offset) => { + ByteArrayGetField(offset, order) => { var array = args.r(0); var i_offset = if(ArrayRangeStart.?(args.vals[1]), ArrayRangeStart.!(args.vals[1]).start, args.i(1)); // XXX: Refactor so no intermediate ByteArrayOffset object needed - return doRefLayoutGetField(args, args.getTypeArg(0), ByteArrayOffset.new(array, offset), i_offset); + return doRefLayoutGetField(args, args.getTypeArg(0), ByteArrayOffset.new(array, offset), i_offset, order); } - ByteArraySetField(offset) => { + ByteArraySetField(offset, order) => { var array = args.r(0); var i_offset = if(ArrayRangeStart.?(args.vals[1]), ArrayRangeStart.!(args.vals[1]).start, args.i(1)); // XXX: Refactor so no intermediate ByteArrayOffset object needed - return doRefLayoutSetField(args, args.getTypeArg(0), ByteArrayOffset.new(array, offset), i_offset, args.vals[2]); + return doRefLayoutSetField(args, args.getTypeArg(0), ByteArrayOffset.new(array, offset), i_offset, order, args.vals[2]); } //---------------------------------------------------------------------------- @@ -929,15 +929,15 @@ def evalOp(op: Operator, args: Arguments) -> Result { return args.throw("EvalUnimplemented", op.opcode.name); } -def doRefLayoutGetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, offset: int) -> Result { +def doRefLayoutGetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, offset: int, order: ByteOrder) -> Result { if (ref == null || ref.array == null) return args.throw(V3Exception.NullCheck, null); match (fieldType) { x: BoolType => { - var v = ref.read(false, offset, 1); + var v = ref.read(order, offset, 1); return Bool.box((v & 1) != 0); } x: IntType => { - var v = ref.read(/*TODO:bigEndian=*/false, offset, x.size); + var v = ref.read(order, offset, x.size); match (x.rank) { SUBI32 => return Int.box(int.view(v) << x.ishift >> x.ishift); SUBU32 => return Int.box(int.view(v) << x.ishift >>> x.ishift); @@ -948,19 +948,19 @@ def doRefLayoutGetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, } } x: EnumType => { - var v = ref.read(false, offset, x.packedByteSize()); + var v = ref.read(order, offset, x.packedByteSize()); if (v >= x.enumDecl.cases.length) v = 0; // out-of-bounds tag => 0 return Int.box(int.view(v)); // TODO: long enum vals? } x: FloatType => { - var v = ref.read(false, offset, x.byteSize()); + var v = ref.read(order, offset, x.byteSize()); if (x.is64) return Float64Val.new(v); else return Float32Val.new(u32.view(v)); } _ => return args.throw("EvalException", Strings.format1("invalid RefLayoutField type %q", fieldType.render)); } } -def doRefLayoutSetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, offset: int, val: Val) -> Result { +def doRefLayoutSetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, offset: int, order: ByteOrder, val: Val) -> Result { if (ref == null || ref.array == null) return args.throw(V3Exception.NullCheck, null); var size = 0, bits: u64 = 0, signed = false; match (fieldType) { @@ -986,7 +986,7 @@ def doRefLayoutSetField(args: Arguments, fieldType: Type, ref: ByteArrayOffset, v: Float32Val => bits = v.bits; v: Float64Val => bits = v.bits; } - ref.write(false, offset, size, bits); + ref.write(order, offset, size, bits); return Values.BOTTOM; } diff --git a/aeneas/src/core/Opcode.v3 b/aeneas/src/core/Opcode.v3 index c77dd495c..1a089549d 100644 --- a/aeneas/src/core/Opcode.v3 +++ b/aeneas/src/core/Opcode.v3 @@ -132,13 +132,13 @@ type Opcode { case RefLayoutAt; case RefLayoutOf; case RefLayoutIn(offset: int); - case RefLayoutGetField(offset: int); - case RefLayoutSetField(offset: int); + case RefLayoutGetField(offset: int, order: ByteOrder); + case RefLayoutSetField(offset: int, order: ByteOrder); case RefLayoutAtRepeatedField(offset: int, scale: int, max: int); - case RefLayoutGetRepeatedField(offset: int, scale: int, max: int); - case RefLayoutSetRepeatedField(offset: int, scale: int, max: int); - case ByteArrayGetField(offset: int); - case ByteArraySetField(offset: int); + case RefLayoutGetRepeatedField(offset: int, scale: int, max: int, order: ByteOrder); + case RefLayoutSetRepeatedField(offset: int, scale: int, max: int, order: ByteOrder); + case ByteArrayGetField(offset: int, order: ByteOrder); + case ByteArraySetField(offset: int, order: ByteOrder); case ForgeRange; // System operations case SystemCall(syscall: SystemCall); diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 3bbd093c5..a725117ff 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -522,31 +522,31 @@ component V3Op { var at: Array = [refType, result]; return newOp0(Opcode.RefLayoutIn(offset), at, [refType], result); } - def newRefLayoutGetField(refType: RefType, offset: int, fieldType: Type) -> Operator { - return newOp0(Opcode.RefLayoutGetField(offset), [refType, fieldType], [refType], fieldType); + def newRefLayoutGetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { + return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], [refType], fieldType); } - def newRefLayoutSetField(refType: RefType, offset: int, fieldType: Type) -> Operator { + def newRefLayoutSetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { var at = [refType, fieldType]; - return newOp0(Opcode.RefLayoutSetField(offset), at, at, Void.TYPE); + return newOp0(Opcode.RefLayoutSetField(offset, order), at, at, Void.TYPE); } def newRefLayoutAtRepeatedField(refType: RefType, offset: int, scale: int, max: int, result: RefType) -> Operator { var opcode = Opcode.RefLayoutAtRepeatedField(offset, scale, max); return newOp0(opcode, [refType, result], [refType, Int.TYPE], result); } - def newRefLayoutGetRepeatedField(refType: RefType, offset: int, scale: int, max: int, fieldType: Type) -> Operator { - var opcode = Opcode.RefLayoutGetRepeatedField(offset, scale, max); + def newRefLayoutGetRepeatedField(refType: RefType, offset: int, scale: int, max: int, fieldType: Type, order: ByteOrder) -> Operator { + var opcode = Opcode.RefLayoutGetRepeatedField(offset, scale, max, order); return newOp0(opcode, [refType, fieldType], [refType, Int.TYPE], fieldType); } - def newRefLayoutSetRepeatedField(refType: RefType, offset: int, scale: int, max: int, fieldType: Type) -> Operator { - var opcode = Opcode.RefLayoutSetRepeatedField(offset, scale, max); + def newRefLayoutSetRepeatedField(refType: RefType, offset: int, scale: int, max: int, fieldType: Type, order: ByteOrder) -> Operator { + var opcode = Opcode.RefLayoutSetRepeatedField(offset, scale, max, order); return newOp0(opcode, [refType, fieldType], [refType, Int.TYPE, fieldType], Void.TYPE); } - def newByteArrayGetField(offset: int, fieldType: Type, startType: Type) -> Operator { - var opcode = Opcode.ByteArrayGetField(offset); + def newByteArrayGetField(offset: int, fieldType: Type, order: ByteOrder, startType: Type) -> Operator { + var opcode = Opcode.ByteArrayGetField(offset, order); return newOp0(opcode, [fieldType, startType], [V3.arrayByteType, startType], fieldType); } - def newByteArraySetField(offset: int, fieldType: Type, startType: Type) -> Operator { - var opcode = Opcode.ByteArraySetField(offset); + def newByteArraySetField(offset: int, fieldType: Type, order: ByteOrder, startType: Type) -> Operator { + var opcode = Opcode.ByteArraySetField(offset, order); return newOp0(opcode, [fieldType, startType], [V3.arrayByteType, startType, fieldType], Void.TYPE); } //---------------------------------------------------------------------------- @@ -626,10 +626,13 @@ def renderOp(op: Operator, buf: StringBuilder) -> StringBuilder { CallVariantSelector(selector) => rfunc = selector.render; CreateClosure(method) => rfunc = method.render; RefLayoutIn(offset) => rfunc = StringBuilder.putd(_, offset); - RefLayoutGetField(offset) => rfunc = StringBuilder.putd(_, offset); - RefLayoutSetField(offset) => rfunc = StringBuilder.putd(_, offset); - ByteArrayGetField(offset) => rfunc = StringBuilder.putd(_, offset); - ByteArraySetField(offset) => rfunc = StringBuilder.putd(_, offset); + RefLayoutGetField(offset, order) => rfunc = StringBuilder.put2(_, "%d,%s", offset, order.name); + RefLayoutSetField(offset, order) => rfunc = StringBuilder.put2(_, "%d,%s", offset, order.name); + RefLayoutAtRepeatedField(offset, scale, max) => rfunc = StringBuilder.put2(_, "%d,%d", offset, scale); + RefLayoutGetRepeatedField(offset, scale, max, order) => rfunc = StringBuilder.put3(_, "%d,%d,%s", offset, scale, order.name); + RefLayoutSetRepeatedField(offset, scale, max, order) => rfunc = StringBuilder.put3(_, "%d,%d,%s", offset, scale, order.name); + ByteArrayGetField(offset, order) => rfunc = StringBuilder.put2(_, "%d,%s", offset, order.name); + ByteArraySetField(offset, order) => rfunc = StringBuilder.put2(_, "%d,%s", offset, order.name); ConditionalThrow(exception) => rfunc = StringBuilder.puts(_, exception); SystemCall(syscall) => rfunc = StringBuilder.puts(_, syscall.name); VstSugar(op) => rfunc = StringBuilder.puts(_, op.name); diff --git a/aeneas/src/ir/SsaNormalizer.v3 b/aeneas/src/ir/SsaNormalizer.v3 index 95f6e2ff7..9ad7bbccd 100644 --- a/aeneas/src/ir/SsaNormalizer.v3 +++ b/aeneas/src/ir/SsaNormalizer.v3 @@ -392,7 +392,7 @@ class SsaRaNormalizer extends SsaRebuilder { curBlock.opIntAdd(start, newGraph.intConst(offset))); return mapN(i_old, ai_new); } - RefLayoutGetField(offset) => { + RefLayoutGetField(offset, order) => { var an = arrayByteNorm; var fn = normTypeArg(op, 1); var ai_new = genRefs(i_old.inputs); @@ -401,12 +401,12 @@ class SsaRaNormalizer extends SsaRebuilder { var result: SsaInstr; match (fn.oldType) { - x: IntType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, facts, array, start); - x: FloatType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, facts, array, start); + x: IntType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, order, facts, array, start); + x: FloatType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, order, facts, array, start); x: EnumType => { var it = IntType.!(x.enumDecl.tagType); var wt = Int.getType(false, it.byteSize() * 8); - result = curBlock.opByteArrayGetField(wt, rangeStartType, offset, facts, array, start); + result = curBlock.opByteArrayGetField(wt, rangeStartType, offset, order, facts, array, start); var caseCount = newGraph.intConst(x.enumDecl.cases.length); var inBound = curBlock.opIntULt(norm.config.ArrayLengthType, it, result, caseCount); result = curBlock.opIntViewI0(it, wt, result); @@ -416,7 +416,7 @@ class SsaRaNormalizer extends SsaRebuilder { } return map1(i_old, result); } - RefLayoutSetField(offset) => { + RefLayoutSetField(offset, order) => { var fn = normTypeArg(op, 1); var ai_new = genRefs(args); var array = ai_new[0], start = ai_new[1], val = ai_new[2]; @@ -424,17 +424,17 @@ class SsaRaNormalizer extends SsaRebuilder { var result: SsaInstr; match (fn.oldType) { - x: IntType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, facts, array, start, val); - x: FloatType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, facts, array, start, val); + x: IntType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, order, facts, array, start, val); + x: FloatType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, order, facts, array, start, val); x: EnumType => { var it = IntType.!(x.enumDecl.tagType); var wt = Int.getType(false, it.byteSize() * 8); - result = curBlock.opByteArraySetField(wt, rangeStartType, offset, facts, array, start, val); + result = curBlock.opByteArraySetField(wt, rangeStartType, offset, order, facts, array, start, val); } } return map1(i_old, result); } - RefLayoutGetRepeatedField(offset, scale, max) => { + RefLayoutGetRepeatedField(offset, scale, max, order) => { var rn = normTypeArg(op, 0), fn = normTypeArg(op, 1); var ai_new = genRefs(args); var array = ai_new[0], start = ai_new[1], index = ai_new[2]; @@ -450,11 +450,11 @@ class SsaRaNormalizer extends SsaRebuilder { ); var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; match (fn.oldType) { - x: IntType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, facts, array, start); - x: FloatType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, facts, array, start); + x: IntType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, order, facts, array, start); + x: FloatType => result = curBlock.opByteArrayGetField(x, rangeStartType, offset, order, facts, array, start); x: EnumType => { var it = IntType.!(x.enumDecl.tagType); - result = curBlock.opByteArrayGetField(it, rangeStartType, offset, facts, array, start); + result = curBlock.opByteArrayGetField(it, rangeStartType, offset, order, facts, array, start); var caseCount = newGraph.intConst(x.enumDecl.cases.length); var inBound = curBlock.opIntULt(it, it, result, caseCount); result = curBlock.addSelect(it, inBound, result, newGraph.nullConst(it)); @@ -463,7 +463,7 @@ class SsaRaNormalizer extends SsaRebuilder { } return map1(i_old, result); } - RefLayoutSetRepeatedField(offset, scale, max) => { + RefLayoutSetRepeatedField(offset, scale, max, order) => { var rn = normTypeArg(op, 0), fn = normTypeArg(op, 1); var ai_new = genRefs(args); var array = ai_new[0], start = ai_new[1], index = ai_new[2], val = ai_new[3]; @@ -479,11 +479,11 @@ class SsaRaNormalizer extends SsaRebuilder { var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; var result: SsaInstr; match (fn.oldType) { - x: IntType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, facts, array, start, val); - x: FloatType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, facts, array, start, val); + x: IntType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, order, facts, array, start, val); + x: FloatType => result = curBlock.opByteArraySetField(fn.oldType, rangeStartType, offset, order, facts, array, start, val); x: EnumType => { var it = IntType.!(x.enumDecl.tagType); - result = curBlock.opByteArraySetField(it, rangeStartType, offset, facts, array, start, val); + result = curBlock.opByteArraySetField(it, rangeStartType, offset, order, facts, array, start, val); } } return map1(i_old, result); @@ -580,38 +580,6 @@ class SsaRaNormalizer extends SsaRebuilder { } } } - def genArrayByteGetMultiple(i_old: SsaApplyOp, it: IntType, array: SsaInstr, i_offset: SsaInstr, offset: int) -> SsaInstr { - // TODO: little-endian only for now - curBlock.at(i_old.source); - var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; - var size = it.packedByteSize(); - var wt = Int.getType(false, it.byteSize() * 8); // rounded to next power of two for efficient shifting - var result: SsaInstr = newGraph.nullConst(wt); - var indexType = norm.config.RangeStartType; - for (i < size) { - var read = curBlock.opArrayGetElem(V3.arrayByteType, indexType, facts, - array, curBlock.opIntAdd(newGraph.intConst(i + offset), i_offset)); - read = curBlock.opIntViewI0(Byte.TYPE, wt, read); - var shifted = if(i == 0, read, curBlock.addApplyF(wt.opShl(), [read, newGraph.intConst(8 * i)], Facts.O_SAFE_SHIFT)); - result = curBlock.addApplyF(wt.opOr(), [result, shifted], Fact.O_PURE); - facts |= Fact.O_NO_NULL_CHECK; - } - return result; - } - def genArrayByteSetMultiple(i_old: SsaApplyOp, it: IntType, array: SsaInstr, i_offset: SsaInstr, offset: int, val: SsaInstr) { - // TODO: little-endian only for now - curBlock.at(i_old.source); - var size = it.packedByteSize(); - var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; - var indexType = norm.config.RangeStartType; - for (i < size) { - var shifted = curBlock.addApplyF(it.opShr(), [val, newGraph.intConst(8 * i)], Facts.O_SAFE_SHIFT); - var b = curBlock.opIntViewI0(it, Byte.TYPE, shifted); - var write = curBlock.opArraySetElem(array.getType(), indexType, facts, - array, curBlock.opIntAdd(newGraph.intConst(i + offset), i_offset), b); - facts |= Fact.O_NO_NULL_CHECK; - } - } def normDefault(i_old: SsaApplyOp, op: Operator) { // normalize a general operator var newOp = op; diff --git a/aeneas/src/jvm/SsaJvmGen.v3 b/aeneas/src/jvm/SsaJvmGen.v3 index 32490b490..fa66ecbed 100644 --- a/aeneas/src/jvm/SsaJvmGen.v3 +++ b/aeneas/src/jvm/SsaJvmGen.v3 @@ -569,48 +569,52 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC emitThrow(exception); code.patchBranch(b); } - ByteArrayGetField(offset) => { + ByteArrayGetField(offset, order) => { var fieldType = op.typeArgs[0]; code.iconst(offset); match (fieldType) { x: IntType => { + // XXX: do 1 and 2 byte cases inline match (x.packedByteSize()) { 1 => jprog.invokesystem(code, "readBytes1", JvmTypes.SIG_BYTE_ARRAY_INT_INT_BYTE); - 2 => jprog.invokesystem(code, "readBytes2", JvmTypes.SIG_BYTE_ARRAY_INT_INT_SHORT); - 3 => jprog.invokesystem(code, "readBytes3", JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT); - 4 => jprog.invokesystem(code, "readBytes4", JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT); - 5 => jprog.invokesystem(code, "readBytes5", JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); - 6 => jprog.invokesystem(code, "readBytes6", JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); - 7 => jprog.invokesystem(code, "readBytes7", JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); - 8 => jprog.invokesystem(code, "readBytes8", JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); + 2 => jprog.invokesystem(code, appendByteOrder("readBytes2", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_SHORT); + 3 => jprog.invokesystem(code, appendByteOrder("readBytes3", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT); + 4 => jprog.invokesystem(code, appendByteOrder("readBytes4", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT); + 5 => jprog.invokesystem(code, appendByteOrder("readBytes5", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); + 6 => jprog.invokesystem(code, appendByteOrder("readBytes6", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); + 7 => jprog.invokesystem(code, appendByteOrder("readBytes7", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); + 8 => jprog.invokesystem(code, appendByteOrder("readBytes8", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_LONG); } emitIntTrunc(x); } x: FloatType => { - if (x == Float.FLOAT32) jprog.invokesystem(code, "readBytesFloat", JvmTypes.SIG_BYTE_ARRAY_INT_INT_FLOAT); - else jprog.invokesystem(code, "readBytesDouble", JvmTypes.SIG_BYTE_ARRAY_INT_INT_DOUBLE); + // XXX: use setBytes4/8 and inline the Double.fromLongBits + if (x == Float.FLOAT32) jprog.invokesystem(code, appendByteOrder("readBytesFloat", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_FLOAT); + else jprog.invokesystem(code, appendByteOrder("readBytesDouble", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_DOUBLE); } } } - ByteArraySetField(offset) => { + ByteArraySetField(offset, order) => { var fieldType = op.typeArgs[0]; code.iconst(offset); match (fieldType) { x: IntType => { + // XXX: do 1 and 2 byte cases inline match (x.packedByteSize()) { 1 => jprog.invokesystem(code, "setBytes1", JvmTypes.SIG_BYTE_ARRAY_INT_BYTE_INT_VOID); - 2 => jprog.invokesystem(code, "setBytes2", JvmTypes.SIG_BYTE_ARRAY_INT_SHORT_INT_VOID); - 3 => jprog.invokesystem(code, "setBytes3", JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT_VOID); - 4 => jprog.invokesystem(code, "setBytes4", JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT_VOID); - 5 => jprog.invokesystem(code, "setBytes5", JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); - 6 => jprog.invokesystem(code, "setBytes6", JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); - 7 => jprog.invokesystem(code, "setBytes7", JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); - 8 => jprog.invokesystem(code, "setBytes8", JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); + 2 => jprog.invokesystem(code, appendByteOrder("setBytes2", order), JvmTypes.SIG_BYTE_ARRAY_INT_SHORT_INT_VOID); + 3 => jprog.invokesystem(code, appendByteOrder("setBytes3", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT_VOID); + 4 => jprog.invokesystem(code, appendByteOrder("setBytes4", order), JvmTypes.SIG_BYTE_ARRAY_INT_INT_INT_VOID); + 5 => jprog.invokesystem(code, appendByteOrder("setBytes5", order), JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); + 6 => jprog.invokesystem(code, appendByteOrder("setBytes6", order), JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); + 7 => jprog.invokesystem(code, appendByteOrder("setBytes7", order), JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); + 8 => jprog.invokesystem(code, appendByteOrder("setBytes8", order), JvmTypes.SIG_BYTE_ARRAY_INT_LONG_INT_VOID); } } x: FloatType => { - if (x == Float.FLOAT32) jprog.invokesystem(code, "setBytesFloat", JvmTypes.SIG_BYTE_ARRAY_INT_FLOAT_INT_VOID); - else jprog.invokesystem(code, "setBytesDouble", JvmTypes.SIG_BYTE_ARRAY_INT_DOUBLE_INT_VOID); + // XXX: use setBytes4/8 and inline the Double.fromLongBits + if (x == Float.FLOAT32) jprog.invokesystem(code, appendByteOrder("setBytesFloat", order), JvmTypes.SIG_BYTE_ARRAY_INT_FLOAT_INT_VOID); + else jprog.invokesystem(code, appendByteOrder("setBytesDouble", order), JvmTypes.SIG_BYTE_ARRAY_INT_DOUBLE_INT_VOID); } } } @@ -619,6 +623,10 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC } return popped; } + def appendByteOrder(str: string, order: ByteOrder) -> string { + if (order == ByteOrder.BIG_ENDIAN) str = Arrays.concat(str, "_be"); + return str; + } def emitCall(i: SsaApplyOp, methodRef: IrSpec) { var jclass = jprog.jvmClass(methodRef.receiver); if (methodRef.isNew()) { diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index 96f4c3a16..3e11923b5 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -60,6 +60,12 @@ class MachLoweringConfig { if (tt.width < 64) return ArithWidth.Sub64; return ArithWidth.Exactly64; } + def getMinimumArithSize(width: int) -> IntType { + if (Int8Arith && width <= 8) return Int.getType(false, 8); + if (Int16Arith && width <= 16) return Int.getType(false, 16); + if (Int32Arith && width <= 32) return Int.getType(false, 32); + return Int.getType(false, 64); + } } // Helper for normalizing a graph in place. @@ -471,7 +477,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo // identity, except for wide integer types var tn = normIntType(i_old.op.typeArgs[0]); var inputs = normRefs(i_old.inputs); - i_new = wideInputs(i_old.op, tn, inputs, Facts.NONE); + i_new = wideInputs(i_old.op, tn, inputs, Fact.O_PURE); } FloatRoundI(is64) => { var inputs = normRefs(i_old.inputs); @@ -500,8 +506,8 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo NormRangeGetElemElem(index) => return genNormRangeGetElem(i_old, index); NormRangeSetElem => return genNormRangeSetElem(i_old, 0); NormRangeSetElemElem(index) => return genNormRangeSetElem(i_old, index); - ByteArrayGetField(offset) => return genByteArrayGetField(i_old, offset); - ByteArraySetField(offset) => return genByteArraySetField(i_old, offset); + ByteArrayGetField(offset, order) => return genByteArrayGetField(i_old, offset, order); + ByteArraySetField(offset, order) => return genByteArraySetField(i_old, offset, order); ArrayGetElemElem(index) => return genArrayGetElem(i_old, index); ArraySetElemElem(index) => return genArraySetElem(i_old, index); ArrayGetLength => i_new = genArrayGetLength(i_old); @@ -1501,102 +1507,93 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo i_old.kill(); i_old.remove(); } - def genByteArrayGetField(i_old: SsaApplyOp, offset: int) { + def genByteArrayGetField(i_old: SsaApplyOp, offset: int, order: ByteOrder) { var inputs = normRefs(i_old.inputs); - var narr = inputs[0], ni_start = inputs[1]; + var ni_arr = inputs[0], ni_start = inputs[1]; var fieldType = i_old.op.typeArgs[0]; - var narr_start = ptrAdd(narr, ni_start); - var nullity = context.compiler.nullity(i_old, narr_start); - if (!nullity.O_NO_NULL_CHECK && !config.ImplicitNullChecks) genNullCheck0(i_old.source, narr_start); - var offsetConst = context.graph.intConst(offset); - var arrayRep = mach.arrayRep(V3.arrayByteType); - var arrayElemOffset = if(i_old.op.typeArgs[1] == V3Range.START_TYPE, offsetConst, genArrayElemOffset(arrayRep.getElemElemOffset(0), 1, offsetConst)); - var machType = mach.machType(fieldType); - - var base = ptrAdd(narr_start, arrayElemOffset), offset = 0; - if (!IntType.?(machType)) return map1(i_old, ptrLoad(machType, base, offset)); + var base = ptrAdd(ni_arr, ni_start); + var nullity = context.compiler.nullity(i_old, base); + if (!nullity.O_NO_NULL_CHECK && !config.ImplicitNullChecks) genNullCheck0(i_old.source, base); + if (i_old.op.typeArgs[1] != V3Range.START_TYPE) offset += mach.arrayRep(V3.arrayByteType).getElemElemOffset(0); - var tn = mach.intNorm.makeType(IntType.!(machType)); + var memoryOrder = if(mach.data.bigEndian, ByteOrder.BIG_ENDIAN, ByteOrder.LITTLE_ENDIAN); + var t = decomposeByteArrayAccess(mach, config, fieldType, offset, order, memoryOrder), tn = t.0, accesses = t.1; - // Generate full-word loads for all but the last word; TODO: little/big endian - var loads = Array.new(tn.size), last = tn.size - 1; - for (i < last) { - var et = tn.sub[i]; - loads[i] = ptrLoad(et, base, offset); - offset = offset + mach.sizeOf(et); - } - - var et = IntType.!(tn.sub[last]); - if (et.width >= 8 && (et.width & et.width - 1) == 0) { - // common case; last load is a power of two and at least a full byte - loads[last] = ptrLoad(et, base, offset); - } else { - // generate multiple power-of-2 byte loads - var wordType = getMinimumArithSize(et.width); - var etWidth = et.packedByteSize() * 8, read = 0; - for (curWidth = mach.intNorm.width; curWidth >= 8; curWidth >>= 1) { - if ((etWidth & curWidth) != 0) { - var curType = Int.getType(false, curWidth); - var load = ptrLoad(curType, base, offset + (read >> 3)); - if (curType != wordType) load = curBlock.opIntViewI0(curType, wordType, load); - if (read != 0) { - load = apply(i_old.source, wordType.opShl(), [load, context.graph.intConst(read)]); - load = apply(i_old.source, wordType.opOr(), [loads[last], load]); + var ai_results = Array.new(accesses.length); + for (i < accesses.length) { + var a = accesses[i]; + match (a) { + Simple(t, offset) => { + var d = ptrLoad(t, base, offset); + ai_results[i] = d; + } + Compound(t, wordType, datums) => { + var d: SsaInstr, or = wordType.opOr(), shl = wordType.opShl(); + for (datum in datums) { + var l = ptrLoad(datum.t, base, datum.offset); + if (datum.t != wordType) l = curBlock.pure(V3Op.newIntViewI(datum.t, wordType), [l]); + if (datum.shift > 0) l = curBlock.pure(shl, [l, context.graph.intConst(datum.shift)]); + if (d != null) d = curBlock.pure(or, [d, l]); + else d = l; } - loads[last] = load; - read += curWidth; + var op = getAccessViewOp(t, wordType); + if (op != null) d = curBlock.pure(op, [d]); + ai_results[i] = d; } } - // sign-extend or mask off fractional upper bits if necessary - if (et.signed || (et.width & 7) != 0 ) loads[last] = curBlock.opIntViewI0(wordType, et, loads[last]); } - mapN(i_old, loads); + if (tn != null && tn.newType != fieldType) { + var op = getAccessViewOp(fieldType, tn.newType); + if (op != null) ai_results = [wideInputs(op, if(tn.size > 1, tn), ai_results, Fact.O_PURE)]; + } + return mapN(i_old, ai_results); } - def getMinimumArithSize(width: int) -> IntType { - if (config.Int8Arith && width <= 8) return Int.getType(false, 8); - if (config.Int16Arith && width <= 16) return Int.getType(false, 16); - if (config.Int32Arith && width <= 32) return Int.getType(false, 32); - return Int.getType(false, 64); + def getAccessViewOp(fieldType: Type, wordType: Type) -> Operator { + if (fieldType == wordType) return null; + match (fieldType) { + x: IntType => match (wordType) { + y: IntType => return V3Op.newIntViewI(wordType, x); + y: FloatType => return if(y.is64, V3Op.opIntViewF64, V3Op.opIntViewF32); + _ => return null; // TODO + } + x: FloatType => return if(x.is64, V3Op.newFloat64ViewI(wordType), V3Op.newFloat32ViewI(wordType)); + _ => return null; // TODO + } } - def genByteArraySetField(i_old: SsaApplyOp, offset: int) { + def genByteArraySetField(i_old: SsaApplyOp, offset: int, order: ByteOrder) { // TODO: byte order var inputs = normRefs(i_old.inputs); - var narr = inputs[0], ni_start = inputs[1], nvalue = inputs[2]; + var ni_arr = inputs[0], ni_start = inputs[1], vals = Arrays.range(inputs, 2, inputs.length); var fieldType = i_old.op.typeArgs[0]; - var narr_start = ptrAdd(narr, ni_start); - var nullity = context.compiler.nullity(i_old, narr_start); - if (!nullity.O_NO_NULL_CHECK && !config.ImplicitNullChecks) genNullCheck0(i_old.source, narr_start); - var arrayRep = mach.arrayRep(V3.arrayByteType); - var offsetConst = context.graph.intConst(offset); - var arrayElemOffset = if(i_old.op.typeArgs[1] == V3Range.START_TYPE, offsetConst, genArrayElemOffset(arrayRep.getElemElemOffset(0), 1, offsetConst)); - var machType = mach.machType(fieldType); - var base = ptrAdd(narr_start, arrayElemOffset), offset = 0, vals = inputs[2 ...]; + var base = ptrAdd(ni_arr, ni_start); + var nullity = context.compiler.nullity(i_old, base); + if (!nullity.O_NO_NULL_CHECK && !config.ImplicitNullChecks) genNullCheck0(i_old.source, base); + if (i_old.op.typeArgs[1] != V3Range.START_TYPE) offset += mach.arrayRep(V3.arrayByteType).getElemElemOffset(0); - if (!IntType.?(machType)) { - ptrStore(machType, base, offset, vals[0]); - i_old.kill(); - i_old.remove(); - return; - } - - var tn = mach.intNorm.makeType(IntType.!(machType)), last = tn.size - 1; - // Generate full-word stores for all but the last word; TODO: little/big endian - for (i < last) { - var et = tn.sub[i]; - ptrStore(et, base, offset, vals[i]); - offset = offset + mach.sizeOf(et); - } + var memoryOrder = if(mach.data.bigEndian, ByteOrder.BIG_ENDIAN, ByteOrder.LITTLE_ENDIAN); + var t = decomposeByteArrayAccess(mach, config, fieldType, offset, order, memoryOrder), tn = t.0, accesses = t.1; - var et = IntType.!(tn.sub[last]), val = vals[last], op_shr = if(et.signed, et.opSar(), et.opShr()); - var etWidth = et.packedByteSize() * 8; - var stored = 0; - for (curWidth = mach.intNorm.width; curWidth >= 8; curWidth >>= 1) { - // generate multiple power-of-2 byte stores - if ((etWidth & curWidth) != 0) { - var valTruncated = val; - if (stored > 0) valTruncated = apply(i_old.source, op_shr, [val, context.graph.intConst(stored)]); - var curType = Int.getType(et.signed, curWidth); - ptrStore(curType, base, offset + (stored >> 3), valTruncated); - stored += curWidth; + var ai_results = Array.new(accesses.length); + if (tn != null && tn.newType != fieldType) { + var op = getAccessViewOp(tn.oldType, fieldType); + var atn = if(tn.size > 1, tn); + if (op != null) vals = wideOutputs(op, atn, vals, Fact.O_PURE); + } + for (i < accesses.length) { + var a = accesses[i], i_val = vals[i]; + match (a) { + Simple(t, offset) => { + ptrStore(t, base, offset, i_val); + } + Compound(t, wordType, datums) => { + var shr = wordType.opShr(); + if (t != wordType) match (t) { + x: FloatType => i_val = curBlock.pure(if(x.is64, V3Op.opIntViewF64, V3Op.opIntViewF32), [i_val]); + } + for (datum in datums) { + var v = if(datum.shift == 0, i_val, curBlock.pure(shr, [i_val, context.graph.intConst(datum.shift)])); + ptrStore(datum.t, base, datum.offset, v); + } + } } } i_old.kill(); @@ -2081,3 +2078,78 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo return ssa.add(op, [context.graph.nullReceiver(), p_size, i_caller_ip, i_caller_sp], Facts.NONE); } } + +def decomposeByteArrayAccess(mach: MachProgram, config: MachLoweringConfig, fieldType: Type, offset: int, fieldOrder: ByteOrder, memoryOrder: ByteOrder) -> (TypeNorm, Array) { + var machType = mach.machType(fieldType); + + if (fieldOrder == memoryOrder) { + // Common case: byte order match. + if (!IntType.?(machType)) return (null, [Access.Simple(fieldType, offset)]); // non-integer type + + var tn = mach.intNorm.makeType(IntType.!(machType)), sub = tn.sub; + var accesses = Array.new(sub.length); + // Generate full-word loads for all but the last word; TODO: little/big endian normalization + var loads = Array.new(tn.size), last = sub.length - 1; + for (i < last) { + var et = sub[i]; + accesses[i] = Access.Simple(et, offset); // XXX: should not need recursive decomposition + offset = offset + mach.packedSizeOf(et); + } + + var et = IntType.!(sub[last]); + if (et.width >= 8 && (et.width & et.width - 1) == 0) { + // common case; last load is a power of two and at least a full byte + accesses[last] = Access.Simple(et, offset); + } else { + // generate multiple power-of-2 accesses + var vec = Vector.new(); + var wordType = config.getMinimumArithSize(et.width); + var etWidth = et.packedByteSize() * 8, bitPos = 0; + for (curWidth = mach.intNorm.width; curWidth >= 8; curWidth >>= 1) { + if ((etWidth & curWidth) != 0) { + var curType = Int.getType(false, curWidth); + vec.put(AccessDatum(curType, offset + (bitPos >> 3), byte.!(bitPos))); + bitPos += curWidth; + } + } + accesses[last] = Access.Compound(et, wordType, vec.extract()); + } + return (null, accesses); + } else { + // Byte order mismatch. Generate individual byte loads and assemble scalars. + var size = mach.packedSizeOf(machType), width = size * 8; + 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)) { + for (i = sub.length - 1; i >= 0; i--) { + var compound = compoundAccess(mach, sub[i], fieldOrder, offset); + accesses[i] = compound; + offset += compound.wordType.packedByteSize(); + } + } else { + for (i < sub.length) { + var compound = compoundAccess(mach, sub[i], fieldOrder, offset); + accesses[i] = compound; + offset += compound.wordType.packedByteSize(); + } + } + return (tn, accesses); + } +} +def compoundAccess(mach: MachProgram, et: Type, fieldOrder: ByteOrder, offset: int) -> Access.Compound { + var size = mach.packedSizeOf(et), width = size * 8; + var bytes = Array.new(size); + var wordType = Int.getType(false, width); + for (j < size) { + var shift = if(fieldOrder == ByteOrder.LITTLE_ENDIAN, j * 8, width - 8 - j * 8); + bytes[j] = AccessDatum(Byte.TYPE, j + offset, byte.!(shift)); + } + return Access.Compound(et, wordType, bytes); +} + +type Access { + case Simple(t: Type, offset: int); + case Compound(t: Type, wordType: IntType, datums: Array); +} +type AccessDatum(t: Type, offset: int, shift: byte); diff --git a/aeneas/src/mach/MachProgram.v3 b/aeneas/src/mach/MachProgram.v3 index cf1eac0fa..c8b98e7cc 100644 --- a/aeneas/src/mach/MachProgram.v3 +++ b/aeneas/src/mach/MachProgram.v3 @@ -316,6 +316,28 @@ class MachProgram extends TargetProgram { } return unexpectedType(t, 0); } + def packedSizeOf(t: Type) -> int { + match(t.typeCon.kind) { + COMPONENT, + VOID => return 0; + INT => return IntType.!(t).packedByteSize(); + BOOL => return 1; + CLASS, + ARRAY => return refSize; + FLOAT => return FloatType.!(t).total_width >>> 3; + ENUM => return V3.getVariantTagType(t).packedByteSize(); + ENUM_SET => return V3.getEnumSetType(t).packedByteSize(); + VARIANT => { + return if (prog.ir.isEnum(t), V3.getVariantTagType(t).packedByteSize(), refSize); + } + ANYFUNC, + FUNCREF => return code.addressSize; + RANGE_START, + POINTER => return data.addressSize; + _ => ; // TODO + } + return unexpectedType(t, 0); + } def sizeOfRegClass(rcl: RegClass) -> int { match (rcl) { I32, F32 => return 4; diff --git a/aeneas/src/main/Version.v3 b/aeneas/src/main/Version.v3 index a25ccd7ec..b0f415ca0 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.1765"; + def version: string = "III-7.1766"; var buildData: string; } diff --git a/aeneas/src/ssa/SsaBuilder.v3 b/aeneas/src/ssa/SsaBuilder.v3 index 954d465fd..6a7a9b944 100644 --- a/aeneas/src/ssa/SsaBuilder.v3 +++ b/aeneas/src/ssa/SsaBuilder.v3 @@ -608,11 +608,11 @@ class SsaBuilder extends SsaBlockState { def opNormRangeSetElemElem(rangeType: Type, indexType: IntType, elem: int, facts: Fact.set, x: SsaInstr, y: SsaInstr, z: SsaInstr, w: SsaInstr) -> SsaInstr { return add(V3Op.newNormRangeSetElemElem(rangeType, indexType, elem), [x, y, z, w], facts); } - def opByteArrayGetField(fieldType: Type, startType: Type, offset: int, facts: Fact.set, x: SsaInstr, y: SsaInstr) -> SsaInstr { - return add(V3Op.newByteArrayGetField(offset, fieldType, startType), [x, y], facts); + def opByteArrayGetField(fieldType: Type, startType: Type, offset: int, order: ByteOrder, facts: Fact.set, x: SsaInstr, y: SsaInstr) -> SsaInstr { + return add(V3Op.newByteArrayGetField(offset, fieldType, order, startType), [x, y], facts); } - def opByteArraySetField(fieldType: Type, startType: Type, offset: int, facts: Fact.set, x: SsaInstr, y: SsaInstr, z: SsaInstr) -> SsaInstr { - return add(V3Op.newByteArraySetField(offset, fieldType, startType), [x, y, z], facts); + def opByteArraySetField(fieldType: Type, startType: Type, offset: int, order: ByteOrder, facts: Fact.set, x: SsaInstr, y: SsaInstr, z: SsaInstr) -> SsaInstr { + return add(V3Op.newByteArraySetField(offset, fieldType, order, startType), [x, y, z], facts); } private def tryElimBoundsCheck(x: SsaInstr, y: SsaInstr) -> Fact.set { if (SsaConst.?(y)) { diff --git a/aeneas/src/ssa/VstSsaGen.v3 b/aeneas/src/ssa/VstSsaGen.v3 index 2ec5c3e53..92a71406f 100644 --- a/aeneas/src/ssa/VstSsaGen.v3 +++ b/aeneas/src/ssa/VstSsaGen.v3 @@ -701,7 +701,7 @@ class VstSsaGen extends VstVisitor { return env.addOp(op, Facts.NONE); } RefLayoutField(receiver, member) => { - var op = V3Op.newRefLayoutGetField(receiver, member.byteOffset, member.mtref.getType()); + var op = V3Op.newRefLayoutGetField(receiver, member.byteOffset, member.mtref.getType(), member.order); return env.addApplyF(op, [obj], Facts.NONE); } RefLayoutNested(receiver, member) => { @@ -709,7 +709,7 @@ class VstSsaGen extends VstVisitor { return env.addApplyF(op, [obj], Facts.NONE); } LayoutField(receiver, member) => { - var op = V3Op.newRefLayoutGetField(receiver, member.byteOffset, member.mtref.getType()); + var op = V3Op.newRefLayoutGetField(receiver, member.byteOffset, member.mtref.getType(), member.order); return env.addOp(op, Facts.NONE); } LayoutNested(receiver, member) => { @@ -819,7 +819,7 @@ class VstSsaGen extends VstVisitor { env.opComponentSetField(spec, obj, val); } RefLayoutField(receiver, member) => { - var op = V3Op.newRefLayoutSetField(receiver, member.byteOffset, member.mtref.getType()); + var op = V3Op.newRefLayoutSetField(receiver, member.byteOffset, member.mtref.getType(), member.order); return env.addApplyF(op, [obj, val], Facts.NONE); } _ => { diff --git a/aeneas/src/v3/Ref.v3 b/aeneas/src/v3/Ref.v3 index dc238aea9..340f524b1 100644 --- a/aeneas/src/v3/Ref.v3 +++ b/aeneas/src/v3/Ref.v3 @@ -47,37 +47,48 @@ class ByteArrayOffset(array: Record, offset: int) extends Val { return h + offset * 33; } // read {count <= 8} bytes and pack into the result value - def read(bigEndian: bool, offset: int, count: int) -> u64 { + def read(order: ByteOrder, offset: int, count: int) -> u64 { var v = array.values; var r: u64, shift = 0; - if (bigEndian) { - for (i < count) { - var ival = Int.unbox(v[this.offset + offset + i]); - r = (r << 8) | u8.view(ival); + match (order) { + BIG_ENDIAN => { + for (i < count) { + var ival = Int.unbox(v[this.offset + offset + i]); + r = (r << 8) | u8.view(ival); + } } - } else { - for (i < count) { - var ival = Int.unbox(v[this.offset + offset + i]); - r |= (u64.view(u8.view(ival)) << u6.view(shift)); - shift += 8; + LITTLE_ENDIAN => { + for (i < count) { + var ival = Int.unbox(v[this.offset + offset + i]); + r |= (u64.view(u8.view(ival)) << u6.view(shift)); + shift += 8; + } } } return r; } // write {count <= 8} bytes into underlying byte array - def write(bigEndian: bool, offset: int, count: int, val: u64) { + def write(order: ByteOrder, offset: int, count: int, val: u64) { var v = array.values; - if (bigEndian) { - var shift = (count - 1) * 8; - for (i < count) { - v[this.offset + offset + i] = Int.box(byte.view(val >> u6.view(shift))); - shift -= 8; + match (order) { + BIG_ENDIAN => { + var shift = (count - 1) * 8; + for (i < count) { + v[this.offset + offset + i] = Int.box(byte.view(val >> u6.view(shift))); + shift -= 8; + } } - } else { - for (i < count) { - v[this.offset + offset + i] = Int.box(byte.view(val)); - val = val >> 8; + LITTLE_ENDIAN => { + for (i < count) { + v[this.offset + offset + i] = Int.box(byte.view(val)); + val = val >> 8; + } } } } } + +enum ByteOrder { + LITTLE_ENDIAN, + BIG_ENDIAN +} diff --git a/aeneas/src/vst/Parser.v3 b/aeneas/src/vst/Parser.v3 index 6d8f18357..90f9b170b 100644 --- a/aeneas/src/vst/Parser.v3 +++ b/aeneas/src/vst/Parser.v3 @@ -305,6 +305,7 @@ component Parser { if (Strings.equal(name, "boxed")) result = VstRepHint.Boxed; else if (Strings.equal(name, "unboxed")) result = VstRepHint.Unboxed; else if (Strings.equal(name, "packed")) result = VstRepHint.Packed; + else if (Strings.equal(name, "big-endian")) result = VstRepHint.BigEndian; else result = VstRepHint.Other(name); } _ => kwError(p, id.name); diff --git a/aeneas/src/vst/Verifier.v3 b/aeneas/src/vst/Verifier.v3 index 4de2830dd..c55d917aa 100644 --- a/aeneas/src/vst/Verifier.v3 +++ b/aeneas/src/vst/Verifier.v3 @@ -191,15 +191,18 @@ class Verifier(compiler: Compiler, prog: Program) { if (size < 0) cv.errAtExpr(decl.size).set("LayoutDeclError", Strings.format1("invalid layout size %q", decl.size.token.image)); decl.byteSize = size; cv.verify(); - verifyFieldOverlapping(decl); - checkLayoutCycle(decl); - } - def verifyFieldOverlapping(decl: VstLayout) { - var cv = decl.verifier; + // check for overlapping fields and propagate big-endian hint from decl to fields var fields = Vector.new(); + var bigEndian = false; + for (l = decl.repHints; l != null; l = l.tail) { + if (VstRepHint.BigEndian.?(l.head)) bigEndian = true; + } for (l = decl.members; l != null; l = l.tail) { match (l.head) { - x: VstLayoutField => if (x.byteOffset >= 0 && x.mtref.byteSize >= 0) fields.put(x); + x: VstLayoutField => { + if (x.byteOffset >= 0 && x.mtref.byteSize >= 0) fields.put(x); + if (bigEndian) x.order = ByteOrder.BIG_ENDIAN; + } } } var length = fields.length; @@ -208,6 +211,7 @@ class Verifier(compiler: Compiler, prog: Program) { var f = a[i], g = a[i + 1]; if ((f.byteOffset + f.mtref.byteSize) > g.byteOffset) cv.errAtDecl(f).FieldDeclError(Strings.format2("field %q overlaps field %q", f.render, g.render)); } + checkLayoutCycle(decl); } def compareFieldOffset(a: VstLayoutField, b: VstLayoutField) -> bool { return a.byteOffset < b.byteOffset; @@ -676,6 +680,9 @@ class VstCompoundVerifier { _ => errAtToken(decl.mtref.tname.name).FieldDeclError(Strings.format1("expected primitive layout field type, found \"%q\"", t.render)); } } + for (l = decl.repHints; l != null; l = l.tail) { + if (VstRepHint.BigEndian.?(l.head)) decl.order = ByteOrder.BIG_ENDIAN; + } mtref.scale = scale; var size64 = mtref.repeatCount * long.view(scale); if (size64 > int.max) errAtRange(decl.mtref.range()).FieldDeclError(Strings.format2("layout field size of %d exceeds internal limitation of %d", size64, int.max)); @@ -1628,7 +1635,8 @@ class TypeChecker(ERROR: ErrorGen, file: VstFile) extends VstVisitor var mtref = member.mtref; expr.receiver = x.expr; expr.read = AppBinding.Apply(V3Op.newRefLayoutGetRepeatedField( - receiver, member.byteOffset, mtref.scale, mtref.repeatCount, mtref.getType()), + receiver, member.byteOffset, mtref.scale, mtref.repeatCount, mtref.getType(), + member.order), Facts.NONE); visitRepeatedIndex(expr.exprs); return mtref.getType(); @@ -1670,7 +1678,8 @@ class TypeChecker(ERROR: ErrorGen, file: VstFile) extends VstVisitor var mtref = member.mtref; expr.receiver = x.expr; expr.write = AppBinding.Apply(V3Op.newRefLayoutSetRepeatedField( - receiver, member.byteOffset, mtref.scale, mtref.repeatCount, mtref.getType()), + receiver, member.byteOffset, mtref.scale, mtref.repeatCount, mtref.getType(), + member.order), Facts.NONE); visitRepeatedIndex(expr.exprs); return mtref.getType(); diff --git a/aeneas/src/vst/Vst.v3 b/aeneas/src/vst/Vst.v3 index 41cc11d02..02fdc976a 100644 --- a/aeneas/src/vst/Vst.v3 +++ b/aeneas/src/vst/Vst.v3 @@ -186,6 +186,7 @@ class VstLayout extends VstCompound { var readonlyType: Type; new(size, name: Token, params: VstList, members: List, repHints: List) super(false, name, null, params, null, members) { + this.repHints = repHints; } } // Parsed "packing P(): N = 0b..." @@ -212,6 +213,7 @@ class VstLayoutField extends VstMember { def offset: Literal; def mtref: MemoryTypeRef; var byteOffset: int = -1; + var order = ByteOrder.LITTLE_ENDIAN; new (offset, mtref, name: Token, repHints: List) super(false, name) { this.repHints = repHints; @@ -417,6 +419,7 @@ type VstRepHint { case Unboxed; case Packed; case Packing(p: VstList); + case BigEndian; case Other(hint: string); } diff --git a/aeneas/src/vst/VstPrinter.v3 b/aeneas/src/vst/VstPrinter.v3 index f905cf0d1..7c5313ae5 100644 --- a/aeneas/src/vst/VstPrinter.v3 +++ b/aeneas/src/vst/VstPrinter.v3 @@ -10,6 +10,9 @@ class Printer(printer: VstPrinter) { def printComponent(cdecl: VstComponent) { printVstCompound("component ", cdecl); } + def printLayout(p: VstLayout) { + printVstCompound("layout ", p); + } def printVstCompound(kind: string, compound: VstCompound) { Terminal.put(kind); Terminal.put(compound.name()); @@ -27,9 +30,12 @@ class Printer(printer: VstPrinter) { Terminal.put("}\n"); } def printMember(decl: VstMember) { - if (VstField.?(decl)) printField(VstField.!(decl)); - else if (VstNew.?(decl)) printNew(VstNew.!(decl)); - else if (VstMethod.?(decl)) printMethod(VstMethod.!(decl)); + match (decl) { + x: VstField => printField(x); + x: VstNew => printNew(x); + x: VstMethod => printMethod(x); + x: VstLayoutField => printLayoutField(x); + } } def printMethod(mdecl: VstMethod) { space("method "); @@ -73,6 +79,12 @@ class Printer(printer: VstPrinter) { printTypeRef(fdecl.tref); printer.printVstField(fdecl); } + def printLayoutField(fdecl: VstLayoutField) { + Terminal.put1(" +%d ", fdecl.byteOffset); + Terminal.put(fdecl.name()); + Terminal.put1(": %q\n", fdecl.mtref.render); +// printer.printVstField(fdecl); + } def printTypeRef(tref: TypeRef) { if (tref == null) return Terminal.put("null"); var buf = TerminalBuffer.new(); @@ -107,6 +119,7 @@ class Printer(printer: VstPrinter) { Terminal.put("#packing "); printCommaList(p.list, printPackingExpr); } + BigEndian => Terminal.put("#big-endian"); Other(s) => Terminal.put1("#%s", s); } } @@ -190,6 +203,7 @@ class VstPrinter extends VstVisitor { prog.vst.components.apply(p.printComponent); prog.vst.classes.apply(p.printClass); prog.vst.packings.apply(p.printPacking); + prog.vst.layouts.apply(p.printLayout); } def visitIf(stmt: IfStmt, indent: int) { p.enter("IfStmt", indent); diff --git a/bin/virgil-mode.el b/bin/virgil-mode.el index 0e30f1e98..a0bbd458e 100644 --- a/bin/virgil-mode.el +++ b/bin/virgil-mode.el @@ -19,6 +19,7 @@ (,"#unboxed" . font-lock-type-face) (,"#boxed" . font-lock-type-face) (,"#packing" . font-lock-type-face) + (,"#big-endian" . font-lock-type-face) (,virgil-decls-regexp . font-lock-keyword-face) (,virgil-stmts-regexp . font-lock-constant-face) (,virgil-builtins-regexp . font-lock-type-face) diff --git a/doc/aeneas-issues.txt b/doc/aeneas-issues.txt index c56d01d80..3263c0c4c 100644 --- a/doc/aeneas-issues.txt +++ b/doc/aeneas-issues.txt @@ -6,18 +6,17 @@ ______ ______ __ _ ______ ______ ______ _____ ______ ______ _ _ ______ _ x86-64-darwin stable binary -shadow-stack-size=128k * layouts +* make SsaInterpreter default +* implement big-endian layouts -- next rev ------------- - make SsaInterpreter default wasi target stable wasm-linux or wasm-wave target wave/linux implementation only add RiGc roots if program allocates - pre-allocate heap space for RiRuntime args (separate from GC) unify v3c-target-nort and v3c-target-nogc scripts -- bugs ------------- - null replacement for variant case methods polymorphic recursion type inference imprecisions -heap-size=3g @@ -63,8 +62,8 @@ ______ ______ __ _ ______ ______ ______ _____ ______ ______ _ _ ______ _ Inform inlining heuristics Inform stack allocation of heap objects, e.g. region size hotpath/trace for register allocation - Duplication jvm backend for VariantReplaceNull -- language usability sucks ------- + pre-allocate heap space for RiRuntime args (separate from GC) allow specifying the type of an enum tag { enum X(tag: byte) { FOO(3) ... } } stray comma at end of initializer => relax in parser type aliases (type X = int { }) @@ -105,10 +104,11 @@ ______ ______ __ _ ______ ______ ______ _____ ______ ______ _ _ ______ _ better error messages for type errors in array literals error messages for comparing with out-of-range integer literals generate self-executing JAR (shell script with JAR appended) - debugger: list files debugger: allow fuzzy match of files / line immutable arrays -- done ------- +* debugger: list files +* null replacement for variant case methods * add -simple-bodies option * default value for variant case types * wizeng:objdump bug: InternalError: address &HostObject.render[code] not fixed diff --git a/rt/jvm/bin/V3S_System.class b/rt/jvm/bin/V3S_System.class index 443828c72be3a2032211bc86959fb1ac837e1097..b2c77b1756e9f90b0fcd3e2be64958e911bd4266 100644 GIT binary patch literal 13825 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 TXBdsdX9({l2(c5en%MO}5yI3M literal 10805 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 8); + } + + public static void setBytes3_be(byte[] bytes, int offset, int value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 2] = (byte)value; + bytes[fullOffset + 1] = (byte)(value >> 8); + bytes[fullOffset + 0] = (byte)(value >> 16); + } + + public static void setBytes4_be(byte[] bytes, int offset, int value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 3] = (byte)value; + bytes[fullOffset + 2] = (byte)(value >> 8); + bytes[fullOffset + 1] = (byte)(value >> 16); + bytes[fullOffset + 0] = (byte)(value >> 24); + } + + public static void setBytes5_be(byte[] bytes, int offset, long value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 4] = (byte)value; + bytes[fullOffset + 3] = (byte)(value >> 8); + bytes[fullOffset + 2] = (byte)(value >> 16); + bytes[fullOffset + 1] = (byte)(value >> 24); + bytes[fullOffset + 0] = (byte)(value >> 32); + } + + public static void setBytes6_be(byte[] bytes, int offset, long value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 5] = (byte)value; + bytes[fullOffset + 4] = (byte)(value >> 8); + bytes[fullOffset + 2] = (byte)(value >> 16); + bytes[fullOffset + 2] = (byte)(value >> 24); + bytes[fullOffset + 1] = (byte)(value >> 32); + bytes[fullOffset + 0] = (byte)(value >> 40); + } + + public static void setBytes7_be(byte[] bytes, int offset, long value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 6] = (byte)value; + bytes[fullOffset + 5] = (byte)(value >> 8); + bytes[fullOffset + 4] = (byte)(value >> 16); + bytes[fullOffset + 3] = (byte)(value >> 24); + bytes[fullOffset + 2] = (byte)(value >> 32); + bytes[fullOffset + 1] = (byte)(value >> 40); + bytes[fullOffset + 0] = (byte)(value >> 48); + } + + public static void setBytes8_be(byte[] bytes, int offset, long value, int staticOffset) { + int fullOffset = offset + staticOffset; + bytes[fullOffset + 7] = (byte)value; + bytes[fullOffset + 6] = (byte)(value >> 8); + bytes[fullOffset + 5] = (byte)(value >> 16); + bytes[fullOffset + 4] = (byte)(value >> 24); + bytes[fullOffset + 3] = (byte)(value >> 32); + bytes[fullOffset + 2] = (byte)(value >> 40); + bytes[fullOffset + 1] = (byte)(value >> 48); + bytes[fullOffset + 0] = (byte)(value >> 56); + } + + public static void setBytesFloat_be(byte[] bytes, int offset, float value, int staticOffset) { + int bits = Float.floatToRawIntBits(value); + V3S_System.setBytes4_be(bytes, offset, bits, staticOffset); + } + + public static void setBytesDouble_be(byte[] bytes, int offset, double value, int staticOffset) { + long bits = Double.doubleToRawLongBits(value); + V3S_System.setBytes8_be(bytes, offset, bits, staticOffset); + } } diff --git a/test/layout/big_endian00.v3 b/test/layout/big_endian00.v3 new file mode 100644 index 000000000..c2d8be205 --- /dev/null +++ b/test/layout/big_endian00.v3 @@ -0,0 +1,12 @@ +//@execute = 287454020 +layout L { + +0 x: u32 #big-endian; + =4; +} + +def data = [0x11u8, 0x22u8, 0x33u8, 0x44u8]; +def r = Ref.at(data, 0); + +def main() -> u32 { + return r.x; +} diff --git a/test/layout/big_endian01.v3 b/test/layout/big_endian01.v3 new file mode 100644 index 000000000..0162b8cad --- /dev/null +++ b/test/layout/big_endian01.v3 @@ -0,0 +1,12 @@ +//@execute = 287454020 +layout L #big-endian { + +0 x: u32; + =4; +} + +def data = [0x11u8, 0x22u8, 0x33u8, 0x44u8]; +def r = Ref.at(data, 0); + +def main() -> u32 { + return r.x; +} diff --git a/test/layout/big_endian02.v3 b/test/layout/big_endian02.v3 new file mode 100644 index 000000000..abfd9f88e --- /dev/null +++ b/test/layout/big_endian02.v3 @@ -0,0 +1,12 @@ +//@execute = 1432778632 +layout L { + +0 x: u32 #big-endian; + =4; +} + +def data = [0x55u8, 0x66u8, 0x77u8, 0x88u8]; + +def main() -> u32 { + def r = Ref.at(data, 0); + return r.x; +} diff --git a/test/layout/big_endian03.v3 b/test/layout/big_endian03.v3 new file mode 100644 index 000000000..bd89b598a --- /dev/null +++ b/test/layout/big_endian03.v3 @@ -0,0 +1,13 @@ +//@execute 0=0; 1=1; 1000000000=1000000000 +layout L { + +0 x: u32 #big-endian; + =4; +} + +def data = [0x55u8, 0x66u8, 0x77u8, 0x88u8]; + +def main(a: u32) -> u32 { + def r = Ref.at(data, 0); + r.x = a; + return r.x; +} diff --git a/test/layout/big_endian04.v3 b/test/layout/big_endian04.v3 new file mode 100644 index 000000000..3ba094a58 --- /dev/null +++ b/test/layout/big_endian04.v3 @@ -0,0 +1,14 @@ +//@execute 0=0; 1=1; 1000000000=10144256 +layout L { + +0 x: u32 #big-endian; + =4; +} + +def data = [0x55u8, 0x66u8, 0x77u8, 0x88u8]; + +def main(a: u32) -> u32 { + def r = Ref.at(data, 0); + r.x = a; + data[0] = 0; + return r.x; +} diff --git a/test/layout/big_endian05.v3 b/test/layout/big_endian05.v3 new file mode 100644 index 000000000..d91731c89 --- /dev/null +++ b/test/layout/big_endian05.v3 @@ -0,0 +1,13 @@ +//@execute 0=6715272; 1=23492488; 255=-10061944 +layout L { + +0 x: int #big-endian; + =4; +} + +def data = [0x55u8, 0x66u8, 0x77u8, 0x88u8]; + +def main(a: byte) -> int { + def r = Ref.at(data, 0); + data[0] = a; + return r.x; +} diff --git a/test/layout/big_endian06.v3 b/test/layout/big_endian06.v3 new file mode 100644 index 000000000..eeb7ad9a6 --- /dev/null +++ b/test/layout/big_endian06.v3 @@ -0,0 +1,17 @@ +//@execute 0=0; 16909060=16909060 +layout L { + +0 x: u32; + +4 y: u32 #big-endian; + +8 z: u32; + =12; +} + +var data = Array.new(L.size); +var r = Ref.of(data); + +def main(a: u32) -> u32 { + r.x = a ^ 0x11223344; + r.y = a; + r.z = a ^ 0x55667788; + return Ref.y(r); +} diff --git a/test/layout/big_endian07.v3 b/test/layout/big_endian07.v3 new file mode 100644 index 000000000..a8d0011fe --- /dev/null +++ b/test/layout/big_endian07.v3 @@ -0,0 +1,17 @@ +//@execute 0=0; 16909060=772; 39304=39304; 287480200=39304 +layout L { + +0 x: u32; + +4 y: u16 #big-endian; + +8 z: u32; + =12; +} + +var data = Array.new(L.size); +var r = Ref.of(data); + +def main(a: u32) -> u16 { + r.x = a ^ 0x11223344; + r.y = u16.view(a); + r.z = a ^ 0x55667788; + return Ref.y(r); +} diff --git a/test/layout/big_endian08.v3 b/test/layout/big_endian08.v3 new file mode 100644 index 000000000..40e1bd164 --- /dev/null +++ b/test/layout/big_endian08.v3 @@ -0,0 +1,55 @@ +//@execute 0=15; 1=15; 99999999=15; -1719109786=15 +layout L { + +0 x1: u8; + +2 x2: u16; + +4 x4: u32; + +8 x8: u64; + =16; +} +layout B #big-endian { + +0 x1: u8; + +2 x2: u16; + +4 x4: u32; + +8 x8: u64; + =16; +} + +var data = Array.new(L.size); +var rl = Ref.of(data); +var rb = Ref.of(data); + +def main(a: u32) -> u32 { + var x = 0x03001030uL * a; + + rl.x1 = u8.view(x); + rl.x2 = u16.view(x); + rl.x4 = u32.view(x); + rl.x8 = u64.view(x); + + return check(); +} + +def check() -> u32 { + var r = 0u; + if (rl.x1 == rb.x1) r |= 0x1; + if (rl.x2 == bswap2(rb.x2)) r |= 0x2; + if (rl.x4 == bswap4(rb.x4)) r |= 0x4; + if (rl.x8 == bswap8(rb.x8)) r |= 0x8; + return r; +} + +def bswap2(x: u16) -> u16 { + return (x >> 8) | ((x & 0xFFu8) << 8); +} +def bswap4(x: u32) -> u32 { + var b0 = x & 0xFF; + var b1 = (x >> 8) & 0xFF; + var b2 = (x >> 16) & 0xFF; + var b3 = (x >> 24) & 0xFF; + return (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3); +} +def bswap8(x: u64) -> u64 { + var w0 = u32.view(x); + var w1 = u32.view(x >> 32); + return (u64.view(bswap4(w0)) << 32) | bswap4(w1); +} diff --git a/test/layout/big_endian09.v3 b/test/layout/big_endian09.v3 new file mode 100644 index 000000000..594cadfa5 --- /dev/null +++ b/test/layout/big_endian09.v3 @@ -0,0 +1,22 @@ +//@execute 0=2; 1=8; 2=32; 3=128 +layout L { + +0 xs: u16[4] #big-endian; + =8; +} + +def data = Array.new(L.size); +var r = Ref.of(data); + +def main(a: int) -> int { + for (i < data.length) data[i] = 0; + r.xs[a] = 0x11; + return check(data); +} + +def check(data: Array) -> int { + var result = 0; + for (i < data.length) { + if (data[i] != 0) result |= 1 << u5.!(i); + } + return result; +} diff --git a/test/layout/big_endian10.v3 b/test/layout/big_endian10.v3 new file mode 100644 index 000000000..73da746e2 --- /dev/null +++ b/test/layout/big_endian10.v3 @@ -0,0 +1,22 @@ +//@execute 0=1; 1=4; 2=16; 3=64 +layout L { + +0 xs: u16[4] #big-endian; + =8; +} + +def data = Array.new(L.size); +var r = Ref.of(data); + +def main(a: int) -> int { + for (i < data.length) data[i] = 0; + r.xs[a] = 0x1100; + return check(data); +} + +def check(data: Array) -> int { + var result = 0; + for (i < data.length) { + if (data[i] != 0) result |= 1 << u5.!(i); + } + return result; +} diff --git a/test/layout/big_endian11.v3 b/test/layout/big_endian11.v3 new file mode 100644 index 000000000..2afce926e --- /dev/null +++ b/test/layout/big_endian11.v3 @@ -0,0 +1,22 @@ +//@execute 0=4; 1=16; 2=64; 3=256 +layout L { + +2 xs: u16[4] #big-endian; + =10; +} + +def data = Array.new(L.size); +var r = Ref.of(data); + +def main(a: int) -> int { + for (i < data.length) data[i] = 0; + r.xs[a] = 0x1100; + return check(data); +} + +def check(data: Array) -> int { + var result = 0; + for (i < data.length) { + if (data[i] != 0) result |= 1 << u5.!(i); + } + return result; +} diff --git a/test/layout/big_endian12.v3 b/test/layout/big_endian12.v3 new file mode 100644 index 000000000..33b1ca6ac --- /dev/null +++ b/test/layout/big_endian12.v3 @@ -0,0 +1,22 @@ +//@execute (0,0)=0; (0,1)=32; (0,256)=16; (0,65536)=8; (0,16777216)=4 +layout L { + +2 xs: u32[2] #big-endian; + =10; +} + +def data = Array.new(L.size); +var r = Ref.of(data); + +def main(index: int, val: u32) -> int { + for (i < data.length) data[i] = 0; + r.xs[index] = val; + return check(data); +} + +def check(data: Array) -> int { + var result = 0; + for (i < data.length) { + if (data[i] != 0) result |= 1 << u5.!(i); + } + return result; +} diff --git a/test/layout/big_endian13.v3 b/test/layout/big_endian13.v3 new file mode 100644 index 000000000..553b0aa59 --- /dev/null +++ b/test/layout/big_endian13.v3 @@ -0,0 +1,14 @@ +//@execute 0=22; 1=33; 2=!BoundsCheckException +layout F { + +0 g: float #big-endian; + =4; +} + +def bytes: Array = [ 0x11, 0x22, 0x33, 0x44, 0x55 ]; +def main(a: int) -> int { + var r = Ref.at(bytes, a); + var g = r.g; + if (g == float.view(0x11223344)) return 22; + if (g == float.view(0x22334455)) return 33; + return 44; +} diff --git a/test/layout/big_endian14.v3 b/test/layout/big_endian14.v3 new file mode 100644 index 000000000..fcc1be930 --- /dev/null +++ b/test/layout/big_endian14.v3 @@ -0,0 +1,32 @@ +//@execute false=2; true=0 +layout F { + +0 g: float #big-endian; + =4; +} + +def bytes: Array = [ 0x01, 0x02, 0x03, 0x04, 0x05 ]; +var r = Ref.of(bytes); + + +def main(a: bool) -> int { + var f: float = if(a, float.view(0x11223344), float.view(0x77665544)); + r.g = f; + return check(); +} + +def outcomes: Array> = [ + [ 0x11, 0x22, 0x33, 0x44, 0x05 ], + [ 0x44, 0x33, 0x22, 0x11, 0x05 ], + [ 0x77, 0x66, 0x55, 0x44, 0x05 ], + [ 0x44, 0x55, 0x66, 0x77, 0x05 ] +]; + +def check() -> int { + for (i < outcomes.length) { + var expected = outcomes[i]; + var eq = true; + for (j < expected.length) if(expected[j] != bytes[j]) eq = false; + if (eq) return i; + } + return -42; +} \ No newline at end of file diff --git a/test/layout/big_endian15.v3 b/test/layout/big_endian15.v3 new file mode 100644 index 000000000..b0ef56b7f --- /dev/null +++ b/test/layout/big_endian15.v3 @@ -0,0 +1,32 @@ +//@execute false=2; true=0 +layout F { + +0 g: double #big-endian; + =8; +} + +def bytes: Array = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 ]; +var r = Ref.at(bytes, 1); + + +def main(a: bool) -> int { + var f: double = if(a, double.view(0x1122334455667788uL), double.view(0x7766554433221100uL)); + r.g = f; + return check(); +} + +def outcomes: Array> = [ + [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x09 ], + [ 0x00, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x09 ], + [ 0x00, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x09 ], + [ 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x09 ] +]; + +def check() -> int { + for (i < outcomes.length) { + var expected = outcomes[i]; + var eq = true; + for (j < expected.length) if(expected[j] != bytes[j]) eq = false; + if (eq) return i; + } + return -42; +} \ No newline at end of file diff --git a/test/layout/big_endian16.v3 b/test/layout/big_endian16.v3 new file mode 100644 index 000000000..d289c6b20 --- /dev/null +++ b/test/layout/big_endian16.v3 @@ -0,0 +1,32 @@ +//@execute false=2; true=0 +layout F { + +1 g: double #big-endian; + =9; +} + +def bytes: Array = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 ]; +var r = Ref.at(bytes, 0); + + +def main(a: bool) -> int { + var f: double = if(a, double.view(0x1122334455667788uL), double.view(0x7766554433221100uL)); + r.g = f; + return check(); +} + +def outcomes: Array> = [ + [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x09 ], + [ 0x00, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x09 ], + [ 0x00, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x09 ], + [ 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x09 ] +]; + +def check() -> int { + for (i < outcomes.length) { + var expected = outcomes[i]; + var eq = true; + for (j < expected.length) if(expected[j] != bytes[j]) eq = false; + if (eq) return i; + } + return -42; +} \ No newline at end of file diff --git a/test/layout/big_endian17.v3 b/test/layout/big_endian17.v3 new file mode 100644 index 000000000..8a03fbfe6 --- /dev/null +++ b/test/layout/big_endian17.v3 @@ -0,0 +1,36 @@ +//@execute false=2; true=0 +layout F { + +1 g: double[2] #big-endian; + =17; +} + +def bytes: Array = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x66 +]; +var r = Ref.at(bytes, 0); + + +def main(a: bool) -> int { + var f: double = if(a, double.view(0x1122334455667788uL), double.view(0x7766554433221100uL)); + r.g[0] = f; + return check(); +} + +def outcomes: Array> = [ + [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x09 ], + [ 0x00, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x09 ], + [ 0x00, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x09 ], + [ 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x09 ] +]; + +def check() -> int { + for (i < outcomes.length) { + var expected = outcomes[i]; + var eq = true; + for (j < expected.length) if(expected[j] != bytes[j]) eq = false; + if (eq) return i; + } + return -42; +} \ No newline at end of file diff --git a/test/layout/big_endian18.v3 b/test/layout/big_endian18.v3 new file mode 100644 index 000000000..e3d47755b --- /dev/null +++ b/test/layout/big_endian18.v3 @@ -0,0 +1,36 @@ +//@execute false=2; true=0 +layout F { + +1 g: double[2] #big-endian; + =17; +} + +def bytes: Array = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x66, 0x67 +]; +var r = Ref.at(bytes, 0); + + +def main(a: bool) -> int { + var f: double = if(a, double.view(0x1122334455667788uL), double.view(0x7766554433221100uL)); + r.g[1] = f; + return check(); +} + +def outcomes: Array> = [ + [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x67 ], + [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x67 ], + [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x67 ], + [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x67 ] +]; + +def check() -> int { + for (i < outcomes.length) { + var expected = outcomes[i]; + var eq = true; + for (j < expected.length) if(expected[j] != bytes[j]) eq = false; + if (eq) return i; + } + return -42; +} \ No newline at end of file diff --git a/test/layout/big_endian19.v3 b/test/layout/big_endian19.v3 new file mode 100644 index 000000000..986378181 --- /dev/null +++ b/test/layout/big_endian19.v3 @@ -0,0 +1,16 @@ +//@execute 0=0; 9=9; 900=900; 9000000=9000000; 123456789=6016277 +layout L { + +1 foo: u24 #big-endian; + =4; +} + +var global_r = Ref.of(Array.new(L.size)); + +def get() -> Ref { + return global_r; +} + +def main(a: int) -> int { + global_r.foo = u24.view(a); + return get().foo; +} diff --git a/test/layout/big_endian20.v3 b/test/layout/big_endian20.v3 new file mode 100644 index 000000000..af61e1096 --- /dev/null +++ b/test/layout/big_endian20.v3 @@ -0,0 +1,20 @@ +//@execute 0=0; 9=9; 900=900; 9000000=9000000; 123456789=6016277 +layout L { + +1 foo: u24 #big-endian; + =4; +} + +var data = Array.new(L.size); +var global_r = Ref.of(data); + +def get() -> Ref { + return global_r; +} + +def main(a: int) -> int { + data[0] = 99; + data[1] = byte.view(a >> 16); + data[2] = byte.view(a >> 8); + data[3] = byte.view(a >> 0); + return get().foo; +} diff --git a/test/layout/big_endian21.v3 b/test/layout/big_endian21.v3 new file mode 100644 index 000000000..2ed5fa335 --- /dev/null +++ b/test/layout/big_endian21.v3 @@ -0,0 +1,20 @@ +//@execute 0=0; 9=9; 900=900; 999999=999999; 9000000=611392; 123456789=773397; 23456789=388117 +layout L { + +1 foo: u20 #big-endian; + =4; +} + +var data = Array.new(L.size); +var global_r = Ref.of(data); + +def get() -> Ref { + return global_r; +} + +def main(a: int) -> int { + data[0] = 99; + data[1] = byte.view(a >> 16); + data[2] = byte.view(a >> 8); + data[3] = byte.view(a >> 0); + return get().foo; +} diff --git a/test/layout/big_endian22.v3 b/test/layout/big_endian22.v3 new file mode 100644 index 000000000..37da2ecd4 --- /dev/null +++ b/test/layout/big_endian22.v3 @@ -0,0 +1,20 @@ +//@execute 0=0; 9=9; 900=900; 9000000=9000000; 123456789=6016277 +layout L { + +1 foo: u24 #big-endian; + =4; +} + +var data = Array.new(L.size); +var global_r = Ref.of(data); + +def get() -> u24 { + return global_r.foo; +} + +def main(a: int) -> int { + data[0] = 99; + data[1] = byte.view(a >> 16); + data[2] = byte.view(a >> 8); + data[3] = byte.view(a >> 0); + return get(); +} diff --git a/test/layout/big_endian23.v3 b/test/layout/big_endian23.v3 new file mode 100644 index 000000000..210633fe6 --- /dev/null +++ b/test/layout/big_endian23.v3 @@ -0,0 +1,13 @@ +//@execute (591879, 0)=0; (591879, 1)=9; (591879, 2)=8; (591879, 3)=7; (132102, 0)=0; (132102, 1)=2; (132102, 2)=4; (132102, 3)=6 +layout L { + +1 foo: u24 #big-endian; + =5; // one byte either side +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: u32, b: byte) -> byte { + r.foo = u24.view(a); + return data[b]; +} diff --git a/test/layout/big_endian24.v3 b/test/layout/big_endian24.v3 new file mode 100644 index 000000000..d04445741 --- /dev/null +++ b/test/layout/big_endian24.v3 @@ -0,0 +1,13 @@ +//@execute (591879, 0)=0; (591879, 1)=9; (591879, 2)=8; (591879, 3)=7; (132102, 0)=0; (132102, 1)=2; (132102, 2)=4; (132102, 3)=6 +layout L #big-endian { + +1 foo: u24; + =5; // one byte either side +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: u32, b: byte) -> byte { + r.foo = u24.view(a); + return data[b]; +} diff --git a/test/layout/big_endian25.v3 b/test/layout/big_endian25.v3 new file mode 100644 index 000000000..d1387fe9f --- /dev/null +++ b/test/layout/big_endian25.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=1; (3, 6)=0; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=0; (-111, 6)=0; (-111, 7)=0 +layout L { + +1 foo: u33; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = u33.view(l); + return data[b]; +} diff --git a/test/layout/big_endian26.v3 b/test/layout/big_endian26.v3 new file mode 100644 index 000000000..fb75092ab --- /dev/null +++ b/test/layout/big_endian26.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=5; (3, 6)=0; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=6; (-111, 6)=0; (-111, 7)=0 +layout L { + +1 foo: u35; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = u35.view(l); + return data[b]; +} diff --git a/test/layout/big_endian27.v3 b/test/layout/big_endian27.v3 new file mode 100644 index 000000000..20cfba33b --- /dev/null +++ b/test/layout/big_endian27.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=157; (3, 6)=6; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=78; (-111, 6)=3; (-111, 7)=0 +layout L { + +1 foo: u43; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = u43.view(l); + return data[b]; +} diff --git a/test/layout/big_endian28.v3 b/test/layout/big_endian28.v3 new file mode 100644 index 000000000..81359ea93 --- /dev/null +++ b/test/layout/big_endian28.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=157; (3, 6)=54; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=78; (-111, 6)=27; (-111, 7)=0 +layout L { + +1 foo: u51; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = u51.view(l); + return data[b]; +} diff --git a/test/layout/big_endian29.v3 b/test/layout/big_endian29.v3 new file mode 100644 index 000000000..37503e180 --- /dev/null +++ b/test/layout/big_endian29.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=157; (3, 6)=54; (3, 7)=208; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=78; (-111, 6)=27; (-111, 7)=232 +layout L { + +1 foo: u61; + =9; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = u61.view(l); + return data[b]; +} diff --git a/test/layout/big_endian30.v3 b/test/layout/big_endian30.v3 new file mode 100644 index 000000000..68314090d --- /dev/null +++ b/test/layout/big_endian30.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=255; (3, 6)=0; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=0; (-111, 6)=0; (-111, 7)=0 +layout L { + +1 foo: i33; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = i33.view(l); + return data[b]; +} diff --git a/test/layout/big_endian31.v3 b/test/layout/big_endian31.v3 new file mode 100644 index 000000000..cf86f30d6 --- /dev/null +++ b/test/layout/big_endian31.v3 @@ -0,0 +1,14 @@ +//@execute (3, 0)=0; (3, 1)=54; (3, 2)=205; (3, 3)=105; (3, 4)=3; (3, 5)=253; (3, 6)=0; (3, 7)=0; (-111, 0)=0; (-111, 1)=50; (-111, 2)=87; (-111, 3)=181; (-111, 4)=129; (-111, 5)=254; (-111, 6)=0; (-111, 7)=0 +layout L { + +1 foo: i35; + =8; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: int, b: int) -> int { + var l = long.view(a) * 0x2345_6789_abcd_ef12L; + r.foo = i35.view(l); + return data[b]; +} diff --git a/test/layout/big_endian32.v3 b/test/layout/big_endian32.v3 new file mode 100644 index 000000000..b770d96bd --- /dev/null +++ b/test/layout/big_endian32.v3 @@ -0,0 +1,27 @@ +//@execute = 42 +layout L #big-endian { + +1 f: double; + =10; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def write(v: double) { + r.f = v; +} + +def main() -> int { + write(double.view(0x88776655_44332211uL)); + if (data[0] != 0) return 0; + if (data[1] != 0x88) return 1; + if (data[2] != 0x77) return 2; + if (data[3] != 0x66) return 3; + if (data[4] != 0x55) return 4; + if (data[5] != 0x44) return 5; + if (data[6] != 0x33) return 6; + if (data[7] != 0x22) return 7; + if (data[8] != 0x11) return 8; + if (data[9] != 0) return 9; + return 42; +} diff --git a/test/layout/big_endian33.v3 b/test/layout/big_endian33.v3 new file mode 100644 index 000000000..1a9ebcdaf --- /dev/null +++ b/test/layout/big_endian33.v3 @@ -0,0 +1,27 @@ +//@execute = 42 +layout L #big-endian { + +1 f: u64; + =10; +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def write(v: u64) { + r.f = v; +} + +def main() -> int { + write(0x88776655_44332211uL); + if (data[0] != 0) return 0; + if (data[1] != 0x88) return 1; + if (data[2] != 0x77) return 2; + if (data[3] != 0x66) return 3; + if (data[4] != 0x55) return 4; + if (data[5] != 0x44) return 5; + if (data[6] != 0x33) return 6; + if (data[7] != 0x22) return 7; + if (data[8] != 0x11) return 8; + if (data[9] != 0) return 9; + return 42; +} diff --git a/test/layout/little_endian24.v3 b/test/layout/little_endian24.v3 new file mode 100644 index 000000000..a9ccd0b43 --- /dev/null +++ b/test/layout/little_endian24.v3 @@ -0,0 +1,13 @@ +//@execute (591879, 0)=0; (591879, 1)=7; (591879, 2)=8; (591879, 3)=9; (132102, 0)=0; (132102, 1)=6; (132102, 2)=4; (132102, 3)=2 +layout L { + +1 foo: u24; + =5; // one byte either side +} + +def data = Array.new(L.size); +def r = Ref.of(data); + +def main(a: u32, b: byte) -> byte { + r.foo = u24.view(a); + return data[b]; +}