From e5bd39e937ce198c3d586b336713945b5fb8fd95 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Sun, 30 Mar 2025 14:52:58 +0200 Subject: [PATCH 01/17] WIP: Introduce Opcode2 --- aeneas/src/core/Opcode.v3 | 2 +- aeneas/src/core/Opcode2.v3 | 558 +++++++++++++++++++++++++ aeneas/src/core/Operator.v3 | 418 +++++++++++------- aeneas/src/core/Operator2.v3 | 354 ++++++++++++++++ aeneas/src/ir/IrOpMethodBuilder.v3 | 15 +- aeneas/src/ir/PartialSpecialization.v3 | 6 +- aeneas/src/ir/Reachability.v3 | 4 +- aeneas/src/ir/SsaNormalizer.v3 | 74 ++-- aeneas/src/ir/TypeNorm.v3 | 7 + aeneas/src/jvm/SsaJvmGen.v3 | 18 +- aeneas/src/mach/MachBackend.v3 | 2 +- aeneas/src/mach/MachLowering.v3 | 32 +- aeneas/src/mach/Pointer.v3 | 4 +- aeneas/src/ssa/Ssa.v3 | 2 +- aeneas/src/ssa/SsaBuilder.v3 | 19 +- aeneas/src/ssa/SsaInterpreter.v3 | 4 +- aeneas/src/ssa/SsaOptimizer.v3 | 12 +- aeneas/src/ssa/VstSsaGen.v3 | 4 +- aeneas/src/types/Function.v3 | 4 + aeneas/src/types/Int.v3 | 2 + aeneas/src/vst/MethodEnv.v3 | 28 +- aeneas/src/vst/Verifier.v3 | 16 +- aeneas/src/wasm/WasmCodeGen.v3 | 2 +- aeneas/src/x86/X86CodeGen.v3 | 14 +- aeneas/test/SsaInstrReducerTest.v3 | 2 - doc/aeneas-issues.txt | 3 + test/cast/tuple_cast18.v3 | 27 ++ test/cast/tuple_cast19.v3 | 21 + test/cast/tuple_cast20.v3 | 22 + test/cast/tuple_cast21.v3 | 21 + test/cast/tuple_cast22.v3 | 13 + test/float/seman/double_members14.v3 | 3 + test/pointer/Pointer_NULL4.v3 | 8 + test/pointer/Pointer_SIZE1.v3 | 28 +- test/range/promote10.v3 | 13 + 35 files changed, 1470 insertions(+), 292 deletions(-) create mode 100644 aeneas/src/core/Opcode2.v3 create mode 100644 aeneas/src/core/Operator2.v3 create mode 100644 test/cast/tuple_cast18.v3 create mode 100644 test/cast/tuple_cast19.v3 create mode 100644 test/cast/tuple_cast20.v3 create mode 100644 test/cast/tuple_cast21.v3 create mode 100644 test/cast/tuple_cast22.v3 create mode 100644 test/float/seman/double_members14.v3 create mode 100644 test/pointer/Pointer_NULL4.v3 create mode 100644 test/range/promote10.v3 diff --git a/aeneas/src/core/Opcode.v3 b/aeneas/src/core/Opcode.v3 index 0f3593e70..e6b238b09 100644 --- a/aeneas/src/core/Opcode.v3 +++ b/aeneas/src/core/Opcode.v3 @@ -336,7 +336,7 @@ component Opcodes { t[Opcode.CallerIp.tag] = P; t[Opcode.CallerSp.tag] = P; - t[Opcode.Alloc.tag] = NONE; + t[Opcode.Alloc.tag] = NZ; // XXX: dead-code eliminatable t[Opcode.RefLayoutAt.tag] = NZ|F; t[Opcode.RefLayoutIn.tag] = P|F; diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 new file mode 100644 index 000000000..3de24cc37 --- /dev/null +++ b/aeneas/src/core/Opcode2.v3 @@ -0,0 +1,558 @@ +// Copyright 2024 Virgil authors. All rights reserved. +// See LICENSE for details of Apache 2.0 license. + +// Represents the statically-known part of an operation, not including the types. +type Opcode2 { + // Boolean operators + case BoolEq; + case BoolAnd; + case BoolOr; + case BoolNot; + // Integer arithmetic and conversions + case IntEq(t: IntType); + case IntAdd(t: IntType); + case IntSub(t: IntType); + case IntMul(t: IntType); + case IntDiv(t: IntType); + case IntMod(t: IntType); + case IntAnd(t: IntType); + case IntOr(t: IntType); + case IntXor(t: IntType); + case IntShl(t: IntType); + case IntSar(t: IntType); + case IntShr(t: IntType); + case IntLt(t: IntType); + case IntLteq(t: IntType); + case IntWide(op: Operator, paramTypes: Array, resultTypes: Array); + // Floating point arithmetic + case FloatAdd(t: FloatType); + case FloatSub(t: FloatType); + case FloatMul(t: FloatType); + case FloatDiv(t: FloatType); + case FloatBitEq(t: FloatType); + case FloatEq(t: FloatType); + case FloatNe(t: FloatType); + case FloatLt(t: FloatType); + case FloatLteq(t: FloatType); + case FloatAbs(t: FloatType); + case FloatCeil(t: FloatType); + case FloatFloor(t: FloatType); + case FloatSqrt(t: FloatType); + // Integer casts and conversions + case IntCastF(to: IntType, from: FloatType); + case IntQueryF(to: IntType, from: FloatType); + case IntViewI(to: IntType, from: Type); // TODO: sharpen "from" + case IntViewF(to: IntType, from: Type); // TODO: sharpen "from" + case IntTruncF(to: IntType, from: FloatType); + // Floating point casts and conversions + case FloatCastI(to: FloatType, from: IntType); + case FloatCastD(to: FloatType, from: FloatType); + case FloatQueryI(to: FloatType, from: IntType); + case FloatQueryD(to: FloatType, from: FloatType); + case FloatPromoteI(to: FloatType, from: IntType); + case FloatPromoteF(to: FloatType, from: FloatType); + case FloatViewI(to: FloatType, from: Type); // TODO: sharpen "from" + case FloatRoundI(to: FloatType, from: Type); // TODO: sharpen "from" + case FloatRound(t: FloatType); + case FloatRoundD(to: FloatType, from: FloatType); + // Reference equality + case RefEq(t: Type); + // Default value operator + case DefaultValue(t: Type); + // Int representation for other types + case IntRepCreate(to: IntRepType, from: Type); + case IntRepView(to: Type, from: IntRepType); + // Tuple operations + case TupleCreate(t: TupleType); + case TupleGetElem(t: TupleType, index: int); + // Array operations + case ArrayAlloc(t: ArrayType); + case ArrayFill(t: ArrayType); + case ArrayInit(t: ArrayType, length: int); + case ArrayTupleInit(t: ArrayType, elems: int, length: int); + case ArrayGetElem(t: ArrayType, it: IntType); + case ArraySetElem(t: ArrayType, it: IntType); + case ArrayGetElemElem(t: ArrayType, it: IntType, index: int); + case ArraySetElemElem(t: ArrayType, it: IntType, index: int); + case ArrayGetLength(t: ArrayType); + // Range operations + case RangeFromTo(t: RangeType, startType: IntType, lengthType: IntType); + case RangeFromPlus(t: RangeType, startType: IntType, endType: IntType); + case RangeGetElem(t: RangeType, it: IntType); + case RangeSetElem(t: RangeType, it: IntType); + case RangeGetLength(t: RangeType); + case RangeStartPlusIndex(t: RangeType, it: IntType); + case RangeStartFromPointer(t: RangeType, pt: PointerType); + // Normalized Range operations + case NormRangeGetElem(t: ArrayType, it: IntType); + case NormRangeGetElemElem(t: ArrayType, index: int, it: IntType); + case NormRangeSetElem(t: ArrayType, it: IntType); + case NormRangeSetElemElem(t: ArrayType, index: int, it: IntType); + // Component operations + case Init(method: IrMethod); + case ComponentGetField(field: IrField); + case ComponentSetField(field: IrField); + // Class operations + case ClassAlloc(spec: IrSpec); // TODO: ClassNew/ClassAlloc + case ClassEmptyAlloc(t: ClassType, paramTypes: Array); + case ClassGetField(spec: IrSpec); + case ClassInitField(spec: IrSpec); + case ClassSetField(spec: IrSpec); + case ClassGetMethod(spec: IrSpec); + case ClassGetVirtual(spec: IrSpec); + case ClassGetSelector(spec: IrSpec); + // Variant operations + case VariantEq(t: ClassType); + case VariantGetTag(t: ClassType); + case VariantAlloc(t: ClassType, paramTypes: Array); + case VariantGetField(spec: IrSpec); + case VariantGetMethod(spec: IrSpec); + case VariantGetVirtual(spec: IrSpec); + case VariantGetSelector(spec: IrSpec); + // Safety checks + case NullCheck(t: Type); + case BoundsCheck(t: Type); + case ConditionalThrow(exception: string); + // Overloaded, polymorphic casts + case OverloadedEq(t: Type); + case TypeCast(cast: TypeCast, to: Type, from: Type); + case TypeQuery(query: TypeQuery, to: Type, from: Type); + case TypeSubsume(to: Type, from: Type); + // Closure and call operations + case CallMethod(spec: IrSpec); + case CallClassMethod(spec: IrSpec); + case CallClassVirtual(spec: IrSpec); + case CallClassSelector(spec: IrSpec); + case CallVariantVirtual(spec: IrSpec); + case CallVariantSelector(spec: IrSpec); + case CallClosure(t: FuncType); + case CallFunction(t: FuncType); + case CreateClosure(obj: Type, method: IrSpec); + case ForgeClosure(ptrType: PointerType, closureType: Type, paramType: Type, resultType: Type); + case UnpackClosure(ptrType: PointerType, closureType: Type, paramType: Type, resultType: Type); + // RefLayout operations + case RefLayoutAt(t: RefType); + case RefLayoutOf(t: RefType); + case RefLayoutIn(t: RefType, offset: int, rt: RefType); + case RefLayoutGetField(t: RefType, offset: int, ft: Type); + case RefLayoutSetField(t: RefType, offset: int, ft: Type); + case RefLayoutAtRepeatedField(t: RefType, offset: int, scale: int, max: int, rt: RefType); + case RefLayoutGetRepeatedField(t: RefType, offset: int, scale: int, max: int, ft: Type); + case RefLayoutSetRepeatedField(t: RefType, offset: int, scale: int, max: int, ft: Type); + case ByteArrayGetField(st: Type, offset: int, ft: Type); + case ByteArraySetField(st: Type, offset: int, ft: Type); + case ForgeRange(ptrType: PointerType, t: RangeType); + // System operations + case SystemCall(syscall: SystemCall, paramType: Type, resultType: Type); + // Container for VST operations + case VstSugar(op: VstOperator, paramTypes: Array, resultType: Type); + +// ------- Machine-level operations --------------------------------------------- + // Pointer operations + case PtrAdd(t: Type, it: IntType); + case PtrSub(t: Type, it: IntType); + case PtrLt(t: PointerType); + case PtrLteq(t: PointerType); + case PtrAtContents(t: PointerType, at: Type); + case PtrAtLength(t: PointerType, arrayType: ArrayType); + case PtrAtObject(t: PointerType, objType: Type); + case PtrAtRangeElem(t: PointerType, rangeType: RangeType, it: IntType); + case PtrAtArrayElem(t: PointerType, arrayType: ArrayType, it: IntType); + case PtrAtEnd(t: PointerType, objType: Type); + case PtrAtRef(t: PointerType, refType: Type); // TODO: refType: RefType + case PtrAtComponentField(t: PointerType, field: IrSpec); + case PtrAtObjectField(t: PointerType, field: IrSpec); + case PtrAtRefLayoutField(refType: RefType, t: PointerType, offset: int); + case PtrCmpSwp(t: PointerType, valType: Type); + case PtrLoad(t: Type, valType: Type); + case PtrStore(t: Type, valType: Type); + case PtrAddRangeStart(t: PointerType); + // Get caller instruction pointer or stack pointer + case CallerIp(t: PointerType); + case CallerSp(t: PointerType); + // Allocate raw memory + case Alloc(t: Type); + // Call + case CallAddress(p: PointerType, rep: Mach_FuncRep); + case CallKernel(kernel: Kernel, paramType: Type, resultType: Type); +} + +component Opcodes2 { + def table = Array.new(Opcode2.CallKernel.tag + 1); + new() { + // shorthand for SSA optimization facts + var F = Fact.O_FOLDABLE; + var M: Fact; // TODO = Fact.O_MONOMORPHIC; + var P = Fact.O_PURE | Fact.O_FOLDABLE; // pure => foldable + var C = Fact.O_COMMUTATIVE; + var A: Fact; // TODO = Fact.O_ASSOCIATIVE; + var NZ = Fact.V_NON_ZERO; + var NNEG = Fact.V_NON_NEGATIVE; + var NNC = Fact.O_NO_NULL_CHECK; + var NONE = Facts.NONE; + + def t = table; // for code shortitude + + // register all operators and their optimization facts + t[Opcode2.BoolEq.tag] = P |M|C; + t[Opcode2.BoolAnd.tag] = P|A|M|C; + t[Opcode2.BoolOr.tag] = P|A|M|C; + t[Opcode2.BoolNot.tag] = P|M; + + t[Opcode2.IntEq.tag] = P |M|C; + t[Opcode2.IntAdd.tag] = P|A|M|C; + t[Opcode2.IntSub.tag] = P|M; + t[Opcode2.IntMul.tag] = P|A|M|C; + t[Opcode2.IntDiv.tag] = F|M; + t[Opcode2.IntMod.tag] = F|M; + t[Opcode2.IntAnd.tag] = P|A|M|C; + t[Opcode2.IntOr.tag] = P|A|M|C; + t[Opcode2.IntXor.tag] = P|A|M|C; + t[Opcode2.IntShl.tag] = P|M; + t[Opcode2.IntSar.tag] = P|M; + t[Opcode2.IntShr.tag] = P|M; + t[Opcode2.IntLt.tag] = P|M; + t[Opcode2.IntLteq.tag] = P|M; + t[Opcode2.IntWide.tag] = P|M; + + t[Opcode2.FloatAdd.tag] = P|A|M|C; + t[Opcode2.FloatSub.tag] = P|M; + t[Opcode2.FloatMul.tag] = P|A|M|C; + t[Opcode2.FloatDiv.tag] = P|M; + t[Opcode2.FloatBitEq.tag] = P |M|C; + t[Opcode2.FloatEq.tag] = P |M|C; + t[Opcode2.FloatNe.tag] = P |M|C; + t[Opcode2.FloatLt.tag] = P|M; + t[Opcode2.FloatLteq.tag] = P|M; + t[Opcode2.FloatAbs.tag] = P|M; + t[Opcode2.FloatCeil.tag] = P|M; + t[Opcode2.FloatFloor.tag] = P|M; + t[Opcode2.FloatSqrt.tag] = P|M; + + t[Opcode2.IntCastF.tag] = F|M; + t[Opcode2.IntQueryF.tag] = P|M; + t[Opcode2.IntViewI.tag] = P|M; + t[Opcode2.IntViewI.tag] = P|M; + t[Opcode2.IntViewF.tag] = P|M; + t[Opcode2.IntTruncF.tag] = P|M; + + t[Opcode2.FloatCastI.tag] = F|M; + t[Opcode2.FloatCastD.tag] = F|M; + t[Opcode2.FloatQueryI.tag] = P|M; + t[Opcode2.FloatQueryD.tag] = P|M; + t[Opcode2.FloatPromoteI.tag] = P|M; + t[Opcode2.FloatPromoteF.tag] = P|M; + t[Opcode2.FloatViewI.tag] = P|M; + t[Opcode2.FloatRoundI.tag] = P|M; + t[Opcode2.FloatRound.tag] = P|M; + t[Opcode2.FloatRoundD.tag] = P|M; + + t[Opcode2.RefEq.tag] = P |C; + t[Opcode2.IntRepCreate.tag] = P |F; + t[Opcode2.IntRepView.tag] = P |F; + + t[Opcode2.TupleCreate.tag] = P; + t[Opcode2.TupleGetElem.tag] = P; + + t[Opcode2.ArrayAlloc.tag] = NZ; + t[Opcode2.ArrayInit.tag] = NZ; + t[Opcode2.ArrayGetElem.tag] = NONE; + t[Opcode2.ArraySetElem.tag] = NONE; + t[Opcode2.ArrayGetLength.tag] = F|NNEG; + + t[Opcode2.RangeFromTo.tag] = F; + t[Opcode2.RangeFromPlus.tag] = F; + t[Opcode2.RangeGetLength.tag] = P; + + t[Opcode2.RangeStartPlusIndex.tag] = P; + t[Opcode2.RangeStartFromPointer.tag] = P; + t[Opcode2.NormRangeGetElem.tag] = F; + t[Opcode2.NormRangeGetElemElem.tag] = F; + t[Opcode2.NormRangeSetElem.tag] = NONE; + t[Opcode2.NormRangeSetElemElem.tag] = NONE; + t[Opcode2.PtrAddRangeStart.tag] = P; + t[Opcode2.ForgeRange.tag] = P; + + t[Opcode2.Init.tag] = M; + t[Opcode2.ComponentGetField.tag] = NNC|M; + t[Opcode2.ComponentSetField.tag] = NNC|M; + + t[Opcode2.ClassAlloc.tag] = NZ; + t[Opcode2.ClassEmptyAlloc.tag] = NZ; // TODO: dead-code elimination + t[Opcode2.ClassGetField.tag] = NONE; + t[Opcode2.ClassSetField.tag] = NONE; + t[Opcode2.ClassInitField.tag] = Fact.O_NO_NULL_CHECK; + t[Opcode2.ClassGetMethod.tag] = NZ|F; + t[Opcode2.ClassGetVirtual.tag] = NZ|F; + t[Opcode2.ClassGetSelector.tag] = NZ|F; + + t[Opcode2.VariantEq.tag] = P |C; + t[Opcode2.VariantGetTag.tag] = P|NNEG; + t[Opcode2.VariantAlloc.tag] = P; + t[Opcode2.VariantGetField.tag] = P; + t[Opcode2.VariantGetMethod.tag] = NZ|P; + t[Opcode2.VariantGetVirtual.tag] = NZ|P; + t[Opcode2.VariantGetSelector.tag] = NZ|P; + + t[Opcode2.NullCheck.tag] = F|NZ; + t[Opcode2.BoundsCheck.tag] = F; + t[Opcode2.ConditionalThrow.tag] = F|M; + + t[Opcode2.OverloadedEq.tag] = P |C; + t[Opcode2.TypeCast.tag] = F; + t[Opcode2.TypeQuery.tag] = P; + t[Opcode2.TypeSubsume.tag] = P; + + t[Opcode2.CallMethod.tag] = NONE; + t[Opcode2.CallClassVirtual.tag] = NONE; + t[Opcode2.CallClassSelector.tag] = NONE; + t[Opcode2.CallClosure.tag] = NONE; + t[Opcode2.CallFunction.tag] = NONE; + t[Opcode2.CreateClosure.tag] = NZ|P|NNC; + t[Opcode2.ForgeClosure.tag] = P|NNC; + t[Opcode2.UnpackClosure.tag] = P|NNC; + + t[Opcode2.SystemCall.tag] = NONE; + + t[Opcode2.PtrAdd.tag] = P|M; // XXX: could be foldable with offset + t[Opcode2.PtrSub.tag] = P|M; + t[Opcode2.PtrLt.tag] = P|M; + t[Opcode2.PtrLteq.tag] = P|M; + t[Opcode2.PtrAtContents.tag] = P; + t[Opcode2.PtrAtLength.tag] = P; + t[Opcode2.PtrAtObject.tag] = P; + t[Opcode2.PtrAtRangeElem.tag] = F|M; + t[Opcode2.PtrAtArrayElem.tag] = F|M; + t[Opcode2.PtrAtComponentField.tag] = P|M; + t[Opcode2.PtrAtObjectField.tag] = F; + t[Opcode2.PtrLoad.tag] = NONE; + t[Opcode2.PtrStore.tag] = NONE; + + t[Opcode2.CallerIp.tag] = P|M; + t[Opcode2.CallerSp.tag] = P|M; + + t[Opcode2.Alloc.tag] = NONE; + + t[Opcode2.RefLayoutAt.tag] = NZ|F|M; + t[Opcode2.RefLayoutIn.tag] = P|F|M; + t[Opcode2.RefLayoutGetField.tag] = NONE; + t[Opcode2.RefLayoutAtRepeatedField.tag] = P|M; + } + def facts(opcode: Opcode2) -> Fact.set { + return table[opcode.tag]; + } + def checkOpenness(opcode: Opcode2) -> Open { +//TODO if (table[opcode.tag].O_MONOMORPHIC) return Open.CLOSED; + var open = Open.OPEN; + match (opcode) { + RefEq(t) => open = isOpenType(t); + IntRepCreate(t, f) => open = isOpenType(f); + IntRepView(t, f) => open = isOpenType(t); + IntViewF(t, f) => open = isOpenType(f); + FloatViewI(t, f) => open = isOpenType(f); + FloatRoundI(t, f) => open = isOpenType(f); + TupleCreate(t) => open = isOpenType(t); + TupleGetElem(t, index) => open = isOpenType(t); + ArrayAlloc(t) => open = isOpenType(t); + ArrayInit(t, length) => open = isOpenType(t); + ArrayTupleInit(t, elems, length) => open = isOpenType(t); + ArrayGetElem(t, it) => open = isOpenType(t); + ArraySetElem(t, it) => open = isOpenType(t); + ArrayGetElemElem(t, it, index) => open = isOpenType(t); + ArraySetElemElem(t, it, index) => open = isOpenType(t); + ArrayGetLength(t) => open = isOpenType(t); + RangeFromTo(t, st, lt) => open = isOpenType(t); + RangeFromPlus(t, st, et) => open = isOpenType(t); + RangeGetElem(t, it) => open = isOpenType(t); + RangeSetElem(t, it) => open = isOpenType(t); + RangeGetLength(t) => open = isOpenType(t); + RangeStartPlusIndex(t, it) => open = isOpenType(t); + RangeStartFromPointer(t, pt) => open = isOpenType(t); + NormRangeGetElem(t, it) => open = isOpenType(t); + NormRangeGetElemElem(t, index, it) => open = isOpenType(t); + NormRangeSetElem(t, it) => open = isOpenType(t); + NormRangeSetElemElem(t, index, it) => open = isOpenType(t); + ClassAlloc(spec) => open = isOpenSpec(spec); + ClassEmptyAlloc(t, paramTypes) => open = isOpenTypeOrTypes(t, paramTypes); + ClassGetField(spec) => open = isOpenSpec(spec); + ClassInitField(spec) => open = isOpenSpec(spec); + ClassSetField(spec) => open = isOpenSpec(spec); + ClassGetMethod(spec) => open = isOpenSpec(spec); + ClassGetVirtual(spec) => open = isOpenSpec(spec); + ClassGetSelector(spec) => open = isOpenSpec(spec); + VariantEq(t) => open = isOpenType(t); + VariantGetTag(t) => open = isOpenType(t); + VariantAlloc(t, paramTypes) => open = isOpenTypeOrTypes(t, paramTypes); + VariantGetField(spec) => open = isOpenSpec(spec); + VariantGetMethod(spec) => open = isOpenSpec(spec); + VariantGetVirtual(spec) => open = isOpenSpec(spec); + VariantGetSelector(spec) => open = isOpenSpec(spec); + NullCheck(t) => open = isOpenType(t); + BoundsCheck(t) => open = isOpenType(t); + OverloadedEq(t) => open = isOpenType(t); + TypeCast(cast, to, from) => open = isOpenType2(to, from); + TypeQuery(query, to, from) => open = isOpenType2(to, from); + TypeSubsume(to, from) => open = isOpenType2(to, from); + CallMethod(spec) => open = isOpenSpec(spec); + CallClassMethod(spec) => open = isOpenSpec(spec); + CallClassVirtual(spec) => open = isOpenSpec(spec); + CallClassSelector(spec) => open = isOpenSpec(spec); + CallVariantVirtual(spec) => open = isOpenSpec(spec); + CallVariantSelector(spec) => open = isOpenSpec(spec); + CallClosure(t) => open = isOpenType(t); + CallFunction(t) => open = isOpenType(t); + CreateClosure(obj, method) => open = isOpenTypeOrSpec(obj, method); + ForgeClosure(ptrType, closureType, paramType, resultType) => open = isOpenTypes([closureType, paramType, resultType]); + UnpackClosure(ptrType, closureType, paramType, resultType) => open = isOpenTypes([closureType, paramType, resultType]); + RefLayoutGetField(t, offset, ft) => open = isOpenType(ft); + RefLayoutSetField(t, offset, ft) => open = isOpenType(ft); + RefLayoutGetRepeatedField(t, offset, scale, max, ft) => open = isOpenType(ft); + RefLayoutSetRepeatedField(t, offset, scale, max, ft) => open = isOpenType(ft); + ByteArrayGetField(st, offset, ft) => open = isOpenType(ft); + ByteArraySetField(st, offset, ft) => open = isOpenType(ft); + ForgeRange(ptrType, t) => open = isOpenType(t); + SystemCall(syscall, paramType, resultType) => open = isOpenType2(paramType, resultType); + VstSugar(op, paramTypes, resultType) => open = isOpenTypeOrTypes(resultType, paramTypes); + PtrAtContents(t, at) => open = isOpenType(at); + PtrAtLength(t, arrayType) => open = isOpenType(arrayType); + PtrAtObject(t, objType) => open = isOpenType(objType); + PtrAtRangeElem(t, at, it) => open = isOpenType(at); + PtrAtArrayElem(t, at, it) => open = isOpenType(at); + PtrAtRef(t, refType) => open = isOpenType(refType); + PtrAtEnd(t, objType) => open = isOpenType(objType); + PtrAtObjectField(t, field) => open = isOpenType(t); + PtrAtRefLayoutField(refType, t, offset) => open = isOpenType(t); + PtrCmpSwp(t, valType) => open = isOpenType(valType); + PtrLoad(t, valType) => open = isOpenType(valType); + PtrStore(t, valType) => open = isOpenType(valType); + Alloc(t) => open = isOpenType(t); + CallAddress(p, rep) => ; // TODO + CallKernel(kernel, paramType, resultType) => open = isOpenType2(paramType, resultType); + _ => ; + } + return open; + } + def subst(opcode: Opcode2, func: Type -> Type) -> Opcode2 { + match (opcode) { + RefEq(t) => return Opcode2.RefEq(func(t)); + IntViewF(t, f) => return Opcode2.IntViewF(t, func(f)); + FloatViewI(t, f) => return Opcode2.FloatViewI(t, func(f)); + FloatRoundI(t, f) => return Opcode2.FloatRoundI(t, func(f)); + TupleCreate(t) => return Opcode2.TupleCreate(TupleType.!(func(t))); + TupleGetElem(t, index) => return Opcode2.TupleGetElem(TupleType.!(func(t)), index); + ArrayAlloc(t) => return Opcode2.ArrayAlloc(substArrayType(t, func)); + ArrayFill(t) => return Opcode2.ArrayFill(substArrayType(t, func)); + ArrayInit(t, length) => return Opcode2.ArrayInit(substArrayType(t, func), length); + ArrayTupleInit(t, elems, length) => return Opcode2.ArrayTupleInit(substArrayType(t, func), elems, length); + ArrayGetElem(t, it) => return Opcode2.ArrayGetElem(substArrayType(t, func), it); + ArraySetElem(t, it) => return Opcode2.ArraySetElem(substArrayType(t, func), it); + ArrayGetElemElem(t, it, index) => return Opcode2.ArrayGetElemElem(substArrayType(t, func), it, index); + ArraySetElemElem(t, it, index) => return Opcode2.ArraySetElemElem(substArrayType(t, func), it, index); + ArrayGetLength(t) => return Opcode2.ArrayGetLength(substArrayType(t, func)); + RangeFromTo(t, st, et) => return Opcode2.RangeFromTo(substRangeType(t, func), st, et); + RangeFromPlus(t, st, lt) => return Opcode2.RangeFromPlus(substRangeType(t, func), st, lt); + RangeGetElem(t, it) => return Opcode2.RangeGetElem(substRangeType(t, func), it); + RangeSetElem(t, it) => return Opcode2.RangeSetElem(substRangeType(t, func), it); + RangeGetLength(t) => return Opcode2.RangeGetLength(substRangeType(t, func)); + RangeStartPlusIndex(t, it) => return Opcode2.RangeStartPlusIndex(substRangeType(t, func), it); + RangeStartFromPointer(t, pt) => return Opcode2.RangeStartFromPointer(substRangeType(t, func), pt); + NormRangeGetElem(t, it) => return Opcode2.NormRangeGetElem(substArrayType(t, func), it); + NormRangeGetElemElem(t, index, it) => return Opcode2.NormRangeGetElemElem(substArrayType(t, func), index, it); + NormRangeSetElem(t, it) => return Opcode2.NormRangeSetElem(substArrayType(t, func), it); + NormRangeSetElemElem(t, index, it) => return Opcode2.NormRangeSetElemElem(substArrayType(t, func), index, it); + ClassAlloc(spec) => return Opcode2.ClassAlloc(substSpec(spec, func)); + ClassEmptyAlloc(classType, paramTypes) => return Opcode2.ClassEmptyAlloc(ClassType.!(func(classType)), substArray(paramTypes, func)); + ClassGetField(spec) => return Opcode2.ClassGetField(substSpec(spec, func)); + ClassInitField(spec) => return Opcode2.ClassInitField(substSpec(spec, func)); + ClassSetField(spec) => return Opcode2.ClassSetField(substSpec(spec, func)); + ClassGetMethod(spec) => return Opcode2.ClassGetMethod(substSpec(spec, func)); + ClassGetVirtual(spec) => return Opcode2.ClassGetVirtual(substSpec(spec, func)); + ClassGetSelector(spec) => return Opcode2.ClassGetSelector(substSpec(spec, func)); + VariantEq(t) => return Opcode2.VariantEq(ClassType.!(func(t))); + VariantGetTag(t) => return Opcode2.VariantGetTag(ClassType.!(func(t))); + VariantAlloc(classType, paramTypes) => return Opcode2.VariantAlloc(ClassType.!(func(classType)), substArray(paramTypes, func)); + VariantGetField(spec) => return Opcode2.VariantGetField(substSpec(spec, func)); + VariantGetMethod(spec) => return Opcode2.VariantGetMethod(substSpec(spec, func)); + VariantGetVirtual(spec) => return Opcode2.VariantGetVirtual(substSpec(spec, func)); + VariantGetSelector(spec) => return Opcode2.VariantGetSelector(substSpec(spec, func)); + NullCheck(t) => return Opcode2.NullCheck(func(t)); + BoundsCheck(t) => return Opcode2.BoundsCheck(func(t)); + OverloadedEq(t) => return Opcode2.OverloadedEq(func(t)); + TypeCast(cast, to, from) => return Opcode2.TypeCast(cast, func(to), func(from)); + TypeQuery(query, to, from) => return Opcode2.TypeQuery(query, func(to), func(from)); + TypeSubsume(to, from) => return Opcode2.TypeSubsume(func(to), func(from)); + CallMethod(spec) => return Opcode2.CallMethod(substSpec(spec, func)); + CallClassMethod(spec) => return Opcode2.CallClassMethod(substSpec(spec, func)); + CallClassVirtual(spec) => return Opcode2.CallClassVirtual(substSpec(spec, func)); + CallClassSelector(spec) => return Opcode2.CallClassSelector(substSpec(spec, func)); + CallVariantVirtual(spec) => return Opcode2.CallVariantVirtual(substSpec(spec, func)); + CallVariantSelector(spec) => return Opcode2.CallVariantSelector(substSpec(spec, func)); + CallClosure(t) => return Opcode2.CallClosure(FuncType.!(func(t))); + CallFunction(t) => return Opcode2.CallFunction(FuncType.!(func(t))); + CreateClosure(obj, method) => return Opcode2.CreateClosure(func(obj), substSpec(method, func)); + ForgeClosure(ptrType, closureType, paramType, resultType) => return Opcode2.ForgeClosure(ptrType, func(closureType), func(paramType), func(resultType)); + UnpackClosure(ptrType, closureType, paramType, resultType) => return Opcode2.UnpackClosure(ptrType, func(closureType), func(paramType), func(resultType)); + RefLayoutGetField(t, offset, ft) => return Opcode2.RefLayoutGetField(t, offset, func(ft)); + RefLayoutSetField(t, offset, ft) => return Opcode2.RefLayoutSetField(t, offset, func(ft)); + RefLayoutGetRepeatedField(t, offset, scale, max, ft) => return Opcode2.RefLayoutGetRepeatedField(t, offset, scale, max, func(ft)); + RefLayoutSetRepeatedField(t, offset, scale, max, ft) => return Opcode2.RefLayoutSetRepeatedField(t, offset, scale, max, func(ft)); + ByteArrayGetField(st, offset, ft) => return Opcode2.ByteArrayGetField(st, offset, func(ft)); + ByteArraySetField(st, offset, ft) => return Opcode2.ByteArraySetField(st, offset, func(ft)); + ForgeRange(ptrType, t) => return Opcode2.ForgeRange(ptrType, substRangeType(t, func)); + SystemCall(syscall, paramType, resultType) => return Opcode2.SystemCall(syscall, func(paramType), func(resultType)); + VstSugar(op, paramTypes, resultType) => return Opcode2.VstSugar(op, substArray(paramTypes, func), func(resultType)); + PtrAtContents(t, at) => return Opcode2.PtrAtContents(t, func(at)); + PtrAtLength(t, arrayType) => return Opcode2.PtrAtLength(t, ArrayType.!(func(arrayType))); + PtrAtObject(t, objType) => return Opcode2.PtrAtObject(t, func(objType)); + PtrAtRangeElem(t, at, it) => return Opcode2.PtrAtRangeElem(t, substRangeType(at, func), it); + PtrAtArrayElem(t, at, it) => return Opcode2.PtrAtArrayElem(t, substArrayType(at, func), it); + PtrAtRef(t, refType) => return Opcode2.PtrAtRef(t, func(refType)); + PtrAtEnd(t, objType) => return Opcode2.PtrAtEnd(t, func(objType)); + PtrAtObjectField(t, field) => return Opcode2.PtrAtObjectField(t, substSpec(field, func)); + PtrAtRefLayoutField(refType, t, offset) => return Opcode2.PtrAtRefLayoutField(substRefType(refType, func), t, offset); + PtrCmpSwp(t, valType) => return Opcode2.PtrCmpSwp(t, func(valType)); + PtrLoad(t, valType) => return Opcode2.PtrLoad(t, func(valType)); + PtrStore(t, valType) => return Opcode2.PtrStore(t, func(valType)); + Alloc(t) => return Opcode2.Alloc(func(t)); + CallAddress(p, rep) => return opcode; // TODO + CallKernel(kernel, paramType, resultType) => return Opcode2.CallKernel(kernel, func(paramType), func(resultType)); + _ => return opcode; + } + } + def isOpenType(t: Type) -> Open { + return if(t.open(), Open.OPEN, Open.CLOSED); + } + def isOpenTypes(types: Range) -> Open { + for (t in types) if (t.open()) return Open.OPEN; + return Open.CLOSED; + } + def isOpenSpec(spec: IrSpec) -> Open { + return if(spec.isPolymorphic(), Open.OPEN, Open.CLOSED); + } + def isOpenTypeOrSpec(t: Type, spec: IrSpec) -> Open { + return if(t.open(), Open.OPEN, isOpenSpec(spec)); + } + def isOpenTypeOrTypes(t: Type, r: Array) -> Open { + return if(t.open(), Open.OPEN, isOpenTypes(r)); + } + def isOpenType2(t1: Type, t2: Type) -> Open { + return if(t1.open() || t2.open(), Open.OPEN, Open.CLOSED); + } + def substSpec(spec: IrSpec, func: Type -> Type) -> IrSpec { + var nreceiver = func(spec.receiver); + var ntypeArgs = substArray(spec.typeArgs, func); + if (nreceiver != spec.receiver || ntypeArgs != spec.typeArgs) return IrSpec.new(nreceiver, ntypeArgs, spec.member); + return spec; + } + def substArray(a: Array, func: Type -> Type) -> Array { + for (i < a.length) { + var prev = a[i], ntype = func(prev); + if (prev != ntype) return Arrays.map(a, func); // XXX: slight redundant work for j < i + } + return a; + } + def substArrayType(t: ArrayType, func: Type -> Type) -> ArrayType { return ArrayType.!(func(t)); } + def substRangeType(t: RangeType, func: Type -> Type) -> RangeType { return RangeType.!(func(t)); } + def substFuncType(t: FuncType, func: Type -> Type) -> FuncType { return FuncType.!(func(t)); } + def substRefType(t: RefType, func: Type -> Type) -> RefType { return RefType.!(func(t)); } +} diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 72f07aa04..9605751ae 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -3,8 +3,9 @@ // An operator represents a computation from argument values to a result value // with possible side-effects. -class Operator(opcode: Opcode, typeArgs: Array, sig: Signature) { +class Operator(opcode: Opcode, typeArgs: Array, sig_: Signature) { private var openness: Open; // lazily computed open / closed + var op2: Operator2; def checkOpenness() -> Open { // openness is not known. check all type args and operator type @@ -12,6 +13,7 @@ class Operator(opcode: Opcode, typeArgs: Array, sig: Signature) { var hash = 0; // XXX: bail out earlier if a nested type is open for (t in typeArgs) hash = hash | t.hash; + var sig = this.sig(); for (t in sig.paramTypes) hash = hash | t.hash; for (t in sig.returnTypes) hash = hash | t.hash; return openness = if((hash & TypeConst.OPEN_MASK) != 0, Open.OPEN, Open.CLOSED); @@ -22,7 +24,9 @@ class Operator(opcode: Opcode, typeArgs: Array, sig: Signature) { def subst(f: Type -> Type) -> Operator { if (openness == Open.CLOSED) return this; if (checkOpenness() == Open.OPEN) { - return Operator.new(opcode, Arrays.map(typeArgs, f), sig.subst(f)); + var op = Operator.new(opcode, Arrays.map(typeArgs, f), sig_.subst(f)); + if (op2 != null) op.op2 = this.op2.subst(f); + return op; } return this; } @@ -36,6 +40,13 @@ class Operator(opcode: Opcode, typeArgs: Array, sig: Signature) { def evaluate(args: Arguments) -> Result { return Eval.doOp(this, args); } + def setOp2(op: Opcode2) -> this { + this.op2 = Operator2.new(op); + } + def sig() -> Signature { + if (op2 != null) return op2.sig(); + return sig_; + } } // Whether an operator is known to contain any open (polymorphic) types. @@ -70,98 +81,121 @@ component V3Op { } //---------------------------------------------------------------------------- - def opBoolEq = Operator.new(Opcode.BoolEq, arr_z, sig_zz_z); - def opBoolAnd = Operator.new(Opcode.BoolAnd, arr_v, sig_zz_z); - def opBoolOr = Operator.new(Opcode.BoolOr, arr_v, sig_zz_z); - def opBoolNot = Operator.new(Opcode.BoolNot, arr_v, sig_z_z); + def opBoolEq = Operator.new(Opcode.BoolEq, arr_z, sig_zz_z).setOp2(Opcode2.BoolEq); + def opBoolAnd = Operator.new(Opcode.BoolAnd, arr_v, sig_zz_z).setOp2(Opcode2.BoolAnd); + def opBoolOr = Operator.new(Opcode.BoolOr, arr_v, sig_zz_z).setOp2(Opcode2.BoolOr); + def opBoolNot = Operator.new(Opcode.BoolNot, arr_v, sig_z_z).setOp2(Opcode2.BoolNot); //---------------------------------------------------------------------------- - def newIntEq(t: Type) -> Operator { - return newOp0(Opcode.IntEq, [t], [t, t], type_z); + def newIntEq(t: IntType) -> Operator { + return newOp0(Opcode.IntEq, [t], [t, t], type_z).setOp2(Opcode2.IntEq(t)) + .setOp2(Opcode2.IntEq(t)); } def newIntWide(op: Operator, normal: Array, result: Type) -> Operator { - return newOp0(Opcode.IntWide(op), arr_v, normal, result); + return newOp0(Opcode.IntWide(op), arr_v, normal, result) + .setOp2(Opcode2.IntWide(op, normal, Tuple.toTypeArray(result))); } //---------------------------------------------------------------------------- - def opFloatBitEq32 = newOp0(Opcode.FloatBitEq(false), arr_f, arr_ff, type_z); - def opFloatBitEq64 = newOp0(Opcode.FloatBitEq(true), arr_d, arr_dd, type_z); + def opFloatBitEq32 = newOp0(Opcode.FloatBitEq(false), arr_f, arr_ff, type_z).setOp2(Opcode2.FloatBitEq(Float.FLOAT32)); + def opFloatBitEq64 = newOp0(Opcode.FloatBitEq(true), arr_d, arr_dd, type_z).setOp2(Opcode2.FloatBitEq(Float.FLOAT64)); //---------------------------------------------------------------------------- def newIntCastF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], [ft], tt); + return newOp0(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], [ft], tt) + .setOp2(Opcode2.IntCastF(IntType.!(tt), FloatType.!(ft))); } def newIntQueryF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], [ft], type_z); + return newOp0(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], [ft], type_z) + .setOp2(Opcode2.IntQueryF(IntType.!(tt), FloatType.!(ft))); } def newIntViewI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntViewI, [ft, tt], [ft], tt); + return newOp0(Opcode.IntViewI, [ft, tt], [ft], tt) + .setOp2(Opcode2.IntViewI(IntType.!(tt), IntType.!(ft))); } - def opIntViewF32 = newOp0(Opcode.IntViewF(false), arr_f, arr_f, type_u); - def opIntViewF64 = newOp0(Opcode.IntViewF(true), arr_d, arr_d, Int.getType(false, 64)); + def opIntViewF32 = newOp0(Opcode.IntViewF(false), arr_f, arr_f, type_u).setOp2(Opcode2.IntViewF(Int.U32, Float.FLOAT32)); + def opIntViewF64 = newOp0(Opcode.IntViewF(true), arr_d, arr_d, Int.getType(false, 64)).setOp2(Opcode2.IntViewF(Long.U64, Float.FLOAT64)); def newIntTruncF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], [ft], tt); + return newOp0(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], [ft], tt) + .setOp2(Opcode2.IntTruncF(IntType.!(tt), FloatType.!(ft))); } //---------------------------------------------------------------------------- def newFloatCastI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], [ft], tt); + return newOp0(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], [ft], tt) + .setOp2(Opcode2.FloatCastI(FloatType.!(tt), IntType.!(ft))); } - def opFloatCastD = newOp0(Opcode.FloatCastD, arr_d, arr_d, type_f); + def opFloatCastD = newOp0(Opcode.FloatCastD, arr_d, arr_d, type_f).setOp2(Opcode2.FloatCastD(Float.FLOAT32, Float.FLOAT64)); def newFloatQueryI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], [ft], type_z); + return newOp0(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], [ft], type_z) + .setOp2(Opcode2.FloatQueryI(FloatType.!(tt), IntType.!(ft))); } - def opFloatQueryD = newOp0(Opcode.FloatQueryD, arr_d, arr_d, type_z); + def opFloatQueryD = newOp0(Opcode.FloatQueryD, arr_d, arr_d, type_z).setOp2(Opcode2.FloatQueryD(Float.FLOAT32, Float.FLOAT64)); def newFloatPromoteI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], [ft], tt); + return newOp0(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], [ft], tt) + .setOp2(Opcode2.FloatPromoteI(FloatType.!(tt), IntType.!(ft))); } - def opFloatPromoteF = newOp0(Opcode.FloatPromoteF, arr_f, arr_f, type_d); + def opFloatPromoteF = newOp0(Opcode.FloatPromoteF, arr_f, arr_f, type_d).setOp2(Opcode2.FloatPromoteF(Float.FLOAT64, Float.FLOAT32)); def newFloat32ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(false), [ft, type_f], [ft], type_f); + return newOp0(Opcode.FloatViewI(false), [ft, type_f], [ft], type_f) + .setOp2(Opcode2.FloatViewI(Float.FLOAT32, ft)); // TODO: ft should be IntType } def newFloat64ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(true), [ft, type_d], [ft], type_d); + return newOp0(Opcode.FloatViewI(true), [ft, type_d], [ft], type_d) + .setOp2(Opcode2.FloatViewI(Float.FLOAT64, ft)); // TODO: ft should be IntType } def newFloatRoundI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], [ft], tt); + return newOp0(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], [ft], tt) + .setOp2(Opcode2.FloatRoundI(FloatType.!(tt), ft)); // TODO: ft should be IntType } def newFloatRound(t: Type) -> Operator { - return newOp0(Opcode.FloatRound(V3.isDouble(t)), [t], [t], t); + return newOp0(Opcode.FloatRound(V3.isDouble(t)), [t], [t], t) + .setOp2(Opcode2.FloatRound(FloatType.!(t))); } - def opFloatRoundD = newOp0(Opcode.FloatRoundD, arr_v, arr_d, type_f); + def opFloatRoundD = newOp0(Opcode.FloatRoundD, arr_v, arr_d, type_f) + .setOp2(Opcode2.FloatRoundD(Float.FLOAT32, Float.FLOAT64)); //---------------------------------------------------------------------------- def newRefEq(t: Type) -> Operator { - return newOp0(Opcode.RefEq, [t], [t, t], type_z); + return newOp0(Opcode.RefEq, [t], [t, t], type_z) + .setOp2(Opcode2.RefEq(t)); } //---------------------------------------------------------------------------- def newDefaultValue(t: Type) -> Operator { - return newOp0(Opcode.DefaultValue, [t], arr_v, t); + return newOp0(Opcode.DefaultValue, [t], arr_v, t) + .setOp2(Opcode2.DefaultValue(t)); } //---------------------------------------------------------------------------- def newIntRepCreate(ft: Type, tt: IntRepType) -> Operator { - return newOp0(Opcode.IntRepCreate, [ft, tt], [ft], tt); + return newOp0(Opcode.IntRepCreate, [ft, tt], [ft], tt) + .setOp2(Opcode2.IntRepCreate(tt, ft)); } def newIntRepView(ft: IntRepType, tt: Type) -> Operator { - return newOp0(Opcode.IntRepView, [ft, tt], [ft], tt); + return newOp0(Opcode.IntRepView, [ft, tt], [ft], tt) + .setOp2(Opcode2.IntRepView(tt, ft)); } //---------------------------------------------------------------------------- def newTupleCreate(tupleType: Type) -> Operator { var paramTypes = Lists.toArray(tupleType.nested); - return newOp0(Opcode.TupleCreate(paramTypes.length), [tupleType], paramTypes, tupleType); + return newOp0(Opcode.TupleCreate(paramTypes.length), [tupleType], paramTypes, tupleType) + .setOp2(Opcode2.TupleCreate(TupleType.!(tupleType))); } def newTupleGetElem(tupleType: Type, index: int) -> Operator { var tt = [tupleType]; - return newOp0(Opcode.TupleGetElem(index), tt, tt, Lists.get(tupleType.nested, index)); + return newOp0(Opcode.TupleGetElem(index), tt, tt, Lists.get(tupleType.nested, index)) + .setOp2(Opcode2.TupleGetElem(TupleType.!(tupleType), index)); } //---------------------------------------------------------------------------- def newArrayAlloc(arrayType: Type) -> Operator { - return newOp0(Opcode.ArrayAlloc, [arrayType], arr_i, arrayType); + return newOp0(Opcode.ArrayAlloc, [arrayType], arr_i, arrayType) + .setOp2(Opcode2.ArrayAlloc(ArrayType.!(arrayType))); } def newArrayFill(arrayType: Type) -> Operator { var elemType = V3Array.elementType(arrayType); - return newOp0(Opcode.ArrayFill, [arrayType], [arrayType, elemType], arrayType); + return newOp0(Opcode.ArrayFill, [arrayType], [arrayType, elemType], arrayType) + .setOp2(Opcode2.ArrayFill(ArrayType.!(arrayType))); } def newArrayInit(arrayType: Type, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); var paramTypes = Array.new(length); for (i < paramTypes.length) paramTypes[i] = elemType; - return newOp0(Opcode.ArrayInit(length), [arrayType], paramTypes, arrayType); + return newOp0(Opcode.ArrayInit(length), [arrayType], paramTypes, arrayType) + .setOp2(Opcode2.ArrayInit(ArrayType.!(arrayType), length)); } def newArrayTupleInit(arrayType: Type, elems: int, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); @@ -173,231 +207,282 @@ component V3Op { paramTypes[i++] = tuple[k]; } } - return newOp0(Opcode.ArrayTupleInit(elems, length), [arrayType], paramTypes, arrayType); + return newOp0(Opcode.ArrayTupleInit(elems, length), [arrayType], paramTypes, arrayType) + .setOp2(Opcode2.ArrayTupleInit(ArrayType.!(arrayType), elems, length)); } def newArrayGetElem(arrayType: Type, indexType: IntType) -> Operator { - var op = if(V3.isArray(arrayType), Opcode.ArrayGetElem, Opcode.RangeGetElem); + var elemType = V3Array.elementType(arrayType); var tt = [arrayType, indexType]; - return newOp0(op, tt, tt, V3Array.elementType(arrayType)); + match (arrayType) { + x: ArrayType => return newOp0(Opcode.ArrayGetElem, tt, tt, elemType) + .setOp2(Opcode2.ArrayGetElem(x, indexType)); + x: RangeType => return newOp0(Opcode.RangeGetElem, tt, tt, elemType) + .setOp2(Opcode2.RangeGetElem(x, indexType)); + _ => return null; // TODO: error + } } def newArraySetElem(arrayType: Type, indexType: IntType) -> Operator { - var etype = V3Array.elementType(arrayType); - var op = if(V3.isArray(arrayType), Opcode.ArraySetElem, Opcode.RangeSetElem); - var tt = [arrayType, indexType, etype]; - return newOp0(op, tt, tt, type_v); + var elemType = V3Array.elementType(arrayType); + var tt = [arrayType, indexType, elemType]; + match (arrayType) { + x: ArrayType => return newOp0(Opcode.ArraySetElem, tt, tt, type_v) + .setOp2(Opcode2.ArraySetElem(x, indexType)); + x: RangeType => return newOp0(Opcode.RangeSetElem, tt, tt, type_v) + .setOp2(Opcode2.RangeSetElem(x, indexType)); + _ => return null; // TODO: error + } } def newArrayGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType]; - return newOp0(Opcode.ArrayGetElemElem(index), tt, tt, etype); + return newOp0(Opcode.ArrayGetElemElem(index), tt, tt, etype) + .setOp2(Opcode2.ArrayGetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArraySetElemElem(arrayType: Type, indexType: Type, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType, etype]; - return newOp0(Opcode.ArraySetElemElem(index), tt, tt, type_v); + return newOp0(Opcode.ArraySetElemElem(index), tt, tt, type_v) + .setOp2(Opcode2.ArraySetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArrayGetLength(arrayType: Type) -> Operator { - var op = if(V3.isArray(arrayType), Opcode.ArrayGetLength, Opcode.RangeGetLength); var tt = [arrayType]; - return newOp0(op, tt, tt, type_i); + match (arrayType) { + x: ArrayType => return newOp0(Opcode.ArrayGetLength, tt, tt, type_i) + .setOp2(Opcode2.ArrayGetLength(x)); + x: RangeType => return newOp0(Opcode.RangeGetLength, tt, tt, type_i) + .setOp2(Opcode2.RangeGetLength(x)); + _ => return null; // TODO: error + } } //---------------------------------------------------------------------------- def newRangeFromPlus(rangeType: Type, startType: Type, lengthType: Type) -> Operator { var tt = [rangeType, startType, lengthType]; - return newOp0(Opcode.RangeFromPlus, tt, tt, rangeType); + return newOp0(Opcode.RangeFromPlus, tt, tt, rangeType) + .setOp2(Opcode2.RangeFromPlus(RangeType.!(rangeType), IntType.!(startType), IntType.!(lengthType))); } def newRangeFromTo(rangeType: Type, startType: Type, endType: Type) -> Operator { var tt = [rangeType, startType, endType]; - return newOp0(Opcode.RangeFromTo, tt, tt, rangeType); + return newOp0(Opcode.RangeFromTo, tt, tt, rangeType) + .setOp2(Opcode2.RangeFromTo(RangeType.!(rangeType), IntType.!(startType), IntType.!(endType))); } def newRangeGetLength(rangeType: Type) -> Operator { var tt = [rangeType]; - return newOp0(Opcode.RangeGetLength, tt, tt, type_i); + return newOp0(Opcode.RangeGetLength, tt, tt, type_i) + .setOp2(Opcode2.RangeGetLength(RangeType.!(rangeType))); } def newRangeStartPlusIndex(rangeType: Type, indexType: IntType) -> Operator { - return newOp0(Opcode.RangeStartPlusIndex, [rangeType, indexType], [type_rs, indexType], type_rs); + return newOp0(Opcode.RangeStartPlusIndex, [rangeType, indexType], [type_rs, indexType], type_rs) + .setOp2(Opcode2.RangeStartPlusIndex(RangeType.!(rangeType), indexType)); } def newRangeStartFromPointer(rangeType: Type, ptrType: PointerType) -> Operator { - return newOp0(Opcode.RangeStartFromPointer, [rangeType, ptrType], [ptrType], type_rs); + return newOp0(Opcode.RangeStartFromPointer, [rangeType, ptrType], [ptrType], type_rs) + .setOp2(Opcode2.RangeStartFromPointer(RangeType.!(rangeType), ptrType)); } def newNormRangeGetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeGetElem, [arrayType, indexType], [arrayType, type_rs, indexType], etype); + return newOp0(Opcode.NormRangeGetElem, [arrayType, indexType], [arrayType, type_rs, indexType], etype) + .setOp2(Opcode2.NormRangeGetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType], etype); + return newOp0(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType], etype) + .setOp2(Opcode2.NormRangeGetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } def newNormRangeSetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeSetElem, [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v); + return newOp0(Opcode.NormRangeSetElem, [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v) + .setOp2(Opcode2.NormRangeSetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeSetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v); + return newOp0(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v) + .setOp2(Opcode2.NormRangeSetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } //---------------------------------------------------------------------------- def newInit(meth: IrMethod) -> Operator { - return newOp0(Opcode.Init(meth), TypeUtil.NO_TYPES, TypeUtil.NO_TYPES, meth.receiver); + return newOp0(Opcode.Init(meth), TypeUtil.NO_TYPES, TypeUtil.NO_TYPES, meth.receiver) + .setOp2(Opcode2.Init(meth)); } def newComponentGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ComponentGetField(fieldRef.asField()), tt, tt, - fieldRef.getFieldType()); + return newOp0(Opcode.ComponentGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) + .setOp2(Opcode2.ComponentGetField(fieldRef.asField())); } def newComponentSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], - type_v); + return newOp0(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) + .setOp2(Opcode2.ComponentSetField(fieldRef.asField())); } //---------------------------------------------------------------------------- def newClassAlloc(newRef: IrSpec) -> Operator { var ftype = newRef.getBoundType(), paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], paramTypes, newRef.receiver); + return newOp0(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], paramTypes, newRef.receiver) + .setOp2(Opcode2.ClassAlloc(newRef)); } def newEmptyClassAlloc(classType: Type) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], TypeUtil.NO_TYPES, classType); + return newOp0(Opcode.ClassAlloc(null), [classType], TypeUtil.NO_TYPES, classType) + .setOp2(Opcode2.ClassEmptyAlloc(ClassType.!(classType), TypeUtil.NO_TYPES)); } def newEmptyClassAllocP(classType: Type, paramTypes: Array) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], paramTypes, classType); + return newOp0(Opcode.ClassAlloc(null), [classType], paramTypes, classType) + .setOp2(Opcode2.ClassEmptyAlloc(ClassType.!(classType), paramTypes)); } def newClassGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ClassGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()); + return newOp0(Opcode.ClassGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) + .setOp2(Opcode2.ClassGetField(fieldRef)); } def newClassInitField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], - [fieldRef.receiver, fieldType], type_v); + return newOp0(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) + .setOp2(Opcode2.ClassInitField(fieldRef)); } def newClassSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], - [fieldRef.receiver, fieldType], type_v); + return newOp0(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) + .setOp2(Opcode2.ClassSetField(fieldRef)); } def newClassGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], - methodRef.getBoundType()); + return newOp0(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) + .setOp2(Opcode2.ClassGetMethod(methodRef)); } def newClassGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], - methodRef.getBoundType()); + return newOp0(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) + .setOp2(Opcode2.ClassGetVirtual(methodRef)); } def newClassGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.ClassGetSelector(selector), typeArgs, [methodRef.receiver], - methodRef.getFuncType()); + return newOp0(Opcode.ClassGetSelector(selector), typeArgs, [methodRef.receiver], methodRef.getFuncType()) + .setOp2(Opcode2.ClassGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newVariantGetTag(vtype: Type) -> Operator { var vt = [vtype]; - return newOp0(Opcode.VariantGetTag, vt, vt, V3.classDecl(vtype).tagType); + return newOp0(Opcode.VariantGetTag, vt, vt, V3.classDecl(vtype).tagType) + .setOp2(Opcode2.VariantGetTag(ClassType.!(vtype))); } def newVariantAlloc(t: Type, fieldTypes: Array) -> Operator { - return newOp0(Opcode.VariantAlloc, [t], fieldTypes, t); + return newOp0(Opcode.VariantAlloc, [t], fieldTypes, t) + .setOp2(Opcode2.VariantAlloc(ClassType.!(t), fieldTypes)); } def newVariantGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()); + return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) + .setOp2(Opcode2.VariantGetField(fieldRef)); } def newVariantGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], - methodRef.getBoundType()); + return newOp0(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) + .setOp2(Opcode2.VariantGetMethod(methodRef)); } def newVariantGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], - methodRef.getBoundType()); + return newOp0(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) + .setOp2(Opcode2.VariantGetVirtual(methodRef)); } def newVariantGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.VariantGetSelector(selector), typeArgs, [methodRef.receiver], - methodRef.getFuncType()); + return newOp0(Opcode.VariantGetSelector(selector), typeArgs, [methodRef.receiver], methodRef.getFuncType()) + .setOp2(Opcode2.VariantGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newNullCheck(rtype: Type) -> Operator { var tt = [rtype]; - return newOp0(Opcode.NullCheck, tt, tt, rtype); + return newOp0(Opcode.NullCheck, tt, tt, rtype) + .setOp2(Opcode2.NullCheck(rtype)); } def newBoundsCheck(rtype: Type) -> Operator { - return newOp0(Opcode.BoundsCheck, [rtype], [rtype, type_i], type_v); + return newOp0(Opcode.BoundsCheck, [rtype], [rtype, type_i], type_v) + .setOp2(Opcode2.BoundsCheck(rtype)); } def newConditionalThrow(exception: string) -> Operator { - return newOp0(Opcode.ConditionalThrow(exception), arr_v, Bool.ARRAY_T, type_v); + return newOp0(Opcode.ConditionalThrow(exception), arr_v, Bool.ARRAY_T, type_v) + .setOp2(Opcode2.ConditionalThrow(exception)); } //---------------------------------------------------------------------------- def newEqual(t: Type) -> Operator { - var opcode: Opcode = Opcode.OverloadedEq; + var opcode: Opcode; + var opcode2: Opcode2; match (t.typeCon.kind) { BOOL => return opBoolEq; + INT => { opcode = Opcode.IntEq; opcode2 = Opcode2.IntEq(IntType.!(t)); } ENUM, - ENUM_SET, - INT => opcode = Opcode.IntEq; - FLOAT => opcode = Opcode.FloatEq(V3.isDouble(t)); + ENUM_SET => { opcode = Opcode.IntEq; opcode2 = Opcode2.OverloadedEq(t); } // TODO + FLOAT => { opcode = Opcode.FloatEq(V3.isDouble(t)); opcode2 = Opcode2.FloatEq(FloatType.!(t)); } POINTER, ARRAY, CLASS, FUNCREF, - RANGE_START => opcode = Opcode.RefEq; - VARIANT => opcode = Opcode.VariantEq; - _ => ; + RANGE_START => { opcode = Opcode.RefEq; opcode2 = Opcode2.RefEq(t); } + VARIANT => { opcode = Opcode.VariantEq; opcode2 = Opcode2.VariantEq(ClassType.!(t)); } + _ => { opcode = Opcode.OverloadedEq; opcode2 = Opcode2.OverloadedEq(t); } } - return newOp0(opcode, [t], [t, t], type_z); + return newOp0(opcode, [t], [t, t], type_z) + .setOp2(opcode2); } def newTypeCast(f: Type, t: Type) -> Operator { var cast = TypeSystem.newTypeCast(f, t); - return newOp0(Opcode.TypeCast(cast), [f, t], [f], t); + return newOp0(Opcode.TypeCast(cast), [f, t], [f], t) + .setOp2(Opcode2.TypeCast(cast, t, f)); } def newTypeQuery(f: Type, t: Type) -> Operator { var query = TypeSystem.newTypeQuery(f, t); - return newOp0(Opcode.TypeQuery(query), [f, t], [f], type_z); + return newOp0(Opcode.TypeQuery(query), [f, t], [f], type_z) + .setOp2(Opcode2.TypeQuery(query, t, f)); } def newTypeSubsume(typeFrom: Type, typeTo: Type) -> Operator { - return newOp0(Opcode.TypeSubsume, [typeFrom, typeTo], [typeFrom], typeTo); + return newOp0(Opcode.TypeSubsume, [typeFrom, typeTo], [typeFrom], typeTo) + .setOp2(Opcode2.TypeSubsume(typeTo, typeFrom)); } //---------------------------------------------------------------------------- def newCallMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallMethod(methodRef)); } def newCallClassMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallClassMethod(methodRef)); } def newCallClassVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallClassVirtual(methodRef)); } def newCallVariantVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallVariantVirtual(methodRef)); } def newCallClassSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallClassSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallClassSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallClassSelector(methodRef)); } def newCallVariantSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var paramTypes = Function.getParamTypeArray(ftype); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallVariantSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallVariantSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallVariantSelector(methodRef)); } def newCallClosure(ftype: Type) -> Operator { var fTypes = Function.getParamTypeArray(ftype); var paramTypes = Arrays.prepend(ftype, fTypes); - return newOp0(Opcode.CallClosure, [ftype], paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallClosure, [ftype], paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallClosure(FuncType.!(ftype))); } def newCallClosure2(ftype: Type, paramTypes: Array) -> Operator { return newOp0(Opcode.CallClosure, [ftype], paramTypes, Function.getReturnType(ftype)); @@ -406,82 +491,103 @@ component V3Op { ftype = Function.funcRefType(Function.prependParamType(AnyRef.TYPE, ftype)); if (ftype.typeCon.kind != Kind.FUNCREF) return V3.fail("only function types allowed"); var paramTypes = Arrays.prepend(ftype, Function.getParamTypeArray(ftype)); - return newOp0(Opcode.CallFunction, [ftype], paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallFunction, [ftype], paramTypes, Function.getReturnType(ftype)) + .setOp2(Opcode2.CallFunction(FuncType.!(ftype))); } - def newCreateClosure(methodRef: IrSpec, closure: Type) -> Operator { + def newCreateClosure(methodRef: IrSpec, objType: Type) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, [closure], methodRef.getBoundType()); + return newOp0(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, [objType], methodRef.getBoundType()) + .setOp2(Opcode2.CreateClosure(objType, methodRef)); } def newForgeClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { var funcType = Function.newType(param, result); - return newOp0(Opcode.ForgeClosure, [receiver, param, result], [ptrType, receiver], funcType); + return newOp0(Opcode.ForgeClosure, [receiver, param, result], [ptrType, receiver], funcType) + .setOp2(Opcode2.ForgeClosure(PointerType.!(ptrType), receiver, param, result)); } def newUnpackClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { var funcType = Function.newType(param, result); - return newOp0(Opcode.UnpackClosure, [receiver, param, result], [funcType], Tuple.newType(Lists.cons2(ptrType, receiver))); + return newOp0(Opcode.UnpackClosure, [receiver, param, result], [funcType], Tuple.newType(Lists.cons2(ptrType, receiver))) + .setOp2(Opcode2.UnpackClosure(PointerType.!(ptrType), receiver, param, result)); } def newForgeRange(elementType: Type, ptrType: Type) -> Operator { var rangeType = V3Range.newType(elementType); - return newOp0(Opcode.ForgeRange, [elementType, ptrType], [ptrType, Int.TYPE], rangeType); + return newOp0(Opcode.ForgeRange, [elementType, ptrType], [ptrType, Int.TYPE], rangeType) + .setOp2(Opcode2.ForgeRange(PointerType.!(ptrType), RangeType.!(V3Range.newType(elementType)))); } //---------------------------------------------------------------------------- def newSystemCall(syscall: SystemCall, paramTypes: Array, returnType: Type) -> Operator { - return newOp0(Opcode.SystemCall(syscall), arr_v, paramTypes, returnType); + return newOp0(Opcode.SystemCall(syscall), arr_v, paramTypes, returnType) + .setOp2(Opcode2.SystemCall(syscall, Tuple.fromTypeArray(paramTypes), returnType)); } //---------------------------------------------------------------------------- def newVstSugar(op: VstOperator, typeParams: Array, paramTypes: Array, result: Type) -> Operator { - return Operator.new(Opcode.VstSugar(op), typeParams, Function.siga(paramTypes, result)); + return Operator.new(Opcode.VstSugar(op), typeParams, Function.siga(paramTypes, result)) + .setOp2(Opcode2.VstSugar(op, paramTypes, result)); } //---------------------------------------------------------------------------- def newPtrAdd(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrAdd, [ptrType, it], [ptrType, it], ptrType); + return newOp0(Opcode.PtrAdd, [ptrType, it], [ptrType, it], ptrType) + .setOp2(Opcode2.PtrAdd(ptrType, IntType.!(it))); } def newPtrSub(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrSub, [ptrType, it], [ptrType, ptrType], it); + return newOp0(Opcode.PtrSub, [ptrType, it], [ptrType, ptrType], it) + .setOp2(Opcode2.PtrSub(ptrType, IntType.!(it))); } def newPtrLt(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLt, [ptrType], [ptrType, ptrType], type_z); + return newOp0(Opcode.PtrLt, [ptrType], [ptrType, ptrType], type_z) + .setOp2(Opcode2.PtrLt(PointerType.!(ptrType))); } def newPtrLteq(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLteq, [ptrType], [ptrType, ptrType], type_z); + return newOp0(Opcode.PtrLteq, [ptrType], [ptrType, ptrType], type_z) + .setOp2(Opcode2.PtrLteq(PointerType.!(ptrType))); } def newPtrAtContents(rangeType: Type, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtContents, [rangeType], [rangeType], ptrType); + return newOp0(Opcode.PtrAtContents, [rangeType], [rangeType], ptrType) + .setOp2(Opcode2.PtrAtContents(PointerType.!(ptrType), rangeType)); } def newPtrAtLength(arrayType: Type, ptrType: Type) -> Operator { var tt = [arrayType]; - return newOp0(Opcode.PtrAtLength, tt, tt, ptrType); + return newOp0(Opcode.PtrAtLength, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtLength(PointerType.!(ptrType), ArrayType.!(arrayType))); } def newPtrAtObject(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtObject, tt, tt, ptrType); + return newOp0(Opcode.PtrAtObject, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtObject(PointerType.!(ptrType), objType)); } def newPtrAtArrayElem(arrayType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [arrayType, indexType]; - return newOp0(Opcode.PtrAtArrayElem, tt, tt, ptrType); + return newOp0(Opcode.PtrAtArrayElem, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtArrayElem(PointerType.!(ptrType), ArrayType.!(arrayType), IntType.!(indexType))); } def newPtrAtRangeElem(rangeType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [rangeType, indexType]; - return newOp0(Opcode.PtrAtRangeElem, tt, tt, ptrType); + return newOp0(Opcode.PtrAtRangeElem, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtRangeElem(PointerType.!(ptrType), RangeType.!(rangeType), IntType.!(indexType))); } def newPtrAtEnd(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtEnd, tt, tt, ptrType); + return newOp0(Opcode.PtrAtEnd, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtEnd(PointerType.!(ptrType), objType)); } def newPtrAtRef(layoutType: Type, ptrType: Type) -> Operator { var tt = [layoutType]; - return newOp0(Opcode.PtrAtRef, tt, tt, ptrType); + return newOp0(Opcode.PtrAtRef, tt, tt, ptrType) + .setOp2(Opcode2.PtrAtRef(PointerType.!(ptrType), layoutType)); } def newPtrAtComponentField(spec: IrSpec, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], TypeUtil.NO_TYPES, ptrType); + return newOp0(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], TypeUtil.NO_TYPES, ptrType) + .setOp2(Opcode2.PtrAtComponentField(PointerType.!(ptrType), spec)); } def newPtrAtObjectField(spec: IrSpec, ptrType: Type) -> Operator { var tt = [spec.receiver]; - return newOp0(Opcode.PtrAtObjectField(spec.asField()), tt, tt, ptrType); + return newOp0(Opcode.PtrAtObjectField(spec.asField()), tt, tt, ptrType) + .setOp2(Opcode2.PtrAtObjectField(PointerType.!(ptrType), spec)); } def newPtrAtRefLayoutField(refType: Type, offset: int, ptrType: Type) -> Operator { var ta = [refType]; - return newOp0(Opcode.PtrAtRefLayoutField(offset), ta, ta, ptrType); + return newOp0(Opcode.PtrAtRefLayoutField(offset), ta, ta, ptrType) + .setOp2(Opcode2.PtrAtRefLayoutField(RefType.!(refType), PointerType.!(ptrType), offset)); } def newPtrAtUnboxedObjectField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; @@ -492,76 +598,94 @@ component V3Op { return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType); } def newPtrCmpSwp(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], [ptrType, valueType, valueType], type_z); + return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], [ptrType, valueType, valueType], type_z) + .setOp2(Opcode2.PtrCmpSwp(PointerType.!(ptrType), valueType)); } def newPtrLoad(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrLoad, [ptrType, valueType], [ptrType], valueType); + return newOp0(Opcode.PtrLoad, [ptrType, valueType], [ptrType], valueType) + .setOp2(Opcode2.PtrLoad(ptrType, valueType)); } def newPtrStore(ptrType: Type, valueType: Type) -> Operator { var tt = [ptrType, valueType]; - return newOp0(Opcode.PtrStore, tt, tt, type_v); + return newOp0(Opcode.PtrStore, tt, tt, type_v) + .setOp2(Opcode2.PtrStore(ptrType, valueType)); } def newPtrAddRangeStart(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAddRangeStart, [ptrType], [ptrType, type_rs], ptrType); + return newOp0(Opcode.PtrAddRangeStart, [ptrType], [ptrType, type_rs], ptrType) + .setOp2(Opcode2.PtrAddRangeStart(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newCallerIp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerIp, TypeUtil.NO_TYPES, arr_v, ptrType); + return newOp0(Opcode.CallerIp, TypeUtil.NO_TYPES, arr_v, ptrType) + .setOp2(Opcode2.CallerIp(PointerType.!(ptrType))); } def newCallerSp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerSp, TypeUtil.NO_TYPES, arr_v, ptrType); + return newOp0(Opcode.CallerSp, TypeUtil.NO_TYPES, arr_v, ptrType) + .setOp2(Opcode2.CallerSp(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newAlloc(ptrType: Type) -> Operator { - return newOp0(Opcode.Alloc, [ptrType], arr_i, ptrType); + return newOp0(Opcode.Alloc, [ptrType], arr_i, ptrType) + .setOp2(Opcode2.Alloc(ptrType)); + } //---------------------------------------------------------------------------- def newCallAddress(rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); // TODO: setOp2 } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { - return Operator.new(Opcode.CallKernel(kernel), typeParams, sig); + return Operator.new(Opcode.CallKernel(kernel), typeParams, sig); // TODO: setOp2 } //---------------------------------------------------------------------------- def newRefLayoutAt(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutAt, at, [V3.arrayByteType, Int.TYPE], refType); + return newOp0(Opcode.RefLayoutAt, at, [V3.arrayByteType, Int.TYPE], refType) + .setOp2(Opcode2.RefLayoutAt(refType)); } def newRefLayoutOf(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutOf, at, [V3.rangeByteType], refType); + return newOp0(Opcode.RefLayoutOf, at, [V3.rangeByteType], refType) + .setOp2(Opcode2.RefLayoutOf(refType)); } def newRefLayoutIn(refType: RefType, offset: int, result: RefType) -> Operator { var at: Array = [refType, result]; - return newOp0(Opcode.RefLayoutIn(offset), at, [refType], result); + return newOp0(Opcode.RefLayoutIn(offset), at, [refType], result) + .setOp2(Opcode2.RefLayoutIn(refType, offset, result)); } def newRefLayoutGetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { - return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], [refType], fieldType); + return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], [refType], fieldType) + .setOp2(Opcode2.RefLayoutGetField(refType, offset, fieldType)); } def newRefLayoutSetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { var at = [refType, fieldType]; - return newOp0(Opcode.RefLayoutSetField(offset, order), at, at, Void.TYPE); + return newOp0(Opcode.RefLayoutSetField(offset, order), at, at, Void.TYPE) + .setOp2(Opcode2.RefLayoutSetField(refType, offset, fieldType)); } 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); + return newOp0(opcode, [refType, result], [refType, Int.TYPE], result) + .setOp2(Opcode2.RefLayoutAtRepeatedField(refType, offset, scale, max, result)); } 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); + return newOp0(opcode, [refType, fieldType], [refType, Int.TYPE], fieldType) + .setOp2(Opcode2.RefLayoutGetRepeatedField(refType, offset, scale, max, fieldType)); } 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); + return newOp0(opcode, [refType, fieldType], [refType, Int.TYPE, fieldType], Void.TYPE) + .setOp2(Opcode2.RefLayoutSetRepeatedField(refType, offset, scale, max, fieldType)); } 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); + return newOp0(opcode, [fieldType, startType], [V3.arrayByteType, startType], fieldType) + .setOp2(Opcode2.ByteArrayGetField(startType, offset, fieldType)); } 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); + return newOp0(opcode, [fieldType, startType], [V3.arrayByteType, startType, fieldType], Void.TYPE) + .setOp2(Opcode2.ByteArraySetField(startType, offset, fieldType)); } //---------------------------------------------------------------------------- def bestCallVirtual(spec: IrSpec) -> Operator { diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 new file mode 100644 index 000000000..402cf1f3b --- /dev/null +++ b/aeneas/src/core/Operator2.v3 @@ -0,0 +1,354 @@ +// Copyright 2024 Virgil authors. All rights reserved. +// See LICENSE for details of Apache 2.0 license. + +class Operator2(opcode: Opcode2) { + private var openness: Open; // lazily computed open / closed + private var sig_: Signature; + + def sig() -> Signature { + return if(sig_ != null, sig_, makeSig().sig_); + } + + def subst(func: Type -> Type) -> Operator2 { + if (checkOpenness() == Open.CLOSED) return this; + return Operator2.new(Opcodes2.subst(opcode, func)); + } + def checkOpenness() -> Open { + if (openness != Open.UNKNOWN) return openness; + return openness = Opcodes2.checkOpenness(opcode); + } + private def substArray(func: Type -> Type, args: Array) -> Array { + for (i < args.length) { + var t = args[i], nt = func(t); + if (t != nt) { + var nargs = Array.new(args.length); + for (j < i) nargs[j] = args[j]; + nargs[i] = nt; + for (j = i + 1; j < args.length; j++) nargs[j] = func(args[j]); + return nargs; + } + } + return args; + } + private def makeSig() -> this { + match (opcode) { + // Boolean operators + BoolEq => set(TYPE_zz, arr_zz, TYPE_z, arr_z); + BoolAnd => set(TYPE_zz, arr_zz, TYPE_z, arr_z); + BoolOr => set(TYPE_zz, arr_zz, TYPE_z, arr_z); + BoolNot => set(TYPE_z, arr_z, TYPE_z, arr_z); + // Integer arithmetic and conversions + IntEq(t) => set_xx_z(t); + IntAdd(t) => set_xx_x(t); + IntSub(t) => set_xx_x(t); + IntMul(t) => set_xx_x(t); + IntDiv(t) => set_xx_x(t); + IntMod(t) => set_xx_x(t); + IntAnd(t) => set_xx_x(t); + IntOr(t) => set_xx_x(t); + IntXor(t) => set_xx_x(t); + IntShl(t) => set_xx_x(t); + IntSar(t) => set_xx_x(t); + IntShr(t) => set_xx_x(t); + IntLt(t) => set_xx_z(t); + IntLteq(t) => set_xx_z(t); + IntWide(op, p, r) => set_arr(p, r); + // Floating point arithmetic + FloatAdd(t) => set_xx_x(t); + FloatSub(t) => set_xx_x(t); + FloatMul(t) => set_xx_x(t); + FloatDiv(t) => set_xx_x(t); + FloatBitEq(t) => set_xx_z(t); + FloatEq(t) => set_xx_z(t); + FloatNe(t) => set_xx_z(t); + FloatLt(t) => set_xx_z(t); + FloatLteq(t) => set_xx_z(t); + FloatAbs(t) => set_x_x(t); + FloatCeil(t) => set_x_x(t); + FloatFloor(t) => set_x_x(t); + FloatSqrt(t) => set_x_x(t); + // Integer casts and conversions + IntCastF(to, from) => set_x_y(from, to); + IntQueryF(to, from) => set_x_z(from); + IntViewI(to, from) => set_x_y(from, to); + IntViewF(to, from) => set_x_y(from, to); + IntTruncF(to, from) => set_x_y(from, to); + // Floating point casts and conversions + FloatCastI(to, from) => set_x_y(from, to); + FloatCastD(to, from) => set_x_y(from, to); + FloatQueryI(to, from) => set_x_z(from); + FloatQueryD(to, from) => set_x_z(from); + FloatPromoteI(to, from) => set_x_y(from, to); + FloatPromoteF(to, from) => set_x_y(from, to); + FloatViewI(to, from) => set_x_y(from, to); + FloatRoundI(to, from) => set_x_y(from, to); + FloatRound(t) => set_x_y(t, t); + FloatRoundD(to, from) => set_x_y(from, to); + // Reference equality + RefEq(t) => set_xx_z(t); + // Default value operator + DefaultValue(t) => set(TYPE_v, arr_v, t, [t]); + IntRepCreate(to, from) => set_x_y(from, to); + IntRepView(to, from) => set_x_y(from, to); + // Tuple operations + TupleCreate(t) => { + var paramTypes = Lists.toArray(t.nested); + set(t, paramTypes, t, [t]); + } + TupleGetElem(t, index) => { + var e = Lists.get(t.nested, index); + set(t, [t], e, [e]); + } + // Array operations + ArrayAlloc(t) => set_x_y(Int.TYPE, t); + ArrayInit(t, length) => { + var elemType = t.elementType(); + var paramTypes = Array.new(length); + for (i < paramTypes.length) paramTypes[i] = elemType; + set(Tuple.fromTypeArray(paramTypes), paramTypes, t, [t]); + } + ArrayFill(t) => { + var elemType = t.elementType(); + var paramTypes = [t, elemType]; + set(Tuple.fromTypeArray(paramTypes), paramTypes, t, [t]); + } + ArrayTupleInit(t, elems, length) => { + var elemType = t.elementType(); + var paramTypes = Array.new(elems * length); + var tuple = Tuple.toTypeArray(elemType); + var i = 0; + for (j < length) { + for (k < tuple.length) { + paramTypes[i++] = tuple[k]; + } + } + set(Tuple.fromTypeArray(paramTypes), paramTypes, t, [t]); + } + ArrayGetElem(t, it) => set_arr([t, it], [t.elementType()]); + ArraySetElem(t, it) => set_arr([t, it, t.elementType()], arr_v); + ArrayGetElemElem(t, it, index) => { + var etype = Tuple.elementType(t.elementType(), index); + var paramTypes = [t, it]; + set(Tuple.fromTypeArray(paramTypes), paramTypes, etype, [etype]); + } + ArraySetElemElem(t, it, index) => { + var etype = Tuple.elementType(t.elementType(), index); + var tt = [t, it, etype]; + set(Tuple.fromTypeArray(tt), tt, TYPE_v, arr_v); + } + ArrayGetLength(t) => set_x_y(t, Int.TYPE); + // Range operations + RangeFromTo(t, st, et) => set_arr([t, st, et], [t]); + RangeFromPlus(t, st, lt) => set_arr([t, st, lt], [t]); + RangeGetElem(t, it) => set_arr([t, it], [t.elementType()]); + RangeSetElem(t, it) => set_arr([t, it, t.elementType()], arr_v); + RangeGetLength(t) => set_x_y(t, Int.TYPE); + RangeStartPlusIndex(t, it) => set_arr([TYPE_rs, it], arr_rs); + RangeStartFromPointer(t, pt) => set_arr([pt], arr_rs); + // Normalized Range operations + NormRangeGetElem(t, it) => set_arr([t, TYPE_rs, it], [t.elementType()]); + NormRangeGetElemElem(t, index, it) => set_arr([t, TYPE_rs, it], [Tuple.elementType(t.elementType(), index)]); + NormRangeSetElem(t, it) => set_arr([t, TYPE_rs, it, t.elementType()], arr_v); + NormRangeSetElemElem(t, index, it) => set_arr([t, TYPE_rs, it, Tuple.elementType(t.elementType(), index)], arr_v); + // Component operations + Init(method) => set(TYPE_v, arr_v, TYPE_v, arr_v); + ComponentGetField(field) => set(field.receiver, [field.receiver], field.fieldType, [field.fieldType]); + ComponentSetField(field) => set_arr([field.receiver, field.fieldType], arr_v); + // Class operations + ClassAlloc(spec) => { + var ftype = spec.getBoundType(), p = Function.getParamType(ftype); + set(p, Tuple.toTypeArray(p), spec.receiver, [spec.receiver]); + } + ClassEmptyAlloc(classType, paramTypes) => { + set(Tuple.fromTypeArray(paramTypes), paramTypes, classType, [classType]); + } + ClassGetField(spec) => { + var r = spec.receiver, f = spec.getFieldType(); + set(r, [r], f, Tuple.toTypeArray(f)); + } + ClassInitField(spec) => { + var r = spec.receiver, f = spec.getFieldType(), arr = [r, f]; + set(Tuple.fromTypeArray(arr), arr, TYPE_v, arr_v); + } + ClassSetField(spec) => { + var r = spec.receiver, f = spec.getFieldType(), arr = [r, f]; + set(Tuple.fromTypeArray(arr), arr, TYPE_v, arr_v); + } + ClassGetMethod(spec) => { + var r = spec.receiver, f = spec.getBoundType(); + set_x_y(r, f); + } + ClassGetVirtual(spec) => { + var r = spec.receiver, f = spec.getBoundType(); + set_x_y(r, f); + } + ClassGetSelector(spec) => { + var r = spec.receiver, f = spec.getFuncType(); + set_x_y(r, f); + } + // Variant operations + VariantEq(t) => set_xx_z(t); + VariantAlloc(classType, paramTypes) => { + set(Tuple.fromTypeArray(paramTypes), paramTypes, classType, [classType]); + } + VariantGetTag(t) => set_x_y(t, V3.getVariantTagType(t)); + VariantGetField(spec) => { + var r = spec.receiver, f = spec.getFieldType(); + set(r, [r], f, Tuple.toTypeArray(f)); + } + VariantGetMethod(spec) => { + var r = spec.receiver, f = spec.getBoundType(); + set_x_y(r, f); + } + VariantGetVirtual(spec) => { + var r = spec.receiver, f = spec.getBoundType(); + set_x_y(r, f); + } + VariantGetSelector(spec) => { + var r = spec.receiver, f = spec.getFuncType(); + set_x_y(r, f); + } + // Safety checks + NullCheck(t) => set(t, [t], TYPE_v, arr_v); + BoundsCheck(t) => set_arr([t, TYPE_i], arr_v); + ConditionalThrow(exception) => set(TYPE_z, arr_z, TYPE_v, arr_v); + // Overloaded, polymorphic casts + OverloadedEq(t) => set_xx_z(t); + TypeCast(cast, to, from) => set_x_y(from, to); + TypeQuery(query, to, from) => set_x_z(from); + TypeSubsume(to, from) => set_x_y(from, to); + // Closure and call operations + CallMethod(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallClassMethod(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallClassVirtual(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallClassSelector(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallVariantVirtual(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallVariantSelector(spec) => { + var ftype = FuncType.!(spec.getUnboundType()); + set_ftype(ftype); + } + CallClosure(t) => { + var sig = t.sig(); + set_arr(Arrays.prepend(t, sig.paramTypes), sig.returnTypes); + } + CallFunction(t) => { + var sig = t.sig(), ftype = t.prependParam(AnyRef.TYPE); + set_arr(Arrays.prepend(ftype, sig.paramTypes), sig.returnTypes); + } + CreateClosure(obj, method) => { + set_x_y(obj, method.getBoundType()); + } + ForgeClosure(ptrType, closureType, paramType, resultType) => { + var funcType = Function.newType(paramType, resultType); + set_arr([ptrType, closureType], [funcType]); + } + UnpackClosure(ptrType, closureType, paramType, resultType) => { + var funcType = Function.newType(paramType, resultType); + set_arr([funcType], [ptrType, closureType]); + } + // RefLayout operations + RefLayoutAt(t) => set_arr([V3.arrayByteType, Int.TYPE], [t]); + RefLayoutOf(t) => set_arr([V3.rangeByteType], [t]); + RefLayoutIn(t, offset, rt) => set_x_y(t, rt); + RefLayoutGetField(t, offset, ft) => set_x_y(t, ft); + RefLayoutSetField(t, offset, ft) => set_arr([t, ft], arr_v); + RefLayoutAtRepeatedField(t, offset, scale, max, rt) => set_arr([t, TYPE_i], [rt]); + RefLayoutGetRepeatedField(t, offset, scale, max, ft) => set_arr([t, TYPE_i], [ft]); + RefLayoutSetRepeatedField(t, offset, scale, max, ft) => set_arr([t, TYPE_i, ft], arr_v); + ByteArrayGetField(st, offset, ft) => set_arr([TYPE_ab, st], [ft]); + ByteArraySetField(st, offset, ft) => set_arr([TYPE_ab, st, ft], arr_v); + ForgeRange(ptrType, t) => set_arr([ptrType, TYPE_i], [t]); + // System operations + SystemCall(syscall, paramType, resultType) => set_ftype(FuncType.!(Function.newType(paramType, resultType))); + // Container for VST operations + VstSugar(op, paramTypes, resultType) => set_arr(paramTypes, [resultType]); + // Pointer operations + PtrAdd(t, it) => set_arr([t, it], [t]); + PtrSub(t, it) => set_arr([t, t], [it]); + PtrLt(t) => set_xx_z(t); + PtrLteq(t) => set_xx_z(t); + PtrAtContents(t, at) => set_x_y(at, t); + PtrAtLength(t, arrayType) => set_x_y(arrayType, t); + PtrAtObject(t, objType) => set_x_y(objType, t); + PtrAtRangeElem(t, rangeType, it) => set_arr([rangeType, it], [t]); + PtrAtArrayElem(t, arrayType, it) => set_arr([arrayType, it], [t]); + PtrAtEnd(t, objType) => set_x_y(objType, t); + PtrAtRef(t, refType) => set_x_y(refType, t); + PtrAtComponentField(t, field) => set(TYPE_v, arr_v, t, [t]); + PtrAtObjectField(t, field) => set_x_y(field.receiver, t); + PtrAtRefLayoutField(refType, t, offset) => set_x_y(refType, t); + PtrCmpSwp(t, valType) => set_arr([t, valType, valType], arr_z); + PtrLoad(t, valType) => set_x_y(t, valType); + PtrStore(t, valType) => set_arr([t, valType], arr_v); + PtrAddRangeStart(t) => set_arr([t, TYPE_rs], [t]); + // Get caller instruction pointer or stack pointer + CallerIp(t) => set(TYPE_v, arr_v, t, [t]); + CallerSp(t) => set(TYPE_v, arr_v, t, [t]); + // Allocate raw memory + Alloc(t) => set(TYPE_v, arr_v, t, [t]); + // Call + CallAddress(p, rep) => { + var funcType = rep.machType.nested.head; + set_arr(rep.paramTypes, [Function.getReturnType(funcType)]); + } + CallKernel(kernel, paramType, resultType) => { + set(paramType, Tuple.toTypeArray(paramType), resultType, Tuple.toTypeArray(resultType)); + } + } + } + def isPolymorphic() -> bool { + return checkOpenness() == Open.OPEN; + } + private def set_x_x(x: Type) { + var arr_x = [x]; + set(x, arr_x, x, arr_x); + } + private def set_x_y(x: Type, y: Type) { + set(x, [x], y, [y]); + } + private def set_x_z(x: Type) { + set(x, [x], TYPE_z, arr_z); + } + private def set_xx_x(x: Type) { + set(Tuple.newType(Lists.cons2(x, x)), [x, x], x, [x]); + } + private def set_xx_z(x: Type) { + set(Tuple.newType(Lists.cons2(x, x)), [x, x], TYPE_z, arr_z); + } + private def set_ftype(f: FuncType) { + sig_ = f.sig(); + } + private def set_arr(p: Array, r: Array) { + sig_ = Signature.new(null, p, r); + } + private def set(p: Type, pa: Array, r: Type, ra: Array) { + sig_ = Signature.new(null, pa, ra); + } +} + +def TYPE_v = Void.TYPE; +def TYPE_z = Bool.TYPE; +def TYPE_i = Int.TYPE; +def arr_v: Array = []; +def arr_z: Array = [TYPE_z]; +def arr_zz: Array = [TYPE_z, TYPE_z]; +def TYPE_zz = Tuple.fromTypeArray(arr_zz); +def TYPE_rs = V3Range.START_TYPE; +def arr_rs: Array = [TYPE_rs]; +def TYPE_ab = V3.arrayByteType; + diff --git a/aeneas/src/ir/IrOpMethodBuilder.v3 b/aeneas/src/ir/IrOpMethodBuilder.v3 index 1f838a638..d1e74088d 100644 --- a/aeneas/src/ir/IrOpMethodBuilder.v3 +++ b/aeneas/src/ir/IrOpMethodBuilder.v3 @@ -18,7 +18,7 @@ class IrOpMethodBuilder(prog: Program) { // build SSA params and types def receiver = createGlobalIrClass(); var context = SsaContext.new(compiler, prog); - var meth = createIrMethod(receiver, typeArgs, op.sig); + var meth = createIrMethod(receiver, typeArgs, op.sig()); meth.setFact(Fact.M_INLINE); context.enterMethod(meth); var block = createSsa(context, receiver, meth); @@ -53,26 +53,27 @@ class IrOpMethodBuilder(prog: Program) { return ssa.addApply(null, V3Op.newCreateClosure(spec, closureType), [closure]); } def getClosureType(ic: IrClass, op: Operator, indexMap: Array) -> Type { - var boundTypes: List; + var boundTypes: List, sig = op.sig(); for (i = indexMap.length - 1; i >= 0; i--) { - boundTypes = List.new(op.sig.paramTypes[indexMap[i]], boundTypes); + boundTypes = List.new(sig.paramTypes[indexMap[i]], boundTypes); } return ic.ctype.typeCon.create(boundTypes); } def createClosureMethod(context: SsaContext, ic: IrClass, op: Operator, abstracter: TypeParamAbstracter, indexMap: Array) -> IrMethod { // create parameters and method op = op.subst(abstracter.substitute); - var paramTypes = Lists.toArray(op.sig.getResidualParamTypeList(indexMap)); - var meth = createIrMethod(ic.ctype, abstracter.getDefaultTypeArgs(), Function.siga(paramTypes, op.sig.returnType())); + var sig = op.sig(); + var paramTypes = Lists.toArray(sig.getResidualParamTypeList(indexMap)); + var meth = createIrMethod(ic.ctype, abstracter.getDefaultTypeArgs(), Function.siga(paramTypes, sig.returnType())); meth.facts |= Fact.M_INLINE; context.enterMethod(meth); // build the body of the method var closureType = getClosureType(ic, op, indexMap); var block = createSsa(context, closureType, meth); var receiver: SsaInstr = meth.ssa.params[0]; - var args = Array.new(op.sig.paramTypes.length); + var args = Array.new(sig.paramTypes.length); var ia = 0, ip = 1; - for (i < op.sig.paramTypes.length) { + for (i < sig.paramTypes.length) { if (ia < indexMap.length && i == indexMap[ia]) { // the argument is bound in the closure var spec = IrSpec.new(closureType, [closureType], ic.fields[ia]); diff --git a/aeneas/src/ir/PartialSpecialization.v3 b/aeneas/src/ir/PartialSpecialization.v3 index 0d552daf1..11b3bb9d0 100644 --- a/aeneas/src/ir/PartialSpecialization.v3 +++ b/aeneas/src/ir/PartialSpecialization.v3 @@ -207,14 +207,14 @@ class Specializer(ra: ReachabilityAnalyzer, rn: ReachabilityNormalizer) { CallClassVirtual(method) => { sig.putType(this, t0); if (sig.first) sig.addVirtualCall(V3Op.extractIrSpec(exp, method)); - putCallConv(sig, exp.sig); + putCallConv(sig, exp.sig()); } CallMethod(method) => { if (sig.first) sig.addDirectCall(V3Op.extractIrSpec(exp, method)); - putCallConv(sig, exp.sig); + putCallConv(sig, exp.sig()); } CallClosure => { - putCallConv(sig, exp.sig); // TODO XXX: can ignore closure? + putCallConv(sig, exp.sig()); // TODO XXX: can ignore closure? } SystemCall => { sig.putType(this, t0); // full specialization diff --git a/aeneas/src/ir/Reachability.v3 b/aeneas/src/ir/Reachability.v3 index 059e9ef23..1d76be3c6 100644 --- a/aeneas/src/ir/Reachability.v3 +++ b/aeneas/src/ir/Reachability.v3 @@ -862,7 +862,7 @@ class VariantComparatorGen(context: SsaContext, root: IrClass, receiver: IrClass var op = V3Op.newVariantGetTag(root.ctype); var t0 = b.addApply(null, op, [p0]); var t1 = b.addApply(null, op, [p1]); - cmp = b.opEqual(op.sig.returnType(), t0, t1); + cmp = b.opEqual(op.sig().returnType(), t0, t1); } else { cmp = graph.trueConst(); } @@ -891,7 +891,7 @@ class VariantComparatorGen(context: SsaContext, root: IrClass, receiver: IrClass var op = V3Op.newVariantGetTag(root.ctype); var get = b.addApply(null, op, [p1]); get.facts |= Fact.O_NO_NULL_CHECK; - var cmp = b.opEqual(op.sig.returnType(), get, graph.intConst(tag)); + var cmp = b.opEqual(op.sig().returnType(), get, graph.intConst(tag)); var eqTag = SsaBlock.new(); b.addIf(cmp, eqTag, falseBlock); diff --git a/aeneas/src/ir/SsaNormalizer.v3 b/aeneas/src/ir/SsaNormalizer.v3 index cbd2e3953..cfbc201b9 100644 --- a/aeneas/src/ir/SsaNormalizer.v3 +++ b/aeneas/src/ir/SsaNormalizer.v3 @@ -332,7 +332,7 @@ class SsaRaNormalizer extends SsaRebuilder { return mapN(i_old, [nfunc, nobj]); } UnpackClosure => { - var ptrType = op.sig.returnTypes[0]; + var ptrType = op.sig().returnTypes[0]; var nargs = genRefs(args), nfunc = nargs[0]; var nobj = if(nargs.length == 1, newGraph.nullConst(ptrType), nargs[1]); return mapN(i_old, [nfunc, nobj]); @@ -361,7 +361,7 @@ class SsaRaNormalizer extends SsaRebuilder { } var rangeStart: SsaInstr; if (norm.config.NormalizeRange) { - rangeStart = curBlock.opRangeStartPlusIndex(an.oldType, Int.TYPE, i_old.facts, newGraph.arrayRangeStartConst(0, an.newType), ai_new[an.size]); + rangeStart = curBlock.opRangeStartPlusIndex(V3.rangeByteType, Int.TYPE, i_old.facts, newGraph.arrayRangeStartConst(0, an.newType), ai_new[an.size]); } else { rangeStart = ai_new[an.size]; } @@ -384,7 +384,7 @@ class SsaRaNormalizer extends SsaRebuilder { var ai_new = genRefs(i_old.inputs); var array = ai_new[0], start = ai_new[an.size]; ai_new[an.size] = if(norm.config.NormalizeRange, - curBlock.opRangeStartPlusIndex(an.oldType, Int.TYPE, i_old.facts, start, newGraph.intConst(offset)), + curBlock.opRangeStartPlusIndex(V3.rangeByteType, Int.TYPE, i_old.facts, start, newGraph.intConst(offset)), curBlock.opIntAdd(start, newGraph.intConst(offset))); return mapN(i_old, ai_new); } @@ -441,7 +441,7 @@ class SsaRaNormalizer extends SsaRebuilder { } var result = SsaInstr.!(newGraph.intConst(0)); start = if(norm.config.NormalizeRange, - curBlock.opRangeStartPlusIndex(rn.sub[0], Int.TYPE, i_old.facts, start, curBlock.opIntMul(index, newGraph.intConst(scale))), + curBlock.opRangeStartPlusIndex(V3.rangeByteType, Int.TYPE, i_old.facts, start, curBlock.opIntMul(index, newGraph.intConst(scale))), curBlock.opIntAdd(start, curBlock.opIntMul(index, newGraph.intConst(scale))) ); var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; @@ -469,7 +469,7 @@ class SsaRaNormalizer extends SsaRebuilder { curBlock.opConditionalThrow(V3Exception.BoundsCheck, oob); } start = if(norm.config.NormalizeRange, - curBlock.opRangeStartPlusIndex(rn.sub[0], Int.TYPE, i_old.facts, start, curBlock.opIntMul(index, newGraph.intConst(scale))), + curBlock.opRangeStartPlusIndex(V3.rangeByteType, Int.TYPE, i_old.facts, start, curBlock.opIntMul(index, newGraph.intConst(scale))), curBlock.opIntAdd(start, curBlock.opIntMul(index, newGraph.intConst(scale))) ); var facts: Fact.set = Fact.O_NO_BOUNDS_CHECK; @@ -489,7 +489,7 @@ class SsaRaNormalizer extends SsaRebuilder { var rn = RangeNorm.!(normTypeArg(op, 0)); var ai_new = genRefs(args); var narr = ai_new[0], start = ai_new[rn.startIndex()]; - var arrayType = ArrayType.!(rn.sub[0]), ptrType = op.sig.returnType(); + var arrayType = ArrayType.!(rn.sub[0]), ptrType = op.sig().returnType(); var op = if(norm.config.NormalizeRange, V3Op.newPtrAddRangeStart(ptrType), V3Op.newPtrAtArrayElem(arrayType, norm.config.RangeStartType, ptrType)); var i_new = curBlock.addApply(curBlock.source, op, [narr, start]); i_new.facts |= Fact.O_NO_BOUNDS_CHECK; @@ -501,14 +501,14 @@ class SsaRaNormalizer extends SsaRebuilder { var ai_new = genRefs(args); var narr = ai_new[0], start = ai_new[rn.startIndex()], length = ai_new[rn.lengthIndex()], index = ai_new[rn.lengthIndex() + 1]; - var arrayType = ArrayType.!(rn.sub[0]), ptrType = op.sig.returnType(); + var arrayType = ArrayType.!(rn.sub[0]), ptrType = op.sig().returnType(); if (context.compiler.boundsCheck(i_old.facts)) { var c1 = curBlock.opU32LtEq(length, index); curBlock.opConditionalThrow(V3Exception.BoundsCheck, c1); } var i_new: SsaInstr; if (norm.config.NormalizeRange) { - var nstart = curBlock.opRangeStartPlusIndex(rn.sub[0], Int.TYPE, i_old.facts, start, index); + var nstart = curBlock.opRangeStartPlusIndex(rn.getRangeType(), Int.TYPE, i_old.facts, start, index); var op = V3Op.newPtrAddRangeStart(ptrType); i_new = curBlock.addApply(curBlock.source, op, [narr, nstart]); } else { @@ -523,7 +523,7 @@ class SsaRaNormalizer extends SsaRebuilder { PtrAtRef => { if (norm.config.NormalizeRange) { var ai_new = genRefs(args); - var ptrType = op.sig.returnType(); + var ptrType = op.sig().returnType(); var op = V3Op.newPtrAddRangeStart(ptrType); var i_new = curBlock.addApply(curBlock.source, op, ai_new); map1(i_old, i_new); @@ -543,7 +543,7 @@ class SsaRaNormalizer extends SsaRebuilder { } var ft = nf[0].asField().fieldType; var i_new = curBlock.addApply(curBlock.source, - V3Op.newPtrAtObjectField(nf[0], i_old.op.sig.returnType()), [receiver]); + V3Op.newPtrAtObjectField(nf[0], i_old.op.sig().returnType()), [receiver]); map1(i_old, i_new); } PtrAtComponentField(field) => { @@ -557,13 +557,13 @@ class SsaRaNormalizer extends SsaRebuilder { } var ft = nf[0].asField().fieldType; var i_new = curBlock.addApply(curBlock.source, - V3Op.newPtrAtComponentField(nf[0], i_old.op.sig.returnType()), Ssa.NO_INSTRS); + V3Op.newPtrAtComponentField(nf[0], i_old.op.sig().returnType()), Ssa.NO_INSTRS); map1(i_old, i_new); } PtrAtRefLayoutField(offset) => { if (norm.config.NormalizeRange) { var ai_new = genRefs(args); - var ptrType = op.sig.returnType(); + var ptrType = op.sig().returnType(); var op = V3Op.newPtrAddRangeStart(ptrType); var start = curBlock.addApply(curBlock.source, op, ai_new); var pt = PointerType.!(start.getType()); @@ -582,7 +582,7 @@ class SsaRaNormalizer extends SsaRebuilder { } SystemCall(syscall) => { // normalize a syscall operator - var ptn = normType(Tuple.fromTypeArray(op.sig.paramTypes)); + var ptn = normType(Tuple.fromTypeArray(op.sig().paramTypes)); var paramTypes = Tuple.toTypeArray(ptn.newType); var returnType = normReturnType(op); var newOp = V3Op.newSystemCall(syscall, paramTypes, returnType.newType); @@ -640,7 +640,7 @@ class SsaRaNormalizer extends SsaRebuilder { } mapN(i_old, rvals.extract()); } else { - var tn = normType(i_old.op.sig.returnType()); + var tn = normType(i_old.op.sig().returnType()); mapNorm(i_old, call, tn); } return call; @@ -800,22 +800,22 @@ class SsaRaNormalizer extends SsaRebuilder { def throwTypeCheckException() { curBlock.addThrow(curBlock.source, V3Exception.TypeCheck); } - def normTypeCastRec(ai_old: Array, offset: int, atn: TypeNorm, rtn: TypeNorm, result: Vector) { + def normTypeCastRec(ai_new: Array, offset: int, atn: TypeNorm, rtn: TypeNorm, result: Vector) { match (TypeSystem.newTypeCast(atn.oldType, rtn.oldType)) { TRUE => { - for (i < rtn.size) result.put(ai_old[offset + i]); + for (i < rtn.size) result.put(ai_new[offset + i]); return; } SUBSUME => { - if (atn.sub == null) result.put(curBlock.opTypeSubsume(atn.newType, rtn.newType, ai_old[offset])); - else for (i < rtn.size) result.put(curBlock.opTypeSubsume(atn.sub[i], rtn.sub[i], ai_old[offset + i])); + if (atn.sub == null) result.put(curBlock.opTypeSubsume(atn.newType, rtn.newType, ai_new[offset])); + else for (i < rtn.size) result.put(curBlock.opTypeSubsume(atn.sub[i], rtn.sub[i], ai_new[offset + i])); return; } TUPLE_CAST => { var tatn = TupleNorm.!(atn), trtn = TupleNorm.!(rtn); if (tatn.nested.length != trtn.nested.length) return throwTypeCheckException(); for (i < tatn.nested.length) { - normTypeCastRec(ai_old, offset + tatn.offsets[i], tatn.nested[i], trtn.nested[i], result); + normTypeCastRec(ai_new, offset + tatn.offsets[i], tatn.nested[i], trtn.nested[i], result); } return; } @@ -823,10 +823,10 @@ class SsaRaNormalizer extends SsaRebuilder { VARIANT_CAST => { if (VariantNorm.?(atn) && VariantNorm.?(rtn)) { var avn = VariantNorm.!(atn), rvn = VariantNorm.!(rtn); - var actualTag = normVariantGetTag(avn, ai_old[offset ...]); + var actualTag = normVariantGetTag(avn, ai_new[offset ...]); var expectedTag = rvn.tagValue; curBlock.opIntRangeCheck(1, expectedTag, expectedTag + 1, actualTag); - for (i < avn.size) result.put(ai_old[offset + i]); + for (i < avn.size) result.put(ai_new[offset + i]); return; } // break @@ -838,8 +838,8 @@ class SsaRaNormalizer extends SsaRebuilder { RANGE_PROMOTE_ARRAY => { var an = ArrayNorm.!(atn), arrayType = an.first(); var s = an.size; - for (i < s) result.put(ai_old[offset + i]); - var array = ai_old[offset], len: SsaInstr; + for (i < s) result.put(ai_new[offset + i]); + var array = ai_new[offset], len: SsaInstr; if (norm.config.NormalizeRange && s <= 1) { result.put(newGraph.arrayRangeStartConst(0, an.newType)); @@ -865,9 +865,9 @@ class SsaRaNormalizer extends SsaRebuilder { _ => ; // break } if (atn.size > 1) { - for (i < atn.size) result.put(curBlock.opTypeCast(atn.sub[i], rtn.sub[i], ai_old[offset + i])); + for (i < atn.size) result.put(curBlock.opTypeCast(atn.sub[i], rtn.sub[i], ai_new[offset + i])); } else { - result.put(curBlock.opTypeCast(atn.newType, rtn.newType, ai_old[offset])); + result.put(curBlock.opTypeCast(atn.newType, rtn.newType, ai_new[offset])); } } def normTypeCast(i_old: SsaApplyOp, op: Operator) { @@ -880,7 +880,7 @@ class SsaRaNormalizer extends SsaRebuilder { def normIntViewI(i_old: SsaApplyOp, op: Operator) { map1(i_old, curBlock.opIntViewI(op, genRef1(i_old.inputs[0]))); } - def normTypeQueryRec(ai_old: Array, offset: int, atn: TypeNorm, rtn: TypeNorm, left: SsaInstr) -> SsaInstr { + def normTypeQueryRec(ai_new: Array, offset: int, atn: TypeNorm, rtn: TypeNorm, left: SsaInstr) -> SsaInstr { match (TypeSystem.newTypeQuery(atn.oldType, rtn.oldType)) { TRUE => return left; UNKNOWN_QUERY, FALSE => return newGraph.falseConst(); @@ -888,7 +888,7 @@ class SsaRaNormalizer extends SsaRebuilder { var tatn = TupleNorm.!(atn), trtn = TupleNorm.!(rtn); if (tatn.nested.length != trtn.nested.length) return newGraph.falseConst(); for (i < tatn.nested.length) { - left = normTypeQueryRec(ai_old, offset + tatn.offsets[i], tatn.nested[i], trtn.nested[i], left); + left = normTypeQueryRec(ai_new, offset + tatn.offsets[i], tatn.nested[i], trtn.nested[i], left); } return left; } @@ -897,7 +897,7 @@ class SsaRaNormalizer extends SsaRebuilder { if (VariantNorm.?(atn) && VariantNorm.?(rtn)) { var avn = VariantNorm.!(atn), rvn = VariantNorm.!(rtn); var expectedTag = newGraph.intConst(rvn.tagValue); - var actualTag = normVariantGetTag(avn, ai_old[offset ...]); + var actualTag = normVariantGetTag(avn, ai_new[offset ...]); var check = curBlock.pure(V3Op.newIntEq(avn.tagType()), [actualTag, expectedTag]); return opAnd(left, check); } @@ -906,9 +906,9 @@ class SsaRaNormalizer extends SsaRebuilder { _ => ; // break } if (atn.size > 1) { - for (i < atn.size) left = opAnd(left, curBlock.opTypeQuery(atn.sub[i], rtn.sub[i], ai_old[offset + i])); + for (i < atn.size) left = opAnd(left, curBlock.opTypeQuery(atn.sub[i], rtn.sub[i], ai_new[offset + i])); } else { - left = opAnd(left, curBlock.opTypeQuery(atn.newType, rtn.newType, ai_old[offset])); + left = opAnd(left, curBlock.opTypeQuery(atn.newType, rtn.newType, ai_new[offset])); } return left; } @@ -1042,7 +1042,7 @@ class SsaRaNormalizer extends SsaRebuilder { if (startType.width > 32) start = curBlock.opIntViewI0(startType, rangeLengthType, start); if (norm.config.NormalizeRange && rangeNorm.arrayNorm.size <= 1) { - result[rangeNorm.startIndex()] = curBlock.opRangeStartPlusIndex(rangeNorm.arrayNorm.newType, rangeLengthType, i_old.facts, rangeStart, start); + result[rangeNorm.startIndex()] = curBlock.opRangeStartPlusIndex(rangeNorm.getRangeType(), rangeLengthType, i_old.facts, rangeStart, start); } else { result[rangeNorm.startIndex()] = curBlock.opIntAdd(start, rangeStart); } @@ -1079,7 +1079,7 @@ class SsaRaNormalizer extends SsaRebuilder { for (i < rangeNorm.startIndex()) result[i] = ai_new[i]; if (norm.config.NormalizeRange && rangeNorm.arrayNorm.size <= 1) { - result[rangeNorm.startIndex()] = curBlock.opRangeStartPlusIndex(rangeNorm.arrayNorm.newType, rangeLengthType, i_old.facts, rangeStart, start); + result[rangeNorm.startIndex()] = curBlock.opRangeStartPlusIndex(rangeNorm.getRangeType(), rangeLengthType, i_old.facts, rangeStart, start); } else { result[rangeNorm.startIndex()] = curBlock.opIntAdd(start, rangeStart); } @@ -1159,7 +1159,7 @@ class SsaRaNormalizer extends SsaRebuilder { mapN(i_old, vals); } def normArraySetElem(i_old: SsaApplyOp, op: Operator) { - var atn = normTypeArg(op, 0), rtn = normType(op.sig.paramTypes[2]); + var atn = normTypeArg(op, 0), rtn = normType(op.sig().paramTypes[2]); var indexType = norm.config.ArrayIndexType; var width = rtn.size; var ai_new = genRefs(i_old.inputs); @@ -1189,7 +1189,7 @@ class SsaRaNormalizer extends SsaRebuilder { } } def normRangeSetElem(i_old: SsaApplyOp, op: Operator) { - var rangeNorm = RangeNorm.!(normTypeArg(op, 0)), rtn = normType(op.sig.paramTypes[2]); + var rangeNorm = RangeNorm.!(normTypeArg(op, 0)), rtn = normType(op.sig().paramTypes[2]); var indexType = norm.config.RangeStartType; var ai_new = genRefs(i_old.inputs), width = rtn.size; var start = ai_new[rangeNorm.startIndex()], length = ai_new[rangeNorm.lengthIndex()], index = ai_new[rangeNorm.size]; @@ -1377,9 +1377,9 @@ class SsaRaNormalizer extends SsaRebuilder { var op_out: Operator; match (boxKind) { OBJECT => - op_out = V3Op.newPtrAtObjectField(nf[0], i_old.op.sig.returnType()); + op_out = V3Op.newPtrAtObjectField(nf[0], i_old.op.sig().returnType()); COMPONENT => - op_out = V3Op.newPtrAtComponentField(nf[0], i_old.op.sig.returnType()); + op_out = V3Op.newPtrAtComponentField(nf[0], i_old.op.sig().returnType()); } var new_inputs = if(ai_new.length == 0, Ssa.NO_INSTRS, [ai_new[0]]); var i_new = curBlock.addApply(curBlock.source, op_out, new_inputs); @@ -1595,7 +1595,7 @@ class SsaRaNormalizer extends SsaRebuilder { return normType(op.typeArgs[index]); } private def normReturnType(op: Operator) -> TypeNorm { - return normType(op.sig.returnType()); + return normType(op.sig().returnType()); } private def funcRef(m: IrSpec) -> SsaInstr { return newGraph.valConst(Function.funcRefType(m.getFuncType()), FuncVal.new(m)); diff --git a/aeneas/src/ir/TypeNorm.v3 b/aeneas/src/ir/TypeNorm.v3 index 941e73436..86e9153ca 100644 --- a/aeneas/src/ir/TypeNorm.v3 +++ b/aeneas/src/ir/TypeNorm.v3 @@ -87,10 +87,17 @@ class ArrayNorm extends TypeNorm { // Ranges are normalized to a tuple. This class caches the array norm as well. class RangeNorm extends TypeNorm { def arrayNorm: ArrayNorm; + private var rangeType: RangeType; new(oldType: Type, newType: Type, sub: Array, arrayNorm) super(oldType, newType, sub) { } def startIndex() -> int { return size - 2; } def lengthIndex() -> int { return size - 1; } + def getRangeType() -> RangeType { + if (rangeType != null) return rangeType; + var at = ArrayType.!(arrayNorm.newType); + var typeCon = if(at.writeable, V3Range.RO_TYPECON, V3Range.TYPECON); + return rangeType = RangeType.!(typeCon.create1(at.elementType())); + } } // Tuples are always flattened into multiple scalars. class TupleNorm extends TypeNorm { diff --git a/aeneas/src/jvm/SsaJvmGen.v3 b/aeneas/src/jvm/SsaJvmGen.v3 index 45df3929f..b62732f08 100644 --- a/aeneas/src/jvm/SsaJvmGen.v3 +++ b/aeneas/src/jvm/SsaJvmGen.v3 @@ -154,7 +154,7 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC } RefEq => op = JvmBytecode.IF_ACMPEQ; IntLt => { - var t = i.op.sig.paramTypes[0]; + var t = i.op.sig().paramTypes[0]; match (IntType.!(t).rank) { SUBI32, SUBU32, I32 => op = JvmBytecode.IF_ICMPLT; SUBI64, SUBU64, I64 => { lcmp = true; op = JvmBytecode.IFLT; } @@ -162,7 +162,7 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC } } IntLteq => { - var t = i.op.sig.paramTypes[0]; + var t = i.op.sig().paramTypes[0]; match (IntType.!(t).rank) { SUBI32, SUBU32, I32 => op = JvmBytecode.IF_ICMPLE; SUBI64, SUBU64, I64 => { lcmp = true; op = JvmBytecode.IFLE; } @@ -563,7 +563,7 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC code.invokevirtual(mtype.name, "invoke", jprog.jvmSig(op.typeArgs[0])); } SystemCall(syscall) => { - jprog.invokesystem(code, syscall.name, jprog.jvmSig(op.sig.funcType())); + jprog.invokesystem(code, syscall.name, jprog.jvmSig(op.sig().funcType())); } VariantGetTag => { var b1: int; @@ -669,10 +669,10 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC code.cur_stack = height; } def emitShift(i: SsaApplyOp, op: Operator) { - var t = op.sig.returnType(), tt = IntType.!(t); + var t = op.sig().returnType(), tt = IntType.!(t); var left = Opcode.IntShl.?(op.opcode); var sar = Opcode.IntSar.?(op.opcode); - var wide = IntType.!(op.sig.paramTypes[1]).width > 32; // TODO: can we use {tt} here? + var wide = IntType.!(op.sig().paramTypes[1]).width > 32; // TODO: can we use {tt} here? if (Opcode.IntShr.?(op.opcode) && !i.input0().facts.V_NON_NEGATIVE) { if (tt.width < 32) { code.swap(); @@ -702,13 +702,13 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC emitIntTrunc(tt); } def emitIntBinop(i: SsaApplyOp, iop: byte, lop: byte, trunc: bool) { - var tt = IntType.!(i.op.sig.returnType()); + var tt = IntType.!(i.op.sig().returnType()); if (tt.width <= 32) code.binop(iop); else code.lbinop(lop); if (trunc) emitIntTrunc(tt); } def emitIntDiv(i: SsaApplyOp) { - var tt = IntType.!(i.op.sig.returnType()); + var tt = IntType.!(i.op.sig().returnType()); var isDiv = Opcode.IntDiv.?(i.op.opcode); match (tt.rank) { U32 => { @@ -994,7 +994,7 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC else code.fconst(0); } def emitIntViewI(i: SsaApplyOp) { - var ft = IntType.!(i.op.sig.paramTypes[0]), tt = IntType.!(i.op.sig.returnType()); + var ft = IntType.!(i.op.sig().paramTypes[0]), tt = IntType.!(i.op.sig().returnType()); if (TypeSystem.isIntToLong(ft, tt)) { code.i2l(); if (!ft.signed) { @@ -1016,7 +1016,7 @@ class SsaJvmGen(jprog: JvmProgram, context: SsaContext, jsig: JvmSig, code: JvmC } } def emitIntCmp(i: SsaApplyOp, iop: byte, lop: byte, isysMethName: string, lsysMethName: string) { - var tt = IntType.!(i.op.sig.paramTypes[0]); + var tt = IntType.!(i.op.sig().paramTypes[0]); if (tt.width > 32) { // XXX: inline 64-bit unsigned compare? if (tt.rank == IntRank.U64) return jprog.invokesystem(code, lsysMethName, JvmTypes.SIG_LONG_LONG_INT); diff --git a/aeneas/src/mach/MachBackend.v3 b/aeneas/src/mach/MachBackend.v3 index 23c09abd9..7ea709846 100644 --- a/aeneas/src/mach/MachBackend.v3 +++ b/aeneas/src/mach/MachBackend.v3 @@ -1017,7 +1017,7 @@ class SsaMachGen(context: SsaContext, mach: MachProgram, regSet: MachRegSet, w: emitN(ArchInstrs.ARCH_RET); } def getProjections(i: SsaApplyOp) -> Array { - var t = i.op.sig.returnType(); + var t = i.op.sig().returnType(); match (t.typeCon.kind) { VOID => return Ssa.NO_INSTRS; TUPLE => ; // fall through to below diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index b3db1101e..5302e5725 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -459,7 +459,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo IntQueryF => return genIntQueryF(i_old); IntViewF(isDouble) => { // identity, except for wide integer types - var itt = IntType.!(i_old.op.sig.returnType()); + var itt = IntType.!(i_old.op.sig().returnType()); var tn = normIntType(itt); var results = wideOutputs(i_old.op, tn, [i_old.input0()], Facts.NONE); return mapN(i_old, results); @@ -543,11 +543,11 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo } VariantGetTag => { var i_obj = normRef1(i_old.inputs[0]); - i_new = genIfNull(i_old, i_old.op.sig.returnType(), i_obj, null, genVariantGetTag(i_old, _)); + i_new = genIfNull(i_old, i_old.op.sig().returnType(), i_obj, null, genVariantGetTag(i_old, _)); } PtrAtLength => { var i_array = normRef1(i_old.inputs[0]); - var i_add = newPtrAdd(i_old.op.sig.returnType()); + var i_add = newPtrAdd(i_old.op.sig().returnType()); var i_offset = context.graph.intConst(mach.getArrayLengthOffset(i_old.op.typeArgs[0])); i_new = apply(i_old.source, i_add, [i_array, i_offset]); } @@ -641,7 +641,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo SystemCall => { var i_new = apply(i_old.source, i_old.op, normRefs(i_old.inputs)); i_new.facts = i_new.facts | i_old.facts; - mapMultiReturn(i_old, i_new, normType(i_old.op.sig.returnType())); + mapMultiReturn(i_old, i_new, normType(i_old.op.sig().returnType())); return; } _ => i_new = normId(i_old); // By default, normalize inputs to other instructions. @@ -684,7 +684,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo return genEqualN(i_old, tn); } def genShiftOp(i_old: SsaApplyOp) { - var op = i_old.op, tt = IntType.!(op.sig.returnType()); + var op = i_old.op, tt = IntType.!(op.sig().returnType()); // Introduce an explicit if-then-else for shift overflow. if (!i_old.facts.O_NO_SHIFT_CHECK) { // XXX: check the config for saturating shifts (e.g. arm32). @@ -808,7 +808,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo if (i_old.checkFact(Fact.O_NO_DIV_CHECK)) return genTruncatingIntOp(i_old); if ((config.ExplicitDivChecks && Opcode.IntDiv.?(i_old.op.opcode)) || (config.ExplicitModChecks && Opcode.IntMod.?(i_old.op.opcode))) { - var tt = IntType.!(i_old.op.sig.returnType()); + var tt = IntType.!(i_old.op.sig().returnType()); if (tt.signed) { var ifc = curBlock.splitForIfCascade(tt); var x = i_old.input0(), y = i_old.input1(); @@ -837,7 +837,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo return genTruncatingIntOp(i_old); } def genTruncatingIntOp(i_old: SsaApplyOp) { - var tt = IntType.!(i_old.op.sig.returnType()); + var tt = IntType.!(i_old.op.sig().returnType()); var tn = normIntType(tt); if (tn == null) { // normal width (i.e. 2 -> 1) operation. @@ -867,13 +867,13 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo curBlock.pt = i_old.next; var arithType = if(arithWidth == mach.intNorm.width, mach.intNorm.word, Int.getType(false, arithWidth)); - var trunc = curBlock.opIntViewI0(arithType, i_old.op.sig.returnType(), i_old); + var trunc = curBlock.opIntViewI0(arithType, i_old.op.sig().returnType(), i_old); map1keep(i_old, trunc); trunc.inputs[0].update(i_old); return trunc; } def genParallelIntOp(i_old: SsaApplyOp, infix: IntType -> Operator) { - var tt = IntType.!(i_old.op.sig.returnType()); + var tt = IntType.!(i_old.op.sig().returnType()); if (tt.width <= mach.intNorm.width) { // 2 -> 1 operation. normInputs(i_old); @@ -900,8 +900,8 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo } def genIntViewI(i_old: SsaApplyOp) { var inputs = normRefs(i_old.inputs); - var ft = IntType.!(i_old.op.sig.paramTypes[0]); - var tt = IntType.!(i_old.op.sig.returnType()); + var ft = IntType.!(i_old.op.sig().paramTypes[0]); + var tt = IntType.!(i_old.op.sig().returnType()); if (tt.width > mach.intNorm.width) { // M -> (N > 1) conversion. var ftn = mach.intNorm.makeType(ft); @@ -971,7 +971,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo } def wideOutputs(op: Operator, tn: TypeNorm, inputs: Array, facts: Fact.set) -> Array { if (tn != null) { - var i_new = apply(curBlock.source, V3Op.newIntWide(op, op.sig.paramTypes, tn.newType), inputs); + var i_new = apply(curBlock.source, V3Op.newIntWide(op, op.sig().paramTypes, tn.newType), inputs); i_new.facts |= facts; var vals = Array.new(tn.sub.length); for (i < tn.size) vals[i] = apply(null, V3Op.newTupleGetElem(tn.newType, i), [i_new]); @@ -983,7 +983,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo } } def wideInputs(op: Operator, tn: TypeNorm, inputs: Array, facts: Fact.set) -> SsaInstr { - if (tn != null) op = V3Op.newIntWide(op, tn.sub, op.sig.returnType()); + if (tn != null) op = V3Op.newIntWide(op, tn.sub, op.sig().returnType()); var i_new = apply(curBlock.source, op, inputs); i_new.facts |= facts; return i_new; @@ -1843,7 +1843,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo if (shift > 0) { val = apply(i_old.source, mach.tagType.opShr(), [val, context.graph.intConst(shift)]); } - var conv = V3Op.newIntViewI(mach.tagType, i_old.op.sig.returnType()); + var conv = V3Op.newIntViewI(mach.tagType, i_old.op.sig().returnType()); return apply(i_old.source, conv, [val]); } @@ -1880,7 +1880,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo if (curBlock.end) return; var i_new = apply(i_old.source, if(config.ObjectSystem, i_old.op, V3Op.newCallAddress(funcRep)), args); i_new.facts = i_new.facts | i_old.facts; - var tn = normType(i_old.op.sig.returnType()); + var tn = normType(i_old.op.sig().returnType()); mapMultiReturn(i_old, i_new, tn); } def apply(source: Source, op: Operator, args: Array) -> SsaInstr { @@ -1932,7 +1932,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo } def ptrLoad(vt: Type, p: SsaInstr, offset: int) -> SsaInstr { if (offset != 0) p = ptrAdd(p, context.graph.intConst(offset)); - var i = apply(null, V3Op.newPtrLoad(p.getType(), vt), [p]); + var i = apply(null, V3Op.newPtrLoad(p.getType(), vt), [p]); // TODO: need to translate p.getType() to (data?) pointer i.facts |= Fact.O_NO_NULL_CHECK; // this load won't trap return i; } diff --git a/aeneas/src/mach/Pointer.v3 b/aeneas/src/mach/Pointer.v3 index 64250cce2..14e95ec7c 100644 --- a/aeneas/src/mach/Pointer.v3 +++ b/aeneas/src/mach/Pointer.v3 @@ -46,8 +46,8 @@ class Pointer_OpCache(ptrType: Type, it: IntType) { def opSub = V3Op.newPtrSub(ptrType, it); def opLt = V3Op.newPtrLt(ptrType); def opLteq = V3Op.newPtrLteq(ptrType); - def opGt = V3Op.newVstSugar(VstOperator.Commute(opLt), opLt.typeArgs, opLt.sig.paramTypes, Bool.TYPE); - def opGteq = V3Op.newVstSugar(VstOperator.Commute(opLteq), opLt.typeArgs, opLt.sig.paramTypes, Bool.TYPE); + def opGt = V3Op.newVstSugar(VstOperator.Commute(opLt), opLt.typeArgs, opLt.sig().paramTypes, Bool.TYPE); + def opGteq = V3Op.newVstSugar(VstOperator.Commute(opLteq), opLt.typeArgs, opLt.sig().paramTypes, Bool.TYPE); var rangeType = V3Range.newType(typeParam); var arrayType = V3Array.newType(typeParam); diff --git a/aeneas/src/ssa/Ssa.v3 b/aeneas/src/ssa/Ssa.v3 index ea3100d54..075cd0f96 100644 --- a/aeneas/src/ssa/Ssa.v3 +++ b/aeneas/src/ssa/Ssa.v3 @@ -131,7 +131,7 @@ class SsaApplyOp extends SsaInstr { def op: Operator; new(source, op, a: Array) super(a) { } def optag() -> int { return op.opcode.tag; } - def getType() -> Type { return op.sig.returnType(); } + def getType() -> Type { return op.sig().returnType(); } } class SsaCheckpoint extends SsaInstr { def source: Source; diff --git a/aeneas/src/ssa/SsaBuilder.v3 b/aeneas/src/ssa/SsaBuilder.v3 index 927e5f6ca..117633c42 100644 --- a/aeneas/src/ssa/SsaBuilder.v3 +++ b/aeneas/src/ssa/SsaBuilder.v3 @@ -3,8 +3,9 @@ def checkNoTypeVarsInOp(op: Operator) { for (t in op.typeArgs) checkNoTypeVars(t); - for (t in op.sig.paramTypes) checkNoTypeVars(t); - for (t in op.sig.returnTypes) checkNoTypeVars(t); + var sig = op.sig(); + for (t in sig.paramTypes) checkNoTypeVars(t); + for (t in sig.returnTypes) checkNoTypeVars(t); } def checkNoTypeVars(t: Type) { if (t.hasTypeVars()) return V3.fail("no type vars allowed"); @@ -29,7 +30,7 @@ class SsaBuilder { // General methods. def addApply(source: Source, op: Operator, args: Array) -> SsaInstr { if (Debug.PARANOID) { checkNoTypeVarsInOp(op); checkInputs(args); } - if (end) return unreachable(op.sig.returnType()); + if (end) return unreachable(op.sig().returnType()); var opcode = op.opcode; if (Opcode.VstSugar.?(opcode)) { return at(source).addApplyVst(source, op, Opcode.VstSugar.!(opcode).op, args); @@ -41,7 +42,7 @@ class SsaBuilder { } def addApplyF(op: Operator, args: Array, facts: Fact.set) -> SsaInstr { if (Debug.PARANOID) { checkNoTypeVarsInOp(op); checkInputs(args); } - if (end) return unreachable(op.sig.returnType()); + if (end) return unreachable(op.sig().returnType()); var opcode = op.opcode; if (Opcode.VstSugar.?(opcode)) { return at(source).addApplyVst(source, op, Opcode.VstSugar.!(opcode).op, args); @@ -52,12 +53,12 @@ class SsaBuilder { return i; } def addApplyVst(source: Source, op: Operator, vst: VstOperator, args: Array) -> SsaInstr { - var pt = op.sig.paramTypes; + var pt = op.sig().paramTypes; if (args.length != pt.length) args = normalizeArgs(pt, args); match (vst) { Nop => return args[0]; - TypeCast => return opTypeCast(op.typeArgs[0], op.typeArgs[1], args[0]); - TypeQuery => return opTypeQuery(op.typeArgs[0], op.typeArgs[1], args[0]); + TypeCast => return opTypeCast(op.typeArgs[0], op.typeArgs[1], if(args.length == 0, graph.nop(), args[0])); + TypeQuery => return opTypeQuery(op.typeArgs[0], op.typeArgs[1], if(args.length == 0, graph.nop(), args[0])); NotEqual => return opBoolNot(opEqual(pt[0], args[0], args[1])); BoolAndAnd => return opBoolAnd0(args[0], args[1]); // laziness handled in VstSsaGen BoolOrOr => return opBoolOr0(args[0], args[1]); // laziness handled in VstSsaGen @@ -158,8 +159,8 @@ class SsaBuilder { def opFloatBitField(op: Operator, ft: FloatType, shift: byte, plus: int, x: SsaInstr) -> SsaInstr { var viewOp = if(ft.is64, V3Op.opIntViewF64, V3Op.opIntViewF32); x = pure(viewOp, [x]); - var ivt = IntType.!(viewOp.sig.returnType()); - var itt = IntType.!(op.sig.returnType()); + var ivt = IntType.!(viewOp.sig().returnType()); + var itt = IntType.!(op.sig().returnType()); if (shift > 0) { x = add(ivt.opShr(), [x, graph.intConst(shift)], Fact.O_NO_SHIFT_CHECK); } diff --git a/aeneas/src/ssa/SsaInterpreter.v3 b/aeneas/src/ssa/SsaInterpreter.v3 index 864b8dbe0..f1f27459a 100644 --- a/aeneas/src/ssa/SsaInterpreter.v3 +++ b/aeneas/src/ssa/SsaInterpreter.v3 @@ -69,11 +69,11 @@ class SsaInterpreter(prog: Program, genSsa: (IrSpec, int) -> SsaGraph) { } y: Val => { setVal(i, y); - if (printer != null && !tailCalled) putEqVal(y, x.op.sig.returnType()); + if (printer != null && !tailCalled) putEqVal(y, x.op.sig().returnType()); } null => { setVal(i, null); - if (printer != null && !tailCalled) putEqVal(null, x.op.sig.returnType()); + if (printer != null && !tailCalled) putEqVal(null, x.op.sig().returnType()); } } return n; diff --git a/aeneas/src/ssa/SsaOptimizer.v3 b/aeneas/src/ssa/SsaOptimizer.v3 index 36fe9c887..e8085fc0b 100644 --- a/aeneas/src/ssa/SsaOptimizer.v3 +++ b/aeneas/src/ssa/SsaOptimizer.v3 @@ -175,7 +175,7 @@ class SsaInstrMatcher { // Initializes the match state for an integer binary operation and returns {yint}. def intbinop(i: SsaApplyOp) -> int { binop(i); - inttype = IntType.!(i.op.sig.paramTypes[0]); + inttype = IntType.!(i.op.sig().paramTypes[0]); if (inttype.width <= 32) { wide = false; if (xconst) xint = V3.unboxI32(xval); @@ -632,7 +632,7 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher { IntViewI => { var xval = unop(i); if (xconst) { - var ft = i.op.sig.paramTypes[0], tt = i.op.sig.returnType(); + var ft = i.op.sig().paramTypes[0], tt = i.op.sig().returnType(); return graph.valConst(tt, Eval.doIntView(IntType.!(ft), IntType.!(tt), xval)); } } @@ -682,7 +682,7 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher { } } TypeCast => { - var ft = i.op.sig.paramTypes[0], tt = i.op.sig.returnType(); + var ft = i.op.sig().paramTypes[0], tt = i.op.sig().returnType(); var cast = TypeSystem.newTypeCast(ft, tt); if (i.inputs.length == 0) { // special cast of casting void -> X @@ -954,7 +954,7 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher { var inputs = i.inputs; var vals = Array.new(inputs.length); for (j < inputs.length) vals[j] = SsaConst.!(inputs[j].dest).val; - return graph.valConst(i.op.sig.returnType(), BoxVal.new(null, vals)); + return graph.valConst(i.op.sig().returnType(), BoxVal.new(null, vals)); } TupleGetElem(index) => { var xval = unop(i); @@ -1113,7 +1113,7 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher { return i; } def normSingleArg(op: Operator, args: Array) -> Array { - if (op.sig.paramTypes.length == 1 && args.length > 1) return [args[0]]; + if (op.sig().paramTypes.length == 1 && args.length > 1) return [args[0]]; return args; } def norm_binop(i: SsaApplyOp) -> Val { @@ -1173,7 +1173,7 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher { } def shiftcheck(i: SsaApplyOp, y: SsaInstr) -> SsaInstr { var bound = posIntBound(y); - if (bound >= 0 && bound < IntType.!(i.op.sig.returnType()).width) { + if (bound >= 0 && bound < IntType.!(i.op.sig().returnType()).width) { i.facts |= Fact.O_NO_SHIFT_CHECK; } return i; diff --git a/aeneas/src/ssa/VstSsaGen.v3 b/aeneas/src/ssa/VstSsaGen.v3 index 355f18bc8..a57f924c2 100644 --- a/aeneas/src/ssa/VstSsaGen.v3 +++ b/aeneas/src/ssa/VstSsaGen.v3 @@ -656,7 +656,7 @@ class VstSsaGen extends VstVisitor { return if(expr.post, t.0, t.1); } def genInc(expr: AutoExpr, pre: SsaInstr, env: VstSsaEnv) -> SsaInstr { - var rtype = expr.op.sig.paramTypes[1], val: Val; + var rtype = expr.op.sig().paramTypes[1], val: Val; match (rtype.typeCon.kind) { INT => val = IntType.!(rtype).box(1); FLOAT => val = if(V3.isDouble(rtype), Float.F64_ONE, Float.F32_ONE); @@ -1303,7 +1303,7 @@ class VstSsaEnv extends SsaBuilder { return opCreateClosure(spec, graph.nullReceiver()); } // return a closure value - return graph.valConst(op.sig.funcType(), Closure.new(null, spec)); + return graph.valConst(op.sig().funcType(), Closure.new(null, spec)); } def addClosureCreate(comp: Operator, args: Array, indexMap: Array) -> SsaInstr { var context = SsaContext.new(gen.context.compiler, gen.context.prog); diff --git a/aeneas/src/types/Function.v3 b/aeneas/src/types/Function.v3 index 560f21ed0..834549a57 100644 --- a/aeneas/src/types/Function.v3 +++ b/aeneas/src/types/Function.v3 @@ -70,6 +70,10 @@ class FuncType extends Type { super(hash, typeCon, nested) { } def paramType() -> Type { return nested.head; } def returnType() -> Type { return nested.tail.head; } + def prependParam(t: Type) -> FuncType { + var paramType = Tuple.fromTypeArray(Arrays.prepend(t, sig().paramTypes)); + return FuncType.!(typeCon.create(Lists.cons2(paramType, returnType()))); + } def sig() -> Signature { if (sigcache == null) { var paramTypes = Tuple.toTypeArray(nested.head); diff --git a/aeneas/src/types/Int.v3 b/aeneas/src/types/Int.v3 index edcd31a2e..5b967912d 100644 --- a/aeneas/src/types/Int.v3 +++ b/aeneas/src/types/Int.v3 @@ -7,6 +7,7 @@ component Int { def MAX_WIDTH = 64; private def cache = Array.new(2 * MAX_WIDTH + 1); def TYPE = getType(true, 32); + def U32 = getType(false, 32); def ARRAY_T: Array = [TYPE]; def ZERO = Box.new(0); def ONE = Box.new(1); @@ -84,6 +85,7 @@ enum IntRank { // Utility methods for working with longs. component Long { def TYPE = Int.getType(true, 64); + def U64 = Int.getType(false, 64); def unboxSU(val: Val, signed: bool) -> long { if (val == null) return 0; if (Box.?(val)) return Box.!(val).val; diff --git a/aeneas/src/vst/MethodEnv.v3 b/aeneas/src/vst/MethodEnv.v3 index 385c9f200..cfc3469ca 100644 --- a/aeneas/src/vst/MethodEnv.v3 +++ b/aeneas/src/vst/MethodEnv.v3 @@ -50,7 +50,7 @@ class MethodEnv { var name = expr.ident.name; if (Strings.equal("length", name.image)) { var op = V3Op.newArrayGetLength(arrayType); - return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig.returnType()); + return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig().returnType()); } return VarBinding.None; } @@ -59,7 +59,7 @@ class MethodEnv { var name = expr.ident.name; if (Strings.equal("length", name.image)) { var op = V3Op.newRangeGetLength(rangeType); - return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig.returnType()); + return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig().returnType()); } return VarBinding.None; } @@ -400,7 +400,7 @@ class MethodEnv { if (op == null) return VarBinding.None; var typeArgs = makeTypeArgs("member", expr, typeParams); if (typeArgs != null) op = op.subst(typeArgs.substitute); - return expr.bind(null, VarBinding.Inst(op, N), op.sig.funcType()); + return expr.bind(null, VarBinding.Inst(op, N), op.sig().funcType()); } def lookupFloatTypeMember(expr: VarExpr, ft: FloatType) -> VarBinding { var name = expr.ident.name.image; @@ -410,7 +410,7 @@ class MethodEnv { else if (Strings.equal(name, "exponent")) op = cache.opExponent; else if (Strings.equal(name, "fraction")) op = cache.opFraction; - if (op != null) return expr.bind(null, VarBinding.Inst(op, N), op.sig.funcType()); + if (op != null) return expr.bind(null, VarBinding.Inst(op, N), op.sig().funcType()); var typeParams: List; if (Strings.equal(name, "nan")) { @@ -451,7 +451,7 @@ class MethodEnv { else if (Strings.equal(name, "fraction")) op = cache.opFraction; else return VarBinding.None; - return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig.returnType()); + return expr.bind(expr.expr, VarBinding.Apply(op, N), op.sig().returnType()); } def lookupPointerTypeMember(expr: VarExpr, etype: Type) -> VarBinding { var name = expr.ident.name.image; @@ -486,7 +486,7 @@ class MethodEnv { if (op == null) return VarBinding.None; var typeArgs = makeTypeArgs("member", expr, typeParams); if (typeArgs != null) op = op.subst(typeArgs.substitute); - var resultType = op.sig.getResidualType(INDEX_00); + var resultType = op.sig().getResidualType(INDEX_00); return expr.bind(expr.expr, VarBinding.Partial(op, N), resultType); } def lookupEnumSetTypeMember(expr: VarExpr, etype: Type) -> VarBinding { @@ -499,7 +499,7 @@ class MethodEnv { if (VstEnumCase.?(c)) { // simple membership check var op = V3Op.newVstSugar(VstOperator.EnumSetHas(VstEnumCase.!(c)), TypeUtil.NO_TYPES, [etype], Bool.TYPE); - return expr.bind(null, VarBinding.Inst(op, N), op.sig.funcType()); + return expr.bind(null, VarBinding.Inst(op, N), op.sig().funcType()); } return VarBinding.None; } @@ -518,11 +518,11 @@ class MethodEnv { var name = expr.ident.name.image; if (Strings.equal("at", name)) { var op = V3Op.newRefLayoutAt(refType); - return expr.bind(null, VarBinding.Inst(op, N), op.sig.funcType()); + return expr.bind(null, VarBinding.Inst(op, N), op.sig().funcType()); } if (Strings.equal("of", name)) { var op = V3Op.newRefLayoutOf(refType); - return expr.bind(null, VarBinding.Inst(op, N), op.sig.funcType()); + return expr.bind(null, VarBinding.Inst(op, N), op.sig().funcType()); } match (refType.layoutDecl.memberMap[name]) { x: VstLayoutField => { @@ -768,9 +768,9 @@ class MethodEnv { } def commute(op: Operator) -> Operator { if (op == null) return null; - var pt = op.sig.paramTypes, p0 = pt[0], p1 = pt[1]; + var pt = op.sig().paramTypes, p0 = pt[0], p1 = pt[1]; if (p0 != p1) pt = [p1, p0]; - return V3Op.newVstSugar(VstOperator.Commute(op), op.typeArgs, pt, op.sig.returnType()); + return V3Op.newVstSugar(VstOperator.Commute(op), op.typeArgs, pt, op.sig().returnType()); } def toInfix(name: string) -> InfixOp { // XXX: avoid the need to create an entire ParserState here @@ -833,7 +833,7 @@ class MethodEnv { Inst(comp, typeParams) => { var typeArgs = makeTypeArgs("member", expr, typeParams); var rop = if(typeArgs != null, comp.subst(typeArgs.substitute), comp); - return expr.bind(receiver, VarBinding.Inst(rop, N), rop.sig.funcType()); + return expr.bind(receiver, VarBinding.Inst(rop, N), rop.sig().funcType()); } _ => return VarBinding.None; } @@ -849,10 +849,10 @@ class MethodEnv { return result; } def newCompBinding(expr: VarExpr, comp: Operator) -> VarBinding { - return expr.bind(null, VarBinding.Inst(comp, N), comp.sig.funcType()); + return expr.bind(null, VarBinding.Inst(comp, N), comp.sig().funcType()); } def newApplyCompBinding(expr: VarExpr, receiver: Expr, comp: Operator) -> VarBinding { - return expr.bind(receiver, VarBinding.Apply(comp, N), comp.sig.returnType()); + return expr.bind(receiver, VarBinding.Apply(comp, N), comp.sig().returnType()); } def bindVar(varDecl: VarDecl) { var name = varDecl.token.image; diff --git a/aeneas/src/vst/Verifier.v3 b/aeneas/src/vst/Verifier.v3 index c0bf7652c..f8183f120 100644 --- a/aeneas/src/vst/Verifier.v3 +++ b/aeneas/src/vst/Verifier.v3 @@ -1415,7 +1415,7 @@ class TypeChecker(ERROR: ErrorGen, file: VstFile) extends VstVisitor return t; } expr.op = op; - typeCheckExpr(expr.expr, op.sig.returnType(), "auto expression"); + typeCheckExpr(expr.expr, op.sig().returnType(), "auto expression"); return t; } def visitArray(expr: ArrayExpr, outer: Type) -> Type { @@ -1975,8 +1975,8 @@ class TypeChecker(ERROR: ErrorGen, file: VstFile) extends VstVisitor errAtToken(infix.token).UnresolvedOp(infix.token, ltype, null); return getErrorType(); } - typeCheckExpr(expr.expr, infix.op.sig.paramTypes[1], "compound assignment"); - return infix.op.sig.returnType(); + typeCheckExpr(expr.expr, infix.op.sig().paramTypes[1], "compound assignment"); + return infix.op.sig().returnType(); } else { typeCheckExpr(expr.expr, ltype, "assignment"); return expr.expr.exactType; @@ -1998,11 +1998,11 @@ class TypeChecker(ERROR: ErrorGen, file: VstFile) extends VstVisitor return getErrorType(); } expr.set(op); - if (op.sig == null) return V3.fail("sig null"); - if (op.sig.paramTypes == null) return V3.fail1("paramtypes null %q", op.render); - typeCheckExpr(expr.left, op.sig.paramTypes[0], "infix operator"); - typeCheckExpr(expr.right, op.sig.paramTypes[1], "infix operator"); - return op.sig.returnType(); + if (op.sig() == null) return V3.fail("sig null"); + if (op.sig().paramTypes == null) return V3.fail1("paramtypes null %q", op.render); + typeCheckExpr(expr.left, op.sig().paramTypes[0], "infix operator"); + typeCheckExpr(expr.right, op.sig().paramTypes[1], "infix operator"); + return op.sig().returnType(); } def visitIfExpr(expr: IfExpr, outer: Type) -> Type { var args = expr.exprs.asArray(), what = "if expression", len = args.length; diff --git a/aeneas/src/wasm/WasmCodeGen.v3 b/aeneas/src/wasm/WasmCodeGen.v3 index a81c4b109..3cff07459 100644 --- a/aeneas/src/wasm/WasmCodeGen.v3 +++ b/aeneas/src/wasm/WasmCodeGen.v3 @@ -376,7 +376,7 @@ class WasmCodeGen extends SsaMachGen { emit3(op2.opcode, dfn(i), usev0(t), useIntConst(width)); } def emitIntViewI(i: SsaApplyOp) { - var ft = IntType.!(i.op.sig.paramTypes[0]), tt = IntType.!(i.op.sig.returnType()); + var ft = IntType.!(i.op.sig().paramTypes[0]), tt = IntType.!(i.op.sig().returnType()); if (ft.width > 32) { // Converting from 64-bit match (tt.rank) { diff --git a/aeneas/src/x86/X86CodeGen.v3 b/aeneas/src/x86/X86CodeGen.v3 index d6504fd0e..df1ba5a2a 100644 --- a/aeneas/src/x86/X86CodeGen.v3 +++ b/aeneas/src/x86/X86CodeGen.v3 @@ -293,7 +293,7 @@ class X86CodeGen extends OldCodeGen { useFixed(i.inputs[2].dest, Regs.EDI), useFixed(i.inputs[3].dest, Regs.EDX)); var upper_divisor = i.inputs[3].dest; - var signed = IntType.!(orig.sig.returnType()).signed; + var signed = IntType.!(orig.sig().returnType()).signed; var zeroCheck = !i.facts.O_NO_ZERO_CHECK && rtsrc != null; var small_divisor = upper_divisor.facts.V_ZERO; var large_divisor = !signed && upper_divisor.facts.V_NON_ZERO; @@ -326,7 +326,7 @@ class X86CodeGen extends OldCodeGen { } def genWideIntCastF(i: SsaApplyOp, orig: Operator, v: VReg, isDouble: bool) -> bool { var name: string, m: (X86MacroAssembler, X86Rm, X86Rm, SSERm, bool) -> void; - var signed = IntType.!(orig.sig.returnType()).signed; + var signed = IntType.!(orig.sig().returnType()).signed; if (isDouble) { name = if(signed, "cvt_d2l", "cvt_d2ul"); m = if(signed, X86MacroAssembler.cvt_fp2l, X86MacroAssembler.cvt_fp2ul); @@ -352,7 +352,7 @@ class X86CodeGen extends OldCodeGen { } def genWideIntTruncF(i: SsaApplyOp, orig: Operator, v: VReg, isDouble: bool) -> bool { var name: string, m: (X86MacroAssembler, X86Rm, X86Rm, SSERm, bool) -> void; - var signed = IntType.!(orig.sig.returnType()).signed; + var signed = IntType.!(orig.sig().returnType()).signed; if (isDouble) { name = if(signed, "long_truncd", "ulong_truncd"); m = if(signed, X86MacroAssembler.long_truncfp, X86MacroAssembler.ulong_truncfp); @@ -385,7 +385,7 @@ class X86CodeGen extends OldCodeGen { return false; } def genIntViewI(i: SsaApplyOp, v: VReg) { - var tt = IntType.!(i.op.sig.returnType()); + var tt = IntType.!(i.op.sig().returnType()); if (tt.width == 32) { id(i, makeVar(i.input0())); } else if (!tt.signed) { @@ -529,7 +529,7 @@ class X86CodeGen extends OldCodeGen { // eliminate int -> byte conversions in cmpswp var vop = SsaApplyOp.!(val); if (Opcode.IntViewI.?(vop.op.opcode)) { - var width = PrimType.!(vop.op.sig.returnType()).width; + var width = PrimType.!(vop.op.sig().returnType()).width; if (width == 8) val = vop.input0(); } } @@ -587,7 +587,7 @@ class X86CodeGen extends OldCodeGen { useFixed(i.input0(), Regs.EAX); var bu = useFixed(i.input1(), Regs.NOT_EDX); var zeroCheck = !i.facts.O_NO_ZERO_CHECK; - if (IntType.!(i.op.sig.returnType()).signed) { + if (IntType.!(i.op.sig().returnType()).signed) { var negCheck = !i.facts.O_NO_DIV_CHECK; gen(if(div, "idiv", "imod"), asm_idiv, (i.source, zeroCheck, negCheck, bu, div)); } else { @@ -750,7 +750,7 @@ class X86CodeGen extends OldCodeGen { return X86CmpMatch.new(X86Conds.NZ, i, null, null); } def signedCmp(i: SsaInstr, signed: X86Cond, unsigned: X86Cond) -> X86Cond { - var t = SsaApplyOp.!(i).op.sig.paramTypes[0]; + var t = SsaApplyOp.!(i).op.sig().paramTypes[0]; match (t.typeCon.kind) { POINTER => return unsigned; INT => return if (IntType.!(t).signed, signed, unsigned); diff --git a/aeneas/test/SsaInstrReducerTest.v3 b/aeneas/test/SsaInstrReducerTest.v3 index fb49c9f34..cc8fe9526 100644 --- a/aeneas/test/SsaInstrReducerTest.v3 +++ b/aeneas/test/SsaInstrReducerTest.v3 @@ -1293,8 +1293,6 @@ def testTupleOps(T: SsaInstrReducerTester) { // test fold of TupleCreate T.assertNo(TUPLE_CREATE([K(0), P])); T.assertNo(TUPLE_CREATE([P, K(0)])); - T.assertTK([], TUPLE_CREATE([])); - T.assertTK([Int.box(11)], TUPLE_CREATE([K(11)])); T.assertTK([Int.box(11), Int.box(12)], TUPLE_CREATE([K(11), K(12)])); T.assertTK([Int.box(11), Int.box(12), Int.box(-1333)], TUPLE_CREATE([K(11), K(12), K(-1333)])); diff --git a/doc/aeneas-issues.txt b/doc/aeneas-issues.txt index f84b41110..500ee24e1 100644 --- a/doc/aeneas-issues.txt +++ b/doc/aeneas-issues.txt @@ -41,6 +41,7 @@ ______ ______ __ _ ______ ______ ______ _____ ______ ______ _ _ ______ _ threads fix and turn on inlining and -O3 fold using SSA interpreter + use frame pointer to help with debugging and profiling -- wasm[gc] issues ----- new type representation for structs, arrays, funcs @@ -55,6 +56,8 @@ ______ ______ __ _ ______ ______ ______ _____ ______ ______ _ _ ______ _ encoding of struct, array, func types -- aeneas sucks ----- + command-line option for reserving ELF sections + CiCompiler mechanism to allocate symbols (e.g. handle_INT32_ADD) names for synthesized functions (e.g. Class.==, byte.!) Do in-place specialization and normalization move IntNormalizer into reachability/norm phase instead of mach lowering diff --git a/test/cast/tuple_cast18.v3 b/test/cast/tuple_cast18.v3 new file mode 100644 index 000000000..558c15412 --- /dev/null +++ b/test/cast/tuple_cast18.v3 @@ -0,0 +1,27 @@ +//@execute 0=0; 1=1; 2=2; 3=3; 4=4 +def KB: byte = 44; +def KI: int = 45; +def KL: long = -46; +def KZ: bool = true; + +def f(var a: A) -> A { + if (A.?(KB)) a = A.!(KB); + if (A.?(KI)) a = A.!(KI); + if (A.?(KL)) a = A.!(KL); + var t = (KI, KB); + if (A.?(t)) a = A.!(t); + var w = (KI, KI, KB); + if (A.?(w)) a = A.!(w); + return a; +} +def testBase() { + var a: A, b: B; + f(a); +} +def test() { + testBase<(A, A, B), (B, A, B)>(); +} +def main(a: int) -> int { + test(); + return a; +} \ No newline at end of file diff --git a/test/cast/tuple_cast19.v3 b/test/cast/tuple_cast19.v3 new file mode 100644 index 000000000..a26c3517e --- /dev/null +++ b/test/cast/tuple_cast19.v3 @@ -0,0 +1,21 @@ +//@execute 0=0; 1=1; 2=2; 3=3; 4=4 +def KB: byte = 44; +def KI: int = 45; +def KL: long = -46; +def KZ: bool = true; + +def f(var a: A) -> A { + var t = (KI, KB); + if (A.?(t)) a = A.!(t); + return a; +} +def testBase() { + f(A.default); +} +def test() { + testBase<(A, A, B), (B, A, B)>(); +} +def main(a: int) -> int { + test(); + return a; +} \ No newline at end of file diff --git a/test/cast/tuple_cast20.v3 b/test/cast/tuple_cast20.v3 new file mode 100644 index 000000000..4fd215e9b --- /dev/null +++ b/test/cast/tuple_cast20.v3 @@ -0,0 +1,22 @@ +//@execute 0=0; 1=1; 2=2; 3=3; 4=4 +def KB: byte = 44; +def KI: int = 45; +def KL: long = -46; +def KZ: bool = true; + +def f(var a: A) -> A { + var t = (KI, KB); + if (A.?(t)) a = A.!(t); + return a; +} +def testBase() { + f(A.default); +} +def test() { + var x: (A, A, B); + f<(A, A, B)>(x); +} +def main(a: int) -> int { + test(); + return a; +} \ No newline at end of file diff --git a/test/cast/tuple_cast21.v3 b/test/cast/tuple_cast21.v3 new file mode 100644 index 000000000..d0884221c --- /dev/null +++ b/test/cast/tuple_cast21.v3 @@ -0,0 +1,21 @@ +//@execute 0=0; 1=1; 2=2; 3=3; 4=4 +def KB: byte = 44; +def KI: int = 45; +def KL: long = -46; +def KZ: bool = true; + +def f(var a: A) -> A { + var w = (KI, KI, KB); + if (A.?(w)) a = A.!(w); + return a; +} +def testBase() { + f(A.default); +} +def test() { + testBase<(A, A, B), (B, A, B)>(); +} +def main(a: int) -> int { + test(); + return a; +} \ No newline at end of file diff --git a/test/cast/tuple_cast22.v3 b/test/cast/tuple_cast22.v3 new file mode 100644 index 000000000..6873fe942 --- /dev/null +++ b/test/cast/tuple_cast22.v3 @@ -0,0 +1,13 @@ +//@execute 0=0; 1=1; 2=2; 3=3; 4=4 +def KB: byte = 44; +def KI: int = 45; + +def f(var a: A) -> A { + var w = (KI, KI, KB); + if (A.?(w)) a = A.!(w); + return a; +} +def main(a: int) -> int { + f<(int, int, byte)>(1, 1, 2); + return a; +} diff --git a/test/float/seman/double_members14.v3 b/test/float/seman/double_members14.v3 new file mode 100644 index 000000000..c4f19aba2 --- /dev/null +++ b/test/float/seman/double_members14.v3 @@ -0,0 +1,3 @@ +//@seman +def y: u64; +def w1: double = double.view(y); diff --git a/test/pointer/Pointer_NULL4.v3 b/test/pointer/Pointer_NULL4.v3 new file mode 100644 index 000000000..cd3bb4c08 --- /dev/null +++ b/test/pointer/Pointer_NULL4.v3 @@ -0,0 +1,8 @@ +//@execute = true +def a = "aaaa"; +def main() -> bool { + return at(a) == Pointer.NULL; +} +def at(r: Range) -> Pointer { + return Pointer.NULL; +} diff --git a/test/pointer/Pointer_SIZE1.v3 b/test/pointer/Pointer_SIZE1.v3 index 0187b63a8..f5df63033 100644 --- a/test/pointer/Pointer_SIZE1.v3 +++ b/test/pointer/Pointer_SIZE1.v3 @@ -1,18 +1,16 @@ //@execute = true -component Pointer_SIZE1 { - def a: Array = Array.new(16); - def main() -> bool { - // test pointer size by writing -1 into a buffer - // and checking how many bytes were overwritten - var p = Pointer.atContents(a), NULL: Pointer; - var q = NULL + -1; - p.store(q); - for (i = 0; i < Pointer.SIZE; i++) { - if (a[i] != 0xFF) return false; - } - for (i = Pointer.SIZE; i < a.length; i++) { - if (a[i] != 0) return false; - } - return true; +def a: Array = Array.new(16); +def main() -> bool { + // test pointer size by writing -1 into a buffer + // and checking how many bytes were overwritten + var p = Pointer.atContents(a), NULL: Pointer; + var q = NULL + -1; + p.store(q); + for (i = 0; i < Pointer.SIZE; i++) { + if (a[i] != 0xFF) return false; } + for (i = Pointer.SIZE; i < a.length; i++) { + if (a[i] != 0) return false; + } + return true; } diff --git a/test/range/promote10.v3 b/test/range/promote10.v3 new file mode 100644 index 000000000..0774deb4b --- /dev/null +++ b/test/range/promote10.v3 @@ -0,0 +1,13 @@ +//@execute 0=3; 1=2; 2=1; 3=1; 4=444 +def main(a: int) -> int { + match (a) { + 0 => return length("aaa"); + 1 => return length([0, 1]); + 2 => return length([7777uL]); + 3 => return length([()]); + } + return 444; +} +def length(r: Range) -> int { + return r.length; +} \ No newline at end of file From f61aade531450d57ca974dae0e3ea5e4bf474706 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 2 Jun 2025 14:41:57 +0200 Subject: [PATCH 02/17] Add CallAddress --- aeneas/src/core/Operator.v3 | 5 +++-- aeneas/src/mach/MachLowering.v3 | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 9605751ae..f30f5d3b5 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -630,9 +630,10 @@ component V3Op { } //---------------------------------------------------------------------------- - def newCallAddress(rep: Mach_FuncRep) -> Operator { + def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); // TODO: setOp2 + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) + .setOp2(Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, sig); // TODO: setOp2 diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index 5302e5725..289fb8940 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -1427,7 +1427,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo var methodRef = IrSpec.new(m.receiver, TypeUtil.NO_TYPES, m); var funcRep = mach.funcRep(methodRef); var func = context.graph.valConst(funcRep.machType, mach.getCodeAddress(methodRef)); - var op = V3Op.newCallAddress(funcRep); // XXX: cache + var op = V3Op.newCallAddress(mach.code.ptrType, funcRep); // XXX: cache return apply(source, op, [func, context.graph.nullReceiver(), size]); } else { return apply(source, V3Op.newAlloc(mtype), [size]); @@ -1878,7 +1878,9 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo def call(i_old: SsaApplyOp, funcRep: Mach_FuncRep, args: Array) { if (curBlock.end) return; - var i_new = apply(i_old.source, if(config.ObjectSystem, i_old.op, V3Op.newCallAddress(funcRep)), args); + var i_new = apply(i_old.source, if(config.ObjectSystem, + i_old.op, + V3Op.newCallAddress(mach.code.ptrType, funcRep)), args); i_new.facts = i_new.facts | i_old.facts; var tn = normType(i_old.op.sig().returnType()); mapMultiReturn(i_old, i_new, tn); From c28df07211078b750178333d1a5e079d07a0766f Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 2 Jun 2025 14:55:35 +0200 Subject: [PATCH 03/17] Add CallKernel --- aeneas/src/core/Opcode2.v3 | 8 ++++---- aeneas/src/core/Operator.v3 | 3 ++- aeneas/src/core/Operator2.v3 | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index 3de24cc37..a9dd058ea 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -174,11 +174,11 @@ type Opcode2 { case Alloc(t: Type); // Call case CallAddress(p: PointerType, rep: Mach_FuncRep); - case CallKernel(kernel: Kernel, paramType: Type, resultType: Type); + case CallKernel(kernel: Kernel, paramTypes: Array, resultType: Type); } component Opcodes2 { - def table = Array.new(Opcode2.CallKernel.tag + 1); + def table = Array.new(Opcode2.CallKernel.tag + 1); // XXX: Opcode2.count new() { // shorthand for SSA optimization facts var F = Fact.O_FOLDABLE; @@ -427,7 +427,7 @@ component Opcodes2 { PtrStore(t, valType) => open = isOpenType(valType); Alloc(t) => open = isOpenType(t); CallAddress(p, rep) => ; // TODO - CallKernel(kernel, paramType, resultType) => open = isOpenType2(paramType, resultType); + CallKernel(kernel, paramTypes, resultType) => open = isOpenTypeOrTypes(resultType, paramTypes); _ => ; } return open; @@ -515,7 +515,7 @@ component Opcodes2 { PtrStore(t, valType) => return Opcode2.PtrStore(t, func(valType)); Alloc(t) => return Opcode2.Alloc(func(t)); CallAddress(p, rep) => return opcode; // TODO - CallKernel(kernel, paramType, resultType) => return Opcode2.CallKernel(kernel, func(paramType), func(resultType)); + CallKernel(kernel, paramTypes, resultType) => return Opcode2.CallKernel(kernel, substArray(paramTypes, func), func(resultType)); _ => return opcode; } } diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index f30f5d3b5..6c76a1b0c 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -636,7 +636,8 @@ component V3Op { .setOp2(Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { - return Operator.new(Opcode.CallKernel(kernel), typeParams, sig); // TODO: setOp2 + return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) + .setOp2(Opcode2.CallKernel(kernel, sig.paramTypes, sig.returnType())); } //---------------------------------------------------------------------------- def newRefLayoutAt(refType: RefType) -> Operator { diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index 402cf1f3b..6e4fe0adb 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -306,8 +306,8 @@ class Operator2(opcode: Opcode2) { var funcType = rep.machType.nested.head; set_arr(rep.paramTypes, [Function.getReturnType(funcType)]); } - CallKernel(kernel, paramType, resultType) => { - set(paramType, Tuple.toTypeArray(paramType), resultType, Tuple.toTypeArray(resultType)); + CallKernel(kernel, paramTypes, resultType) => { + set(Tuple.fromTypeArray(paramTypes), paramTypes, resultType, Tuple.toTypeArray(resultType)); } } } From bcecb154daa974cf5ae0c3871fc0ae71cf5085ca Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 00:13:11 +0200 Subject: [PATCH 04/17] Bump heap size --- bin/dev/aeneas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/dev/aeneas b/bin/dev/aeneas index 536ef367f..8b5eb0b4b 100755 --- a/bin/dev/aeneas +++ b/bin/dev/aeneas @@ -8,7 +8,7 @@ VIRGIL_LOC=${VIRGIL_LOC:=$(builtin cd $BIN/.. >/dev/null && builtin pwd)} AENEAS_SYS=${AENEAS_SYS:=${VIRGIL_LOC}/rt/darwin/*.v3} AENEAS_LOC=${AENEAS_LOC:=${VIRGIL_LOC}/aeneas/src} AENEAS_JVM_TUNING=${AENEAS_JVM_TUNING:="-client -Xms900m -Xmx900m -XX:+UseSerialGC"} -V3C_HEAP_SIZE=-heap-size=800m +V3C_HEAP_SIZE=-heap-size=1200m debug=0 CYAN='' From 6a398fd701a25183f185823d00c5514ee31b544a Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 00:44:51 +0200 Subject: [PATCH 05/17] Revert "Add CallAddress" to consider OOM This reverts commit 092135346a1ad0abb96d35090dbcb1bba83f2021. --- aeneas/src/core/Operator.v3 | 5 ++--- aeneas/src/mach/MachLowering.v3 | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 6c76a1b0c..bb1c9332a 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -630,10 +630,9 @@ component V3Op { } //---------------------------------------------------------------------------- - def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { + def newCallAddress(rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) - .setOp2(Opcode2.CallAddress(p, rep)); + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); // TODO: setOp2 } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index 289fb8940..5302e5725 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -1427,7 +1427,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo var methodRef = IrSpec.new(m.receiver, TypeUtil.NO_TYPES, m); var funcRep = mach.funcRep(methodRef); var func = context.graph.valConst(funcRep.machType, mach.getCodeAddress(methodRef)); - var op = V3Op.newCallAddress(mach.code.ptrType, funcRep); // XXX: cache + var op = V3Op.newCallAddress(funcRep); // XXX: cache return apply(source, op, [func, context.graph.nullReceiver(), size]); } else { return apply(source, V3Op.newAlloc(mtype), [size]); @@ -1878,9 +1878,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo def call(i_old: SsaApplyOp, funcRep: Mach_FuncRep, args: Array) { if (curBlock.end) return; - var i_new = apply(i_old.source, if(config.ObjectSystem, - i_old.op, - V3Op.newCallAddress(mach.code.ptrType, funcRep)), args); + var i_new = apply(i_old.source, if(config.ObjectSystem, i_old.op, V3Op.newCallAddress(funcRep)), args); i_new.facts = i_new.facts | i_old.facts; var tn = normType(i_old.op.sig().returnType()); mapMultiReturn(i_old, i_new, tn); From 5cfaeb50d8bcff418ca151ee3cd216e58f57eb44 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 01:06:11 +0200 Subject: [PATCH 06/17] Use setOp2 for CallAddress --- aeneas/src/core/Opcode2.v3 | 14 ++++++++++++-- aeneas/src/core/Operator.v3 | 5 +++-- aeneas/src/core/Operator2.v3 | 3 +-- aeneas/src/mach/MachLowering.v3 | 6 ++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index a9dd058ea..9d9ca7654 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -426,7 +426,11 @@ component Opcodes2 { PtrLoad(t, valType) => open = isOpenType(valType); PtrStore(t, valType) => open = isOpenType(valType); Alloc(t) => open = isOpenType(t); - CallAddress(p, rep) => ; // TODO + CallAddress(p, rep) => { + if (isOpenTypes(rep.paramTypes) != Open.CLOSED) return Open.OPEN; + if (isOpenTypes(rep.returnTypes) != Open.CLOSED) return Open.OPEN; + open = Open.CLOSED; + } CallKernel(kernel, paramTypes, resultType) => open = isOpenTypeOrTypes(resultType, paramTypes); _ => ; } @@ -514,7 +518,13 @@ component Opcodes2 { PtrLoad(t, valType) => return Opcode2.PtrLoad(t, func(valType)); PtrStore(t, valType) => return Opcode2.PtrStore(t, func(valType)); Alloc(t) => return Opcode2.Alloc(func(t)); - CallAddress(p, rep) => return opcode; // TODO + CallAddress(p, rep) => { + var np = substArray(rep.paramTypes, func); + var nr = substArray(rep.returnTypes, func); + if (np == rep.paramTypes && nr == rep.returnTypes) return opcode; + var nrep = Mach_FuncRep.new(rep.origType, rep.machType, np, nr); // TODO: assuming same calling convention + return Opcode2.CallAddress(p, nrep); + } CallKernel(kernel, paramTypes, resultType) => return Opcode2.CallKernel(kernel, substArray(paramTypes, func), func(resultType)); _ => return opcode; } diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index bb1c9332a..6c76a1b0c 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -630,9 +630,10 @@ component V3Op { } //---------------------------------------------------------------------------- - def newCallAddress(rep: Mach_FuncRep) -> Operator { + def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); // TODO: setOp2 + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) + .setOp2(Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index 6e4fe0adb..37ab6e79e 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -303,8 +303,7 @@ class Operator2(opcode: Opcode2) { Alloc(t) => set(TYPE_v, arr_v, t, [t]); // Call CallAddress(p, rep) => { - var funcType = rep.machType.nested.head; - set_arr(rep.paramTypes, [Function.getReturnType(funcType)]); + set_arr(rep.paramTypes, rep.returnTypes); } CallKernel(kernel, paramTypes, resultType) => { set(Tuple.fromTypeArray(paramTypes), paramTypes, resultType, Tuple.toTypeArray(resultType)); diff --git a/aeneas/src/mach/MachLowering.v3 b/aeneas/src/mach/MachLowering.v3 index 5302e5725..289fb8940 100644 --- a/aeneas/src/mach/MachLowering.v3 +++ b/aeneas/src/mach/MachLowering.v3 @@ -1427,7 +1427,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo var methodRef = IrSpec.new(m.receiver, TypeUtil.NO_TYPES, m); var funcRep = mach.funcRep(methodRef); var func = context.graph.valConst(funcRep.machType, mach.getCodeAddress(methodRef)); - var op = V3Op.newCallAddress(funcRep); // XXX: cache + var op = V3Op.newCallAddress(mach.code.ptrType, funcRep); // XXX: cache return apply(source, op, [func, context.graph.nullReceiver(), size]); } else { return apply(source, V3Op.newAlloc(mtype), [size]); @@ -1878,7 +1878,9 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo def call(i_old: SsaApplyOp, funcRep: Mach_FuncRep, args: Array) { if (curBlock.end) return; - var i_new = apply(i_old.source, if(config.ObjectSystem, i_old.op, V3Op.newCallAddress(funcRep)), args); + var i_new = apply(i_old.source, if(config.ObjectSystem, + i_old.op, + V3Op.newCallAddress(mach.code.ptrType, funcRep)), args); i_new.facts = i_new.facts | i_old.facts; var tn = normType(i_old.op.sig().returnType()); mapMultiReturn(i_old, i_new, tn); From abfeb31bd5527dca9e85bd87dea0ed7409538574 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 01:14:26 +0200 Subject: [PATCH 07/17] Bump vaddr_start because Darwin kernel bug? --- aeneas/src/x86-64/X86_64Darwin.v3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aeneas/src/x86-64/X86_64Darwin.v3 b/aeneas/src/x86-64/X86_64Darwin.v3 index a772205bc..f9f8c459c 100644 --- a/aeneas/src/x86-64/X86_64Darwin.v3 +++ b/aeneas/src/x86-64/X86_64Darwin.v3 @@ -27,7 +27,7 @@ def SPACE = AddressSpace.new("mem", false, 64, 8, // Darwin target for x86-64 architecture. Generates an Mach-O binary directly. class X86_64DarwinTarget extends Target { def test: bool; - def DEFAULT_VADDR_START: int = 0x08000000; + def DEFAULT_VADDR_START: int = 0x0A1111000; new(name: string, test) super(name) { } From bd09af653cd992d2f007688ae5f77e71d250a9dc Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 01:16:24 +0200 Subject: [PATCH 08/17] Too many digits --- aeneas/src/x86-64/X86_64Darwin.v3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aeneas/src/x86-64/X86_64Darwin.v3 b/aeneas/src/x86-64/X86_64Darwin.v3 index f9f8c459c..3a98489d9 100644 --- a/aeneas/src/x86-64/X86_64Darwin.v3 +++ b/aeneas/src/x86-64/X86_64Darwin.v3 @@ -27,7 +27,7 @@ def SPACE = AddressSpace.new("mem", false, 64, 8, // Darwin target for x86-64 architecture. Generates an Mach-O binary directly. class X86_64DarwinTarget extends Target { def test: bool; - def DEFAULT_VADDR_START: int = 0x0A1111000; + def DEFAULT_VADDR_START: int = 0x0A111000; new(name: string, test) super(name) { } From a37fad80fa96abbb6a91924ebdc8aed32766a1da Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 11:44:46 +0200 Subject: [PATCH 09/17] Add PtrAtUnboxed...Field --- aeneas/src/core/Opcode2.v3 | 13 +++++++++++++ aeneas/src/core/Operator.v3 | 10 ++++++---- aeneas/src/core/Operator2.v3 | 2 ++ aeneas/src/x86-64/X86_64Darwin.v3 | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index 9d9ca7654..4c353274e 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -163,6 +163,8 @@ type Opcode2 { case PtrAtComponentField(t: PointerType, field: IrSpec); case PtrAtObjectField(t: PointerType, field: IrSpec); case PtrAtRefLayoutField(refType: RefType, t: PointerType, offset: int); + case PtrAtUnboxedObjectField(fields: List, t: PointerType); + case PtrAtUnboxedComponentField(fields: List, t: PointerType); case PtrCmpSwp(t: PointerType, valType: Type); case PtrLoad(t: Type, valType: Type); case PtrStore(t: Type, valType: Type); @@ -422,6 +424,8 @@ component Opcodes2 { PtrAtEnd(t, objType) => open = isOpenType(objType); PtrAtObjectField(t, field) => open = isOpenType(t); PtrAtRefLayoutField(refType, t, offset) => open = isOpenType(t); + PtrAtUnboxedObjectField(fields, ptrType) => open = isOpenSpecs(fields); + PtrAtUnboxedComponentField(fields, ptrType) => open = isOpenSpecs(fields); PtrCmpSwp(t, valType) => open = isOpenType(valType); PtrLoad(t, valType) => open = isOpenType(valType); PtrStore(t, valType) => open = isOpenType(valType); @@ -514,6 +518,8 @@ component Opcodes2 { PtrAtEnd(t, objType) => return Opcode2.PtrAtEnd(t, func(objType)); PtrAtObjectField(t, field) => return Opcode2.PtrAtObjectField(t, substSpec(field, func)); PtrAtRefLayoutField(refType, t, offset) => return Opcode2.PtrAtRefLayoutField(substRefType(refType, func), t, offset); + PtrAtUnboxedObjectField(fields, ptrType) => return Opcode2.PtrAtUnboxedObjectField(Lists.map(fields, substSpec(_, func)), ptrType); // XXX: optimize closed case + PtrAtUnboxedComponentField(fields, ptrType) => return Opcode2.PtrAtUnboxedComponentField(Lists.map(fields, substSpec(_, func)), ptrType); // XXX: optimize closed case PtrCmpSwp(t, valType) => return Opcode2.PtrCmpSwp(t, func(valType)); PtrLoad(t, valType) => return Opcode2.PtrLoad(t, func(valType)); PtrStore(t, valType) => return Opcode2.PtrStore(t, func(valType)); @@ -539,6 +545,13 @@ component Opcodes2 { def isOpenSpec(spec: IrSpec) -> Open { return if(spec.isPolymorphic(), Open.OPEN, Open.CLOSED); } + def isOpenSpecs(specs: List) -> Open { + for (l = specs; l != null; l = l.tail) { + var open = isOpenType(l.head.receiver); + if (open != Open.CLOSED) return open; + } + return Open.CLOSED; + } def isOpenTypeOrSpec(t: Type, spec: IrSpec) -> Open { return if(t.open(), Open.OPEN, isOpenSpec(spec)); } diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 6c76a1b0c..aef6e0999 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -591,11 +591,13 @@ component V3Op { } def newPtrAtUnboxedObjectField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType); + return newOp0(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType) + .setOp2(Opcode2.PtrAtUnboxedObjectField(specs, PointerType.!(ptrType))); } def newPtrAtUnboxedComponentField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType); + return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType) + .setOp2(Opcode2.PtrAtUnboxedComponentField(specs, PointerType.!(ptrType))); } def newPtrCmpSwp(ptrType: Type, valueType: Type) -> Operator { return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], [ptrType, valueType, valueType], type_z) @@ -632,8 +634,8 @@ component V3Op { //---------------------------------------------------------------------------- def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) - .setOp2(Opcode2.CallAddress(p, rep)); + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); +//TODO .setOp2(Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index 37ab6e79e..ccc0fc3e1 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -292,6 +292,8 @@ class Operator2(opcode: Opcode2) { PtrAtComponentField(t, field) => set(TYPE_v, arr_v, t, [t]); PtrAtObjectField(t, field) => set_x_y(field.receiver, t); PtrAtRefLayoutField(refType, t, offset) => set_x_y(refType, t); + PtrAtUnboxedObjectField(fields, ptrType) => set_x_y(fields.head.receiver, ptrType); + PtrAtUnboxedComponentField(fields, ptrType) => set_x_y(fields.head.receiver, ptrType); PtrCmpSwp(t, valType) => set_arr([t, valType, valType], arr_z); PtrLoad(t, valType) => set_x_y(t, valType); PtrStore(t, valType) => set_arr([t, valType], arr_v); diff --git a/aeneas/src/x86-64/X86_64Darwin.v3 b/aeneas/src/x86-64/X86_64Darwin.v3 index 3a98489d9..a772205bc 100644 --- a/aeneas/src/x86-64/X86_64Darwin.v3 +++ b/aeneas/src/x86-64/X86_64Darwin.v3 @@ -27,7 +27,7 @@ def SPACE = AddressSpace.new("mem", false, 64, 8, // Darwin target for x86-64 architecture. Generates an Mach-O binary directly. class X86_64DarwinTarget extends Target { def test: bool; - def DEFAULT_VADDR_START: int = 0x0A111000; + def DEFAULT_VADDR_START: int = 0x08000000; new(name: string, test) super(name) { } From a2e29c1de9eb0a5446a91cac9d26d2aa365cd32e Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 11:49:31 +0200 Subject: [PATCH 10/17] Add CallAddress again --- aeneas/src/core/Operator.v3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index aef6e0999..e67f44534 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -634,8 +634,8 @@ component V3Op { //---------------------------------------------------------------------------- def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)); -//TODO .setOp2(Opcode2.CallAddress(p, rep)); + return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) + .setOp2(Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) From 83af1ebc35e7ece4e8a70b0f36501521b793e69d Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Mon, 2 Jun 2025 15:42:18 +0200 Subject: [PATCH 11/17] Make Opcode2 mandatory --- aeneas/src/core/Opcode2.v3 | 2 +- aeneas/src/core/Operator.v3 | 400 ++++++++++++------------------------ aeneas/src/ssa/VstSsaGen.v3 | 6 +- aeneas/src/types/Float.v3 | 27 ++- aeneas/src/types/Int.v3 | 45 ++-- 5 files changed, 165 insertions(+), 315 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index 4c353274e..1bab7dcbb 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -143,7 +143,7 @@ type Opcode2 { case ByteArraySetField(st: Type, offset: int, ft: Type); case ForgeRange(ptrType: PointerType, t: RangeType); // System operations - case SystemCall(syscall: SystemCall, paramType: Type, resultType: Type); + case SystemCall(syscall: SystemCall, paramType: Type, resultType: Type); // TODO: paramTypes // Container for VST operations case VstSugar(op: VstOperator, paramTypes: Array, resultType: Type); diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index e67f44534..38b6cde32 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -3,9 +3,9 @@ // An operator represents a computation from argument values to a result value // with possible side-effects. -class Operator(opcode: Opcode, typeArgs: Array, sig_: Signature) { +class Operator(opcode: Opcode, typeArgs: Array, opc2: Opcode2) { private var openness: Open; // lazily computed open / closed - var op2: Operator2; + var op2 = Operator2.new(opc2); def checkOpenness() -> Open { // openness is not known. check all type args and operator type @@ -23,11 +23,7 @@ class Operator(opcode: Opcode, typeArgs: Array, sig_: Signature) { } def subst(f: Type -> Type) -> Operator { if (openness == Open.CLOSED) return this; - if (checkOpenness() == Open.OPEN) { - var op = Operator.new(opcode, Arrays.map(typeArgs, f), sig_.subst(f)); - if (op2 != null) op.op2 = this.op2.subst(f); - return op; - } + if (checkOpenness() == Open.OPEN) return Operator.new(opcode, Arrays.map(typeArgs, f), Opcodes2.subst(opc2, f)); return this; } def equals(that: Operator) -> bool { @@ -44,8 +40,7 @@ class Operator(opcode: Opcode, typeArgs: Array, sig_: Signature) { this.op2 = Operator2.new(op); } def sig() -> Signature { - if (op2 != null) return op2.sig(); - return sig_; + return op2.sig(); } } @@ -76,126 +71,103 @@ component V3Op { def sig_zz_z = Signature.new(null, arr_zz, arr_z); def sig_z_z = Signature.new(null, arr_z, arr_z); - private def newOp0(opcode: Opcode, typeArgs: Array, paramTypes: Array, returnType: Type) -> Operator { - return Operator.new(opcode, typeArgs, Function.siga(paramTypes, returnType)); + private def newOp0(opcode: Opcode, typeArgs: Array, opc2: Opcode2) -> Operator { + return Operator.new(opcode, typeArgs, opc2); } //---------------------------------------------------------------------------- - def opBoolEq = Operator.new(Opcode.BoolEq, arr_z, sig_zz_z).setOp2(Opcode2.BoolEq); - def opBoolAnd = Operator.new(Opcode.BoolAnd, arr_v, sig_zz_z).setOp2(Opcode2.BoolAnd); - def opBoolOr = Operator.new(Opcode.BoolOr, arr_v, sig_zz_z).setOp2(Opcode2.BoolOr); - def opBoolNot = Operator.new(Opcode.BoolNot, arr_v, sig_z_z).setOp2(Opcode2.BoolNot); + def opBoolEq = Operator.new(Opcode.BoolEq, arr_z, Opcode2.BoolEq); + def opBoolAnd = Operator.new(Opcode.BoolAnd, arr_v, Opcode2.BoolAnd); + def opBoolOr = Operator.new(Opcode.BoolOr, arr_v, Opcode2.BoolOr); + def opBoolNot = Operator.new(Opcode.BoolNot, arr_v, Opcode2.BoolNot); //---------------------------------------------------------------------------- def newIntEq(t: IntType) -> Operator { - return newOp0(Opcode.IntEq, [t], [t, t], type_z).setOp2(Opcode2.IntEq(t)) - .setOp2(Opcode2.IntEq(t)); + return newOp0(Opcode.IntEq, [t], Opcode2.IntEq(t)); } def newIntWide(op: Operator, normal: Array, result: Type) -> Operator { - return newOp0(Opcode.IntWide(op), arr_v, normal, result) - .setOp2(Opcode2.IntWide(op, normal, Tuple.toTypeArray(result))); + return newOp0(Opcode.IntWide(op), arr_v, Opcode2.IntWide(op, normal, Tuple.toTypeArray(result))); } //---------------------------------------------------------------------------- - def opFloatBitEq32 = newOp0(Opcode.FloatBitEq(false), arr_f, arr_ff, type_z).setOp2(Opcode2.FloatBitEq(Float.FLOAT32)); - def opFloatBitEq64 = newOp0(Opcode.FloatBitEq(true), arr_d, arr_dd, type_z).setOp2(Opcode2.FloatBitEq(Float.FLOAT64)); + def opFloatBitEq32 = newOp0(Opcode.FloatBitEq(false), arr_f, Opcode2.FloatBitEq(Float.FLOAT32)); + def opFloatBitEq64 = newOp0(Opcode.FloatBitEq(true), arr_d, Opcode2.FloatBitEq(Float.FLOAT64)); //---------------------------------------------------------------------------- def newIntCastF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], [ft], tt) - .setOp2(Opcode2.IntCastF(IntType.!(tt), FloatType.!(ft))); + return newOp0(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], Opcode2.IntCastF(IntType.!(tt), FloatType.!(ft))); } def newIntQueryF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], [ft], type_z) - .setOp2(Opcode2.IntQueryF(IntType.!(tt), FloatType.!(ft))); + return newOp0(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], Opcode2.IntQueryF(IntType.!(tt), FloatType.!(ft))); } def newIntViewI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntViewI, [ft, tt], [ft], tt) - .setOp2(Opcode2.IntViewI(IntType.!(tt), IntType.!(ft))); + return newOp0(Opcode.IntViewI, [ft, tt], Opcode2.IntViewI(IntType.!(tt), IntType.!(ft))); } - def opIntViewF32 = newOp0(Opcode.IntViewF(false), arr_f, arr_f, type_u).setOp2(Opcode2.IntViewF(Int.U32, Float.FLOAT32)); - def opIntViewF64 = newOp0(Opcode.IntViewF(true), arr_d, arr_d, Int.getType(false, 64)).setOp2(Opcode2.IntViewF(Long.U64, Float.FLOAT64)); + def opIntViewF32 = newOp0(Opcode.IntViewF(false), arr_f, Opcode2.IntViewF(Int.U32, Float.FLOAT32)); + def opIntViewF64 = newOp0(Opcode.IntViewF(true), arr_d, Opcode2.IntViewF(Long.U64, Float.FLOAT64)); def newIntTruncF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], [ft], tt) - .setOp2(Opcode2.IntTruncF(IntType.!(tt), FloatType.!(ft))); + return newOp0(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], Opcode2.IntTruncF(IntType.!(tt), FloatType.!(ft))); } //---------------------------------------------------------------------------- def newFloatCastI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], [ft], tt) - .setOp2(Opcode2.FloatCastI(FloatType.!(tt), IntType.!(ft))); + return newOp0(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatCastI(FloatType.!(tt), IntType.!(ft))); } - def opFloatCastD = newOp0(Opcode.FloatCastD, arr_d, arr_d, type_f).setOp2(Opcode2.FloatCastD(Float.FLOAT32, Float.FLOAT64)); + def opFloatCastD = newOp0(Opcode.FloatCastD, arr_d, Opcode2.FloatCastD(Float.FLOAT32, Float.FLOAT64)); def newFloatQueryI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], [ft], type_z) - .setOp2(Opcode2.FloatQueryI(FloatType.!(tt), IntType.!(ft))); + return newOp0(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatQueryI(FloatType.!(tt), IntType.!(ft))); } - def opFloatQueryD = newOp0(Opcode.FloatQueryD, arr_d, arr_d, type_z).setOp2(Opcode2.FloatQueryD(Float.FLOAT32, Float.FLOAT64)); + def opFloatQueryD = newOp0(Opcode.FloatQueryD, arr_d, Opcode2.FloatQueryD(Float.FLOAT32, Float.FLOAT64)); def newFloatPromoteI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], [ft], tt) - .setOp2(Opcode2.FloatPromoteI(FloatType.!(tt), IntType.!(ft))); + return newOp0(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatPromoteI(FloatType.!(tt), IntType.!(ft))); } - def opFloatPromoteF = newOp0(Opcode.FloatPromoteF, arr_f, arr_f, type_d).setOp2(Opcode2.FloatPromoteF(Float.FLOAT64, Float.FLOAT32)); + def opFloatPromoteF = newOp0(Opcode.FloatPromoteF, arr_f, Opcode2.FloatPromoteF(Float.FLOAT64, Float.FLOAT32)); def newFloat32ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(false), [ft, type_f], [ft], type_f) - .setOp2(Opcode2.FloatViewI(Float.FLOAT32, ft)); // TODO: ft should be IntType + return newOp0(Opcode.FloatViewI(false), [ft, type_f], Opcode2.FloatViewI(Float.FLOAT32, ft)); // TODO: ft should be IntType } def newFloat64ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(true), [ft, type_d], [ft], type_d) - .setOp2(Opcode2.FloatViewI(Float.FLOAT64, ft)); // TODO: ft should be IntType + return newOp0(Opcode.FloatViewI(true), [ft, type_d], Opcode2.FloatViewI(Float.FLOAT64, ft)); // TODO: ft should be IntType } def newFloatRoundI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], [ft], tt) - .setOp2(Opcode2.FloatRoundI(FloatType.!(tt), ft)); // TODO: ft should be IntType + return newOp0(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatRoundI(FloatType.!(tt), ft)); // TODO: ft should be IntType } def newFloatRound(t: Type) -> Operator { - return newOp0(Opcode.FloatRound(V3.isDouble(t)), [t], [t], t) - .setOp2(Opcode2.FloatRound(FloatType.!(t))); + return newOp0(Opcode.FloatRound(V3.isDouble(t)), [t], Opcode2.FloatRound(FloatType.!(t))); } - def opFloatRoundD = newOp0(Opcode.FloatRoundD, arr_v, arr_d, type_f) - .setOp2(Opcode2.FloatRoundD(Float.FLOAT32, Float.FLOAT64)); + def opFloatRoundD = newOp0(Opcode.FloatRoundD, arr_v, Opcode2.FloatRoundD(Float.FLOAT32, Float.FLOAT64)); //---------------------------------------------------------------------------- def newRefEq(t: Type) -> Operator { - return newOp0(Opcode.RefEq, [t], [t, t], type_z) - .setOp2(Opcode2.RefEq(t)); + return newOp0(Opcode.RefEq, [t], Opcode2.RefEq(t)); } //---------------------------------------------------------------------------- def newDefaultValue(t: Type) -> Operator { - return newOp0(Opcode.DefaultValue, [t], arr_v, t) - .setOp2(Opcode2.DefaultValue(t)); + return newOp0(Opcode.DefaultValue, [t], Opcode2.DefaultValue(t)); } //---------------------------------------------------------------------------- def newIntRepCreate(ft: Type, tt: IntRepType) -> Operator { - return newOp0(Opcode.IntRepCreate, [ft, tt], [ft], tt) - .setOp2(Opcode2.IntRepCreate(tt, ft)); + return newOp0(Opcode.IntRepCreate, [ft, tt], Opcode2.IntRepCreate(tt, ft)); } def newIntRepView(ft: IntRepType, tt: Type) -> Operator { - return newOp0(Opcode.IntRepView, [ft, tt], [ft], tt) - .setOp2(Opcode2.IntRepView(tt, ft)); + return newOp0(Opcode.IntRepView, [ft, tt], Opcode2.IntRepView(tt, ft)); } //---------------------------------------------------------------------------- def newTupleCreate(tupleType: Type) -> Operator { var paramTypes = Lists.toArray(tupleType.nested); - return newOp0(Opcode.TupleCreate(paramTypes.length), [tupleType], paramTypes, tupleType) - .setOp2(Opcode2.TupleCreate(TupleType.!(tupleType))); + return newOp0(Opcode.TupleCreate(paramTypes.length), [tupleType], Opcode2.TupleCreate(TupleType.!(tupleType))); } def newTupleGetElem(tupleType: Type, index: int) -> Operator { var tt = [tupleType]; - return newOp0(Opcode.TupleGetElem(index), tt, tt, Lists.get(tupleType.nested, index)) - .setOp2(Opcode2.TupleGetElem(TupleType.!(tupleType), index)); + return newOp0(Opcode.TupleGetElem(index), tt, Opcode2.TupleGetElem(TupleType.!(tupleType), index)); } //---------------------------------------------------------------------------- def newArrayAlloc(arrayType: Type) -> Operator { - return newOp0(Opcode.ArrayAlloc, [arrayType], arr_i, arrayType) - .setOp2(Opcode2.ArrayAlloc(ArrayType.!(arrayType))); + return newOp0(Opcode.ArrayAlloc, [arrayType], Opcode2.ArrayAlloc(ArrayType.!(arrayType))); } def newArrayFill(arrayType: Type) -> Operator { var elemType = V3Array.elementType(arrayType); - return newOp0(Opcode.ArrayFill, [arrayType], [arrayType, elemType], arrayType) - .setOp2(Opcode2.ArrayFill(ArrayType.!(arrayType))); + return newOp0(Opcode.ArrayFill, [arrayType], Opcode2.ArrayFill(ArrayType.!(arrayType))); } def newArrayInit(arrayType: Type, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); var paramTypes = Array.new(length); for (i < paramTypes.length) paramTypes[i] = elemType; - return newOp0(Opcode.ArrayInit(length), [arrayType], paramTypes, arrayType) - .setOp2(Opcode2.ArrayInit(ArrayType.!(arrayType), length)); + return newOp0(Opcode.ArrayInit(length), [arrayType], Opcode2.ArrayInit(ArrayType.!(arrayType), length)); } def newArrayTupleInit(arrayType: Type, elems: int, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); @@ -207,17 +179,14 @@ component V3Op { paramTypes[i++] = tuple[k]; } } - return newOp0(Opcode.ArrayTupleInit(elems, length), [arrayType], paramTypes, arrayType) - .setOp2(Opcode2.ArrayTupleInit(ArrayType.!(arrayType), elems, length)); + return newOp0(Opcode.ArrayTupleInit(elems, length), [arrayType], Opcode2.ArrayTupleInit(ArrayType.!(arrayType), elems, length)); } def newArrayGetElem(arrayType: Type, indexType: IntType) -> Operator { var elemType = V3Array.elementType(arrayType); var tt = [arrayType, indexType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArrayGetElem, tt, tt, elemType) - .setOp2(Opcode2.ArrayGetElem(x, indexType)); - x: RangeType => return newOp0(Opcode.RangeGetElem, tt, tt, elemType) - .setOp2(Opcode2.RangeGetElem(x, indexType)); + x: ArrayType => return newOp0(Opcode.ArrayGetElem, tt, Opcode2.ArrayGetElem(x, indexType)); + x: RangeType => return newOp0(Opcode.RangeGetElem, tt, Opcode2.RangeGetElem(x, indexType)); _ => return null; // TODO: error } } @@ -225,183 +194,147 @@ component V3Op { var elemType = V3Array.elementType(arrayType); var tt = [arrayType, indexType, elemType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArraySetElem, tt, tt, type_v) - .setOp2(Opcode2.ArraySetElem(x, indexType)); - x: RangeType => return newOp0(Opcode.RangeSetElem, tt, tt, type_v) - .setOp2(Opcode2.RangeSetElem(x, indexType)); + x: ArrayType => return newOp0(Opcode.ArraySetElem, tt, Opcode2.ArraySetElem(x, indexType)); + x: RangeType => return newOp0(Opcode.RangeSetElem, tt, Opcode2.RangeSetElem(x, indexType)); _ => return null; // TODO: error } } def newArrayGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType]; - return newOp0(Opcode.ArrayGetElemElem(index), tt, tt, etype) - .setOp2(Opcode2.ArrayGetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); + return newOp0(Opcode.ArrayGetElemElem(index), tt, Opcode2.ArrayGetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArraySetElemElem(arrayType: Type, indexType: Type, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType, etype]; - return newOp0(Opcode.ArraySetElemElem(index), tt, tt, type_v) - .setOp2(Opcode2.ArraySetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); + return newOp0(Opcode.ArraySetElemElem(index), tt, Opcode2.ArraySetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArrayGetLength(arrayType: Type) -> Operator { var tt = [arrayType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArrayGetLength, tt, tt, type_i) - .setOp2(Opcode2.ArrayGetLength(x)); - x: RangeType => return newOp0(Opcode.RangeGetLength, tt, tt, type_i) - .setOp2(Opcode2.RangeGetLength(x)); + x: ArrayType => return newOp0(Opcode.ArrayGetLength, tt, Opcode2.ArrayGetLength(x)); + x: RangeType => return newOp0(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(x)); _ => return null; // TODO: error } } //---------------------------------------------------------------------------- def newRangeFromPlus(rangeType: Type, startType: Type, lengthType: Type) -> Operator { var tt = [rangeType, startType, lengthType]; - return newOp0(Opcode.RangeFromPlus, tt, tt, rangeType) - .setOp2(Opcode2.RangeFromPlus(RangeType.!(rangeType), IntType.!(startType), IntType.!(lengthType))); + return newOp0(Opcode.RangeFromPlus, tt, Opcode2.RangeFromPlus(RangeType.!(rangeType), IntType.!(startType), IntType.!(lengthType))); } def newRangeFromTo(rangeType: Type, startType: Type, endType: Type) -> Operator { var tt = [rangeType, startType, endType]; - return newOp0(Opcode.RangeFromTo, tt, tt, rangeType) - .setOp2(Opcode2.RangeFromTo(RangeType.!(rangeType), IntType.!(startType), IntType.!(endType))); + return newOp0(Opcode.RangeFromTo, tt, Opcode2.RangeFromTo(RangeType.!(rangeType), IntType.!(startType), IntType.!(endType))); } def newRangeGetLength(rangeType: Type) -> Operator { var tt = [rangeType]; - return newOp0(Opcode.RangeGetLength, tt, tt, type_i) - .setOp2(Opcode2.RangeGetLength(RangeType.!(rangeType))); + return newOp0(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(RangeType.!(rangeType))); } def newRangeStartPlusIndex(rangeType: Type, indexType: IntType) -> Operator { - return newOp0(Opcode.RangeStartPlusIndex, [rangeType, indexType], [type_rs, indexType], type_rs) - .setOp2(Opcode2.RangeStartPlusIndex(RangeType.!(rangeType), indexType)); + return newOp0(Opcode.RangeStartPlusIndex, [rangeType, indexType], Opcode2.RangeStartPlusIndex(RangeType.!(rangeType), indexType)); } def newRangeStartFromPointer(rangeType: Type, ptrType: PointerType) -> Operator { - return newOp0(Opcode.RangeStartFromPointer, [rangeType, ptrType], [ptrType], type_rs) - .setOp2(Opcode2.RangeStartFromPointer(RangeType.!(rangeType), ptrType)); + return newOp0(Opcode.RangeStartFromPointer, [rangeType, ptrType], Opcode2.RangeStartFromPointer(RangeType.!(rangeType), ptrType)); } def newNormRangeGetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeGetElem, [arrayType, indexType], [arrayType, type_rs, indexType], etype) - .setOp2(Opcode2.NormRangeGetElem(ArrayType.!(arrayType), IntType.!(indexType))); + return newOp0(Opcode.NormRangeGetElem, [arrayType, indexType], Opcode2.NormRangeGetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType], etype) - .setOp2(Opcode2.NormRangeGetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); + return newOp0(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], Opcode2.NormRangeGetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } def newNormRangeSetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeSetElem, [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v) - .setOp2(Opcode2.NormRangeSetElem(ArrayType.!(arrayType), IntType.!(indexType))); + return newOp0(Opcode.NormRangeSetElem, [arrayType, indexType], Opcode2.NormRangeSetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeSetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], [arrayType, type_rs, indexType, etype], type_v) - .setOp2(Opcode2.NormRangeSetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); + return newOp0(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], Opcode2.NormRangeSetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } //---------------------------------------------------------------------------- def newInit(meth: IrMethod) -> Operator { - return newOp0(Opcode.Init(meth), TypeUtil.NO_TYPES, TypeUtil.NO_TYPES, meth.receiver) - .setOp2(Opcode2.Init(meth)); + return newOp0(Opcode.Init(meth), TypeUtil.NO_TYPES, Opcode2.Init(meth)); } def newComponentGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ComponentGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) - .setOp2(Opcode2.ComponentGetField(fieldRef.asField())); + return newOp0(Opcode.ComponentGetField(fieldRef.asField()), tt, Opcode2.ComponentGetField(fieldRef.asField())); } def newComponentSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) - .setOp2(Opcode2.ComponentSetField(fieldRef.asField())); + return newOp0(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ComponentSetField(fieldRef.asField())); } //---------------------------------------------------------------------------- def newClassAlloc(newRef: IrSpec) -> Operator { var ftype = newRef.getBoundType(), paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], paramTypes, newRef.receiver) - .setOp2(Opcode2.ClassAlloc(newRef)); + return newOp0(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], Opcode2.ClassAlloc(newRef)); } def newEmptyClassAlloc(classType: Type) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], TypeUtil.NO_TYPES, classType) - .setOp2(Opcode2.ClassEmptyAlloc(ClassType.!(classType), TypeUtil.NO_TYPES)); + return newOp0(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), TypeUtil.NO_TYPES)); } def newEmptyClassAllocP(classType: Type, paramTypes: Array) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], paramTypes, classType) - .setOp2(Opcode2.ClassEmptyAlloc(ClassType.!(classType), paramTypes)); + return newOp0(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), paramTypes)); } def newClassGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ClassGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) - .setOp2(Opcode2.ClassGetField(fieldRef)); + return newOp0(Opcode.ClassGetField(fieldRef.asField()), tt, Opcode2.ClassGetField(fieldRef)); } def newClassInitField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) - .setOp2(Opcode2.ClassInitField(fieldRef)); + return newOp0(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassInitField(fieldRef)); } def newClassSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], [fieldRef.receiver, fieldType], type_v) - .setOp2(Opcode2.ClassSetField(fieldRef)); + return newOp0(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassSetField(fieldRef)); } def newClassGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) - .setOp2(Opcode2.ClassGetMethod(methodRef)); + return newOp0(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, Opcode2.ClassGetMethod(methodRef)); } def newClassGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) - .setOp2(Opcode2.ClassGetVirtual(methodRef)); + return newOp0(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.ClassGetVirtual(methodRef)); } def newClassGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.ClassGetSelector(selector), typeArgs, [methodRef.receiver], methodRef.getFuncType()) - .setOp2(Opcode2.ClassGetSelector(methodRef)); + return newOp0(Opcode.ClassGetSelector(selector), typeArgs, Opcode2.ClassGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newVariantGetTag(vtype: Type) -> Operator { var vt = [vtype]; - return newOp0(Opcode.VariantGetTag, vt, vt, V3.classDecl(vtype).tagType) - .setOp2(Opcode2.VariantGetTag(ClassType.!(vtype))); + return newOp0(Opcode.VariantGetTag, vt, Opcode2.VariantGetTag(ClassType.!(vtype))); } def newVariantAlloc(t: Type, fieldTypes: Array) -> Operator { - return newOp0(Opcode.VariantAlloc, [t], fieldTypes, t) - .setOp2(Opcode2.VariantAlloc(ClassType.!(t), fieldTypes)); + return newOp0(Opcode.VariantAlloc, [t], Opcode2.VariantAlloc(ClassType.!(t), fieldTypes)); } def newVariantGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType()) - .setOp2(Opcode2.VariantGetField(fieldRef)); + return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, Opcode2.VariantGetField(fieldRef)); } def newVariantGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) - .setOp2(Opcode2.VariantGetMethod(methodRef)); + return newOp0(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, Opcode2.VariantGetMethod(methodRef)); } def newVariantGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, [methodRef.receiver], methodRef.getBoundType()) - .setOp2(Opcode2.VariantGetVirtual(methodRef)); + return newOp0(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.VariantGetVirtual(methodRef)); } def newVariantGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.VariantGetSelector(selector), typeArgs, [methodRef.receiver], methodRef.getFuncType()) - .setOp2(Opcode2.VariantGetSelector(methodRef)); + return newOp0(Opcode.VariantGetSelector(selector), typeArgs, Opcode2.VariantGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newNullCheck(rtype: Type) -> Operator { var tt = [rtype]; - return newOp0(Opcode.NullCheck, tt, tt, rtype) - .setOp2(Opcode2.NullCheck(rtype)); + return newOp0(Opcode.NullCheck, tt, Opcode2.NullCheck(rtype)); } def newBoundsCheck(rtype: Type) -> Operator { - return newOp0(Opcode.BoundsCheck, [rtype], [rtype, type_i], type_v) - .setOp2(Opcode2.BoundsCheck(rtype)); + return newOp0(Opcode.BoundsCheck, [rtype], Opcode2.BoundsCheck(rtype)); } def newConditionalThrow(exception: string) -> Operator { - return newOp0(Opcode.ConditionalThrow(exception), arr_v, Bool.ARRAY_T, type_v) - .setOp2(Opcode2.ConditionalThrow(exception)); + return newOp0(Opcode.ConditionalThrow(exception), arr_v, Opcode2.ConditionalThrow(exception)); } //---------------------------------------------------------------------------- def newEqual(t: Type) -> Operator { @@ -421,275 +354,206 @@ component V3Op { VARIANT => { opcode = Opcode.VariantEq; opcode2 = Opcode2.VariantEq(ClassType.!(t)); } _ => { opcode = Opcode.OverloadedEq; opcode2 = Opcode2.OverloadedEq(t); } } - return newOp0(opcode, [t], [t, t], type_z) - .setOp2(opcode2); + return newOp0(opcode, [t], opcode2); } def newTypeCast(f: Type, t: Type) -> Operator { var cast = TypeSystem.newTypeCast(f, t); - return newOp0(Opcode.TypeCast(cast), [f, t], [f], t) - .setOp2(Opcode2.TypeCast(cast, t, f)); + return newOp0(Opcode.TypeCast(cast), [f, t], Opcode2.TypeCast(cast, t, f)); } def newTypeQuery(f: Type, t: Type) -> Operator { var query = TypeSystem.newTypeQuery(f, t); - return newOp0(Opcode.TypeQuery(query), [f, t], [f], type_z) - .setOp2(Opcode2.TypeQuery(query, t, f)); + return newOp0(Opcode.TypeQuery(query), [f, t], Opcode2.TypeQuery(query, t, f)); } def newTypeSubsume(typeFrom: Type, typeTo: Type) -> Operator { - return newOp0(Opcode.TypeSubsume, [typeFrom, typeTo], [typeFrom], typeTo) - .setOp2(Opcode2.TypeSubsume(typeTo, typeFrom)); + return newOp0(Opcode.TypeSubsume, [typeFrom, typeTo], Opcode2.TypeSubsume(typeTo, typeFrom)); } //---------------------------------------------------------------------------- def newCallMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - var ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallMethod(methodRef)); + return newOp0(Opcode.CallMethod(methodRef.asMethod()), typeArgs, Opcode2.CallMethod(methodRef)); } def newCallClassMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallClassMethod(methodRef)); + return newOp0(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, Opcode2.CallClassMethod(methodRef)); } def newCallClassVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallClassVirtual(methodRef)); + return newOp0(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallClassVirtual(methodRef)); } def newCallVariantVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallVariantVirtual(methodRef)); + return newOp0(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallVariantVirtual(methodRef)); } def newCallClassSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallClassSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallClassSelector(methodRef)); + return newOp0(Opcode.CallClassSelector(selector), typeArgs, Opcode2.CallClassSelector(methodRef)); } def newCallVariantSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - var paramTypes = Function.getParamTypeArray(ftype); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallVariantSelector(selector), typeArgs, paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallVariantSelector(methodRef)); + return newOp0(Opcode.CallVariantSelector(selector), typeArgs, Opcode2.CallVariantSelector(methodRef)); } def newCallClosure(ftype: Type) -> Operator { - var fTypes = Function.getParamTypeArray(ftype); - var paramTypes = Arrays.prepend(ftype, fTypes); - return newOp0(Opcode.CallClosure, [ftype], paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallClosure(FuncType.!(ftype))); - } - def newCallClosure2(ftype: Type, paramTypes: Array) -> Operator { - return newOp0(Opcode.CallClosure, [ftype], paramTypes, Function.getReturnType(ftype)); + return newOp0(Opcode.CallClosure, [ftype], Opcode2.CallClosure(FuncType.!(ftype))); } def newCallFunction(ftype: Type) -> Operator { ftype = Function.funcRefType(Function.prependParamType(AnyRef.TYPE, ftype)); if (ftype.typeCon.kind != Kind.FUNCREF) return V3.fail("only function types allowed"); - var paramTypes = Arrays.prepend(ftype, Function.getParamTypeArray(ftype)); - return newOp0(Opcode.CallFunction, [ftype], paramTypes, Function.getReturnType(ftype)) - .setOp2(Opcode2.CallFunction(FuncType.!(ftype))); + return newOp0(Opcode.CallFunction, [ftype], Opcode2.CallFunction(FuncType.!(ftype))); } def newCreateClosure(methodRef: IrSpec, objType: Type) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, [objType], methodRef.getBoundType()) - .setOp2(Opcode2.CreateClosure(objType, methodRef)); + return newOp0(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, Opcode2.CreateClosure(objType, methodRef)); } def newForgeClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { - var funcType = Function.newType(param, result); - return newOp0(Opcode.ForgeClosure, [receiver, param, result], [ptrType, receiver], funcType) - .setOp2(Opcode2.ForgeClosure(PointerType.!(ptrType), receiver, param, result)); + return newOp0(Opcode.ForgeClosure, [receiver, param, result], Opcode2.ForgeClosure(PointerType.!(ptrType), receiver, param, result)); } def newUnpackClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { - var funcType = Function.newType(param, result); - return newOp0(Opcode.UnpackClosure, [receiver, param, result], [funcType], Tuple.newType(Lists.cons2(ptrType, receiver))) - .setOp2(Opcode2.UnpackClosure(PointerType.!(ptrType), receiver, param, result)); + return newOp0(Opcode.UnpackClosure, [receiver, param, result], Opcode2.UnpackClosure(PointerType.!(ptrType), receiver, param, result)); } def newForgeRange(elementType: Type, ptrType: Type) -> Operator { - var rangeType = V3Range.newType(elementType); - return newOp0(Opcode.ForgeRange, [elementType, ptrType], [ptrType, Int.TYPE], rangeType) - .setOp2(Opcode2.ForgeRange(PointerType.!(ptrType), RangeType.!(V3Range.newType(elementType)))); + return newOp0(Opcode.ForgeRange, [elementType, ptrType], Opcode2.ForgeRange(PointerType.!(ptrType), RangeType.!(V3Range.newType(elementType)))); } //---------------------------------------------------------------------------- def newSystemCall(syscall: SystemCall, paramTypes: Array, returnType: Type) -> Operator { - return newOp0(Opcode.SystemCall(syscall), arr_v, paramTypes, returnType) - .setOp2(Opcode2.SystemCall(syscall, Tuple.fromTypeArray(paramTypes), returnType)); + return newOp0(Opcode.SystemCall(syscall), arr_v, Opcode2.SystemCall(syscall, Tuple.fromTypeArray(paramTypes), returnType)); } //---------------------------------------------------------------------------- def newVstSugar(op: VstOperator, typeParams: Array, paramTypes: Array, result: Type) -> Operator { - return Operator.new(Opcode.VstSugar(op), typeParams, Function.siga(paramTypes, result)) - .setOp2(Opcode2.VstSugar(op, paramTypes, result)); + return Operator.new(Opcode.VstSugar(op), typeParams, Opcode2.VstSugar(op, paramTypes, result)); } //---------------------------------------------------------------------------- def newPtrAdd(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrAdd, [ptrType, it], [ptrType, it], ptrType) - .setOp2(Opcode2.PtrAdd(ptrType, IntType.!(it))); + return newOp0(Opcode.PtrAdd, [ptrType, it], Opcode2.PtrAdd(ptrType, IntType.!(it))); } def newPtrSub(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrSub, [ptrType, it], [ptrType, ptrType], it) - .setOp2(Opcode2.PtrSub(ptrType, IntType.!(it))); + return newOp0(Opcode.PtrSub, [ptrType, it], Opcode2.PtrSub(ptrType, IntType.!(it))); } def newPtrLt(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLt, [ptrType], [ptrType, ptrType], type_z) - .setOp2(Opcode2.PtrLt(PointerType.!(ptrType))); + return newOp0(Opcode.PtrLt, [ptrType], Opcode2.PtrLt(PointerType.!(ptrType))); } def newPtrLteq(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLteq, [ptrType], [ptrType, ptrType], type_z) - .setOp2(Opcode2.PtrLteq(PointerType.!(ptrType))); + return newOp0(Opcode.PtrLteq, [ptrType], Opcode2.PtrLteq(PointerType.!(ptrType))); } def newPtrAtContents(rangeType: Type, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtContents, [rangeType], [rangeType], ptrType) - .setOp2(Opcode2.PtrAtContents(PointerType.!(ptrType), rangeType)); + return newOp0(Opcode.PtrAtContents, [rangeType], Opcode2.PtrAtContents(PointerType.!(ptrType), rangeType)); } def newPtrAtLength(arrayType: Type, ptrType: Type) -> Operator { var tt = [arrayType]; - return newOp0(Opcode.PtrAtLength, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtLength(PointerType.!(ptrType), ArrayType.!(arrayType))); + return newOp0(Opcode.PtrAtLength, tt, Opcode2.PtrAtLength(PointerType.!(ptrType), ArrayType.!(arrayType))); } def newPtrAtObject(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtObject, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtObject(PointerType.!(ptrType), objType)); + return newOp0(Opcode.PtrAtObject, tt, Opcode2.PtrAtObject(PointerType.!(ptrType), objType)); } def newPtrAtArrayElem(arrayType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [arrayType, indexType]; - return newOp0(Opcode.PtrAtArrayElem, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtArrayElem(PointerType.!(ptrType), ArrayType.!(arrayType), IntType.!(indexType))); + return newOp0(Opcode.PtrAtArrayElem, tt, Opcode2.PtrAtArrayElem(PointerType.!(ptrType), ArrayType.!(arrayType), IntType.!(indexType))); } def newPtrAtRangeElem(rangeType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [rangeType, indexType]; - return newOp0(Opcode.PtrAtRangeElem, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtRangeElem(PointerType.!(ptrType), RangeType.!(rangeType), IntType.!(indexType))); + return newOp0(Opcode.PtrAtRangeElem, tt, Opcode2.PtrAtRangeElem(PointerType.!(ptrType), RangeType.!(rangeType), IntType.!(indexType))); } def newPtrAtEnd(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtEnd, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtEnd(PointerType.!(ptrType), objType)); + return newOp0(Opcode.PtrAtEnd, tt, Opcode2.PtrAtEnd(PointerType.!(ptrType), objType)); } def newPtrAtRef(layoutType: Type, ptrType: Type) -> Operator { var tt = [layoutType]; - return newOp0(Opcode.PtrAtRef, tt, tt, ptrType) - .setOp2(Opcode2.PtrAtRef(PointerType.!(ptrType), layoutType)); + return newOp0(Opcode.PtrAtRef, tt, Opcode2.PtrAtRef(PointerType.!(ptrType), layoutType)); } def newPtrAtComponentField(spec: IrSpec, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], TypeUtil.NO_TYPES, ptrType) - .setOp2(Opcode2.PtrAtComponentField(PointerType.!(ptrType), spec)); + return newOp0(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], Opcode2.PtrAtComponentField(PointerType.!(ptrType), spec)); } def newPtrAtObjectField(spec: IrSpec, ptrType: Type) -> Operator { var tt = [spec.receiver]; - return newOp0(Opcode.PtrAtObjectField(spec.asField()), tt, tt, ptrType) - .setOp2(Opcode2.PtrAtObjectField(PointerType.!(ptrType), spec)); + return newOp0(Opcode.PtrAtObjectField(spec.asField()), tt, Opcode2.PtrAtObjectField(PointerType.!(ptrType), spec)); } def newPtrAtRefLayoutField(refType: Type, offset: int, ptrType: Type) -> Operator { var ta = [refType]; - return newOp0(Opcode.PtrAtRefLayoutField(offset), ta, ta, ptrType) - .setOp2(Opcode2.PtrAtRefLayoutField(RefType.!(refType), PointerType.!(ptrType), offset)); + return newOp0(Opcode.PtrAtRefLayoutField(offset), ta, Opcode2.PtrAtRefLayoutField(RefType.!(refType), PointerType.!(ptrType), offset)); } def newPtrAtUnboxedObjectField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType) - .setOp2(Opcode2.PtrAtUnboxedObjectField(specs, PointerType.!(ptrType))); + return newOp0(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedObjectField(specs, PointerType.!(ptrType))); } def newPtrAtUnboxedComponentField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, ta, ptrType) - .setOp2(Opcode2.PtrAtUnboxedComponentField(specs, PointerType.!(ptrType))); + return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedComponentField(specs, PointerType.!(ptrType))); } def newPtrCmpSwp(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], [ptrType, valueType, valueType], type_z) - .setOp2(Opcode2.PtrCmpSwp(PointerType.!(ptrType), valueType)); + return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], Opcode2.PtrCmpSwp(PointerType.!(ptrType), valueType)); } def newPtrLoad(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrLoad, [ptrType, valueType], [ptrType], valueType) - .setOp2(Opcode2.PtrLoad(ptrType, valueType)); + return newOp0(Opcode.PtrLoad, [ptrType, valueType], Opcode2.PtrLoad(ptrType, valueType)); } def newPtrStore(ptrType: Type, valueType: Type) -> Operator { var tt = [ptrType, valueType]; - return newOp0(Opcode.PtrStore, tt, tt, type_v) - .setOp2(Opcode2.PtrStore(ptrType, valueType)); + return newOp0(Opcode.PtrStore, tt, Opcode2.PtrStore(ptrType, valueType)); } def newPtrAddRangeStart(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAddRangeStart, [ptrType], [ptrType, type_rs], ptrType) - .setOp2(Opcode2.PtrAddRangeStart(PointerType.!(ptrType))); + return newOp0(Opcode.PtrAddRangeStart, [ptrType], Opcode2.PtrAddRangeStart(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newCallerIp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerIp, TypeUtil.NO_TYPES, arr_v, ptrType) - .setOp2(Opcode2.CallerIp(PointerType.!(ptrType))); + return newOp0(Opcode.CallerIp, TypeUtil.NO_TYPES, Opcode2.CallerIp(PointerType.!(ptrType))); } def newCallerSp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerSp, TypeUtil.NO_TYPES, arr_v, ptrType) - .setOp2(Opcode2.CallerSp(PointerType.!(ptrType))); + return newOp0(Opcode.CallerSp, TypeUtil.NO_TYPES, Opcode2.CallerSp(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newAlloc(ptrType: Type) -> Operator { - return newOp0(Opcode.Alloc, [ptrType], arr_i, ptrType) - .setOp2(Opcode2.Alloc(ptrType)); + return newOp0(Opcode.Alloc, [ptrType], Opcode2.Alloc(ptrType)); } //---------------------------------------------------------------------------- def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], rep.paramTypes, Function.getReturnType(funcType)) - .setOp2(Opcode2.CallAddress(p, rep)); + return newOp0(Opcode.CallAddress(rep), [rep.machType], Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { - return Operator.new(Opcode.CallKernel(kernel), typeParams, sig) - .setOp2(Opcode2.CallKernel(kernel, sig.paramTypes, sig.returnType())); + return Operator.new(Opcode.CallKernel(kernel), typeParams, Opcode2.CallKernel(kernel, sig.paramTypes, sig.returnType())); } //---------------------------------------------------------------------------- def newRefLayoutAt(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutAt, at, [V3.arrayByteType, Int.TYPE], refType) - .setOp2(Opcode2.RefLayoutAt(refType)); + return newOp0(Opcode.RefLayoutAt, at, Opcode2.RefLayoutAt(refType)); } def newRefLayoutOf(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutOf, at, [V3.rangeByteType], refType) - .setOp2(Opcode2.RefLayoutOf(refType)); + return newOp0(Opcode.RefLayoutOf, at, Opcode2.RefLayoutOf(refType)); } def newRefLayoutIn(refType: RefType, offset: int, result: RefType) -> Operator { var at: Array = [refType, result]; - return newOp0(Opcode.RefLayoutIn(offset), at, [refType], result) - .setOp2(Opcode2.RefLayoutIn(refType, offset, result)); + return newOp0(Opcode.RefLayoutIn(offset), at, Opcode2.RefLayoutIn(refType, offset, result)); } def newRefLayoutGetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { - return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], [refType], fieldType) - .setOp2(Opcode2.RefLayoutGetField(refType, offset, fieldType)); + return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], Opcode2.RefLayoutGetField(refType, offset, fieldType)); } def newRefLayoutSetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { var at = [refType, fieldType]; - return newOp0(Opcode.RefLayoutSetField(offset, order), at, at, Void.TYPE) - .setOp2(Opcode2.RefLayoutSetField(refType, offset, fieldType)); + return newOp0(Opcode.RefLayoutSetField(offset, order), at, Opcode2.RefLayoutSetField(refType, offset, fieldType)); } 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) - .setOp2(Opcode2.RefLayoutAtRepeatedField(refType, offset, scale, max, result)); + return newOp0(opcode, [refType, result], Opcode2.RefLayoutAtRepeatedField(refType, offset, scale, max, result)); } 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) - .setOp2(Opcode2.RefLayoutGetRepeatedField(refType, offset, scale, max, fieldType)); + return newOp0(opcode, [refType, fieldType], Opcode2.RefLayoutGetRepeatedField(refType, offset, scale, max, fieldType)); } 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) - .setOp2(Opcode2.RefLayoutSetRepeatedField(refType, offset, scale, max, fieldType)); + return newOp0(opcode, [refType, fieldType], Opcode2.RefLayoutSetRepeatedField(refType, offset, scale, max, fieldType)); } 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) - .setOp2(Opcode2.ByteArrayGetField(startType, offset, fieldType)); + return newOp0(opcode, [fieldType, startType], Opcode2.ByteArrayGetField(startType, offset, fieldType)); } 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) - .setOp2(Opcode2.ByteArraySetField(startType, offset, fieldType)); + return newOp0(opcode, [fieldType, startType], Opcode2.ByteArraySetField(startType, offset, fieldType)); } //---------------------------------------------------------------------------- def bestCallVirtual(spec: IrSpec) -> Operator { diff --git a/aeneas/src/ssa/VstSsaGen.v3 b/aeneas/src/ssa/VstSsaGen.v3 index a57f924c2..364621bcc 100644 --- a/aeneas/src/ssa/VstSsaGen.v3 +++ b/aeneas/src/ssa/VstSsaGen.v3 @@ -1232,8 +1232,10 @@ class VstSsaGen extends VstVisitor { indexMap[i] = p.index; args[i] = env[l.head.1.decl.ssa]; } - var paramTypes = Lists.toArray(List.new(expr.func.ftype, expr.func.params.mapList(ParamDecl.vtype))); - var op = V3Op.newCallClosure2(expr.func.ftype, paramTypes); + // TODO: is the recomputation of parameter types necessary? +// var paramTypes = Lists.toArray(List.new(expr.func.ftype, expr.func.params.mapList(ParamDecl.vtype))); +// var op = V3Op.newCallClosure2(expr.func.ftype, paramTypes); + var op = V3Op.newCallClosure(expr.func.ftype); return env.addClosureCreate(op, args, indexMap); } diff --git a/aeneas/src/types/Float.v3 b/aeneas/src/types/Float.v3 index e7670f6e5..d521b8a4e 100644 --- a/aeneas/src/types/Float.v3 +++ b/aeneas/src/types/Float.v3 @@ -166,24 +166,24 @@ class FloatOpCache(ft: FloatType) { def binopSig = Function.sig(tupleType, ft); def cmpSig = Function.sig(tupleType, Bool.TYPE); - def opAdd = newOp(Opcode.FloatAdd(ft.is64), typeArgs, binopSig); - def opSub = newOp(Opcode.FloatSub(ft.is64), typeArgs, binopSig); - def opMul = newOp(Opcode.FloatMul(ft.is64), typeArgs, binopSig); - def opDiv = newOp(Opcode.FloatDiv(ft.is64), typeArgs, binopSig); + def opAdd = Operator.new(Opcode.FloatAdd(ft.is64), typeArgs, Opcode2.FloatAdd(ft)); + def opSub = Operator.new(Opcode.FloatSub(ft.is64), typeArgs, Opcode2.FloatSub(ft)); + def opMul = Operator.new(Opcode.FloatMul(ft.is64), typeArgs, Opcode2.FloatMul(ft)); + def opDiv = Operator.new(Opcode.FloatDiv(ft.is64), typeArgs, Opcode2.FloatDiv(ft)); def opSign = V3Op.newVstSugar(VstOperator.FloatSign, arr_t, arr_t, Int.getType(false, 1)); def opExponent = V3Op.newVstSugar(VstOperator.FloatExponent, arr_t, arr_t, Int.getType(true, ft.exp_width)); def opFraction = V3Op.newVstSugar(VstOperator.FloatFraction, arr_t, arr_t, Int.getType(false, ft.fraction_width)); - def opAbs = newOp(Opcode.FloatAbs(ft.is64), typeArgs, unopSig); - def opCeil = newOp(Opcode.FloatCeil(ft.is64), typeArgs, unopSig); - def opFloor = newOp(Opcode.FloatFloor(ft.is64), typeArgs, unopSig); - def opSqrt = newOp(Opcode.FloatSqrt(ft.is64), typeArgs, unopSig); + def opAbs = Operator.new(Opcode.FloatAbs(ft.is64), typeArgs, Opcode2.FloatAbs(ft)); + def opCeil = Operator.new(Opcode.FloatCeil(ft.is64), typeArgs, Opcode2.FloatCeil(ft)); + def opFloor = Operator.new(Opcode.FloatFloor(ft.is64), typeArgs, Opcode2.FloatFloor(ft)); + def opSqrt = Operator.new(Opcode.FloatSqrt(ft.is64), typeArgs, Opcode2.FloatSqrt(ft)); - def opEqual = newOp(Opcode.FloatEq(ft.is64), typeArgs, cmpSig); - def opNotEqual = newOp(Opcode.FloatNe(ft.is64), typeArgs, cmpSig); - def opLt = newOp(Opcode.FloatLt(ft.is64), typeArgs, cmpSig); - def opLteq = newOp(Opcode.FloatLteq(ft.is64), typeArgs, cmpSig); + def opEqual = Operator.new(Opcode.FloatEq(ft.is64), typeArgs, Opcode2.FloatEq(ft)); + def opNotEqual = Operator.new(Opcode.FloatNe(ft.is64), typeArgs, Opcode2.FloatNe(ft)); + def opLt = Operator.new(Opcode.FloatLt(ft.is64), typeArgs, Opcode2.FloatLt(ft)); + def opLteq = Operator.new(Opcode.FloatLteq(ft.is64), typeArgs, Opcode2.FloatLteq(ft)); def opGt = V3Op.newVstSugar(VstOperator.Commute(opLt), arr_t, [ft, ft], Bool.TYPE); def opGteq = V3Op.newVstSugar(VstOperator.Commute(opLteq), arr_t, [ft, ft], Bool.TYPE); @@ -191,9 +191,6 @@ class FloatOpCache(ft: FloatType) { return null; } } -def newOp(op: Opcode, typeArgs: Array, sig: Signature) -> Operator { - return Operator.new(op, typeArgs, sig); -} class Float32Val(bits: u32) extends Val { def equals(that: Val) -> bool { if (Float.isNan32(bits)) return false; diff --git a/aeneas/src/types/Int.v3 b/aeneas/src/types/Int.v3 index 5b967912d..1fa7b781e 100644 --- a/aeneas/src/types/Int.v3 +++ b/aeneas/src/types/Int.v3 @@ -143,20 +143,20 @@ class IntType extends PrimType { if (v == 0) return null; return Box.new(v); } - def opEq() -> Operator { return opcache().compare(V3Infix.EqEq, Opcode.IntEq); } - def opLt() -> Operator { return opcache().compare(V3Infix.Lt, Opcode.IntLt); } - def opLtEq() -> Operator { return opcache().compare(V3Infix.LtEq, Opcode.IntLteq); } - def opAdd() -> Operator { return opcache().arith(V3Infix.Add, Opcode.IntAdd); } - def opSub() -> Operator { return opcache().arith(V3Infix.Sub, Opcode.IntSub); } - def opMul() -> Operator { return opcache().arith(V3Infix.Mul, Opcode.IntMul); } - def opDiv() -> Operator { return opcache().arith(V3Infix.Div, Opcode.IntDiv); } - def opMod() -> Operator { return opcache().arith(V3Infix.Mod, Opcode.IntMod); } - def opAnd() -> Operator { return opcache().arith(V3Infix.And, Opcode.IntAnd); } - def opOr() -> Operator { return opcache().arith(V3Infix.Or, Opcode.IntOr); } - def opXor() -> Operator { return opcache().arith(V3Infix.Xor, Opcode.IntXor); } - def opShl() -> Operator { return opcache().shift(V3Infix.Shl, Opcode.IntShl); } - def opSar() -> Operator { return opcache().shift(V3Infix.Sar, if(signed, Opcode.IntSar, Opcode.IntShr)); } - def opShr() -> Operator { return opcache().shift(V3Infix.Shr, Opcode.IntShr); } + def opEq() -> Operator { return opcache().get(V3Infix.EqEq, Opcode.IntEq, Opcode2.IntEq); } + def opLt() -> Operator { return opcache().get(V3Infix.Lt, Opcode.IntLt, Opcode2.IntLt); } + def opLtEq() -> Operator { return opcache().get(V3Infix.LtEq, Opcode.IntLteq, Opcode2.IntLteq); } + def opAdd() -> Operator { return opcache().get(V3Infix.Add, Opcode.IntAdd, Opcode2.IntAdd); } + def opSub() -> Operator { return opcache().get(V3Infix.Sub, Opcode.IntSub, Opcode2.IntSub); } + def opMul() -> Operator { return opcache().get(V3Infix.Mul, Opcode.IntMul, Opcode2.IntMul); } + def opDiv() -> Operator { return opcache().get(V3Infix.Div, Opcode.IntDiv, Opcode2.IntDiv); } + def opMod() -> Operator { return opcache().get(V3Infix.Mod, Opcode.IntMod, Opcode2.IntMod); } + def opAnd() -> Operator { return opcache().get(V3Infix.And, Opcode.IntAnd, Opcode2.IntAnd); } + def opOr() -> Operator { return opcache().get(V3Infix.Or, Opcode.IntOr, Opcode2.IntOr); } + def opXor() -> Operator { return opcache().get(V3Infix.Xor, Opcode.IntXor, Opcode2.IntXor); } + def opShl() -> Operator { return opcache().get(V3Infix.Shl, Opcode.IntShl, Opcode2.IntShl); } + def opSar() -> Operator { return opcache().get(V3Infix.Sar, if(signed, Opcode.IntSar, Opcode.IntShr), if(signed, Opcode2.IntSar, Opcode2.IntShr)); } + def opShr() -> Operator { return opcache().get(V3Infix.Shr, Opcode.IntShr, Opcode2.IntShr); } def unsigned() -> IntType { return if(signed, Int.getType(false, width), this); } @@ -206,25 +206,12 @@ class IntType extends PrimType { // A cache of integer arithmetic operators that is referenced from the TypeCon. class IntOpCache(it: IntType) { def typeArgs: Array = [it]; - def tupleType = Tuple.newType(Lists.cons2(it, it)); - def binopSig = Function.sig(tupleType, it); - def cmpSig = Function.sig(tupleType, Bool.TYPE); def cache = Array.new(V3Infix.None.tag + 1); - def compare(infix: V3Infix, opcode: Opcode) -> Operator { + def get(infix: V3Infix, opcode: Opcode, opc: IntType -> Opcode2) -> Operator { var op = cache[infix.tag]; if (op != null) return op; - return cache[infix.tag] = Operator.new(opcode, typeArgs, cmpSig); - } - def arith(infix: V3Infix, opcode: Opcode) -> Operator { - var op = cache[infix.tag]; - if (op != null) return op; - return cache[infix.tag] = Operator.new(opcode, typeArgs, binopSig); - } - def shift(infix: V3Infix, opcode: Opcode) -> Operator { - var op = cache[infix.tag]; - if (op != null) return op; - return cache[infix.tag] = Operator.new(opcode, typeArgs, Function.siga([it, Byte.TYPE], it)); + return cache[infix.tag] = Operator.new(opcode, typeArgs, opc(it)); } } From 16d69d45fce7540733b1a109c386d490fe917169 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 12:29:16 +0200 Subject: [PATCH 12/17] Fix type of shift operators --- aeneas/src/core/Operator2.v3 | 9 ++++++--- test/core/seman/sar08.v3 | 3 +++ test/core/seman/sar08b.v3 | 3 +++ test/core/seman/shl08.v3 | 2 ++ test/core/seman/shl08b.v3 | 2 ++ test/core/seman/shr08.v3 | 3 +++ test/core/seman/shr08b.v3 | 3 +++ 7 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test/core/seman/sar08.v3 create mode 100644 test/core/seman/sar08b.v3 create mode 100644 test/core/seman/shl08.v3 create mode 100644 test/core/seman/shl08b.v3 create mode 100644 test/core/seman/shr08.v3 create mode 100644 test/core/seman/shr08b.v3 diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index ccc0fc3e1..4e77940e7 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -47,9 +47,9 @@ class Operator2(opcode: Opcode2) { IntAnd(t) => set_xx_x(t); IntOr(t) => set_xx_x(t); IntXor(t) => set_xx_x(t); - IntShl(t) => set_xx_x(t); - IntSar(t) => set_xx_x(t); - IntShr(t) => set_xx_x(t); + IntShl(t) => set_xb_x(t); + IntSar(t) => set_xb_x(t); + IntShr(t) => set_xb_x(t); IntLt(t) => set_xx_z(t); IntLteq(t) => set_xx_z(t); IntWide(op, p, r) => set_arr(p, r); @@ -328,6 +328,9 @@ class Operator2(opcode: Opcode2) { private def set_xx_x(x: Type) { set(Tuple.newType(Lists.cons2(x, x)), [x, x], x, [x]); } + private def set_xb_x(x: Type) { + set(Tuple.newType(Lists.cons2(x, Byte.TYPE)), [x, Byte.TYPE], x, [x]); + } private def set_xx_z(x: Type) { set(Tuple.newType(Lists.cons2(x, x)), [x, x], TYPE_z, arr_z); } diff --git a/test/core/seman/sar08.v3 b/test/core/seman/sar08.v3 new file mode 100644 index 000000000..da0d52d45 --- /dev/null +++ b/test/core/seman/sar08.v3 @@ -0,0 +1,3 @@ +//@seman +var f: (int, byte) -> int = int.>>; + diff --git a/test/core/seman/sar08b.v3 b/test/core/seman/sar08b.v3 new file mode 100644 index 000000000..6973b536c --- /dev/null +++ b/test/core/seman/sar08b.v3 @@ -0,0 +1,3 @@ +//@seman = TypeError @ 2:28 +var f: (int, int) -> int = int.>>; + diff --git a/test/core/seman/shl08.v3 b/test/core/seman/shl08.v3 new file mode 100644 index 000000000..607a24771 --- /dev/null +++ b/test/core/seman/shl08.v3 @@ -0,0 +1,2 @@ +//@seman +var f: (int, byte) -> int = int.<<; diff --git a/test/core/seman/shl08b.v3 b/test/core/seman/shl08b.v3 new file mode 100644 index 000000000..9c82d14da --- /dev/null +++ b/test/core/seman/shl08b.v3 @@ -0,0 +1,2 @@ +//@seman = TypeError @ 2:28 +var f: (int, int) -> int = int.<<; diff --git a/test/core/seman/shr08.v3 b/test/core/seman/shr08.v3 new file mode 100644 index 000000000..5471b007f --- /dev/null +++ b/test/core/seman/shr08.v3 @@ -0,0 +1,3 @@ +//@seman +var f: (int, byte) -> int = int.>>>; + diff --git a/test/core/seman/shr08b.v3 b/test/core/seman/shr08b.v3 new file mode 100644 index 000000000..ba1aa8ef0 --- /dev/null +++ b/test/core/seman/shr08b.v3 @@ -0,0 +1,3 @@ +//@seman = TypeError @ 2:28 +var f: (int, int) -> int = int.>>>; + From 6b439764f1601256bbd8fd2d2791a393b4a66182 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 13:11:19 +0200 Subject: [PATCH 13/17] Small cleanups --- aeneas/src/core/Opcode2.v3 | 8 +------- aeneas/src/core/Operator.v3 | 6 ------ aeneas/src/core/Operator2.v3 | 28 ++++++++-------------------- 3 files changed, 9 insertions(+), 33 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index 1bab7dcbb..e8a57eab5 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -567,13 +567,7 @@ component Opcodes2 { if (nreceiver != spec.receiver || ntypeArgs != spec.typeArgs) return IrSpec.new(nreceiver, ntypeArgs, spec.member); return spec; } - def substArray(a: Array, func: Type -> Type) -> Array { - for (i < a.length) { - var prev = a[i], ntype = func(prev); - if (prev != ntype) return Arrays.map(a, func); // XXX: slight redundant work for j < i - } - return a; - } + def substArray(a: Array, func: Type -> Type) -> Array { return Arrays.mapId(a, func); } def substArrayType(t: ArrayType, func: Type -> Type) -> ArrayType { return ArrayType.!(func(t)); } def substRangeType(t: RangeType, func: Type -> Type) -> RangeType { return RangeType.!(func(t)); } def substFuncType(t: FuncType, func: Type -> Type) -> FuncType { return FuncType.!(func(t)); } diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 38b6cde32..89d459ac0 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -33,12 +33,6 @@ class Operator(opcode: Opcode, typeArgs: Array, opc2: Opcode2) { def render(buf: StringBuilder) -> StringBuilder { return renderOp(this, buf); } - def evaluate(args: Arguments) -> Result { - return Eval.doOp(this, args); - } - def setOp2(op: Opcode2) -> this { - this.op2 = Operator2.new(op); - } def sig() -> Signature { return op2.sig(); } diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index 4e77940e7..462969569 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -8,7 +8,6 @@ class Operator2(opcode: Opcode2) { def sig() -> Signature { return if(sig_ != null, sig_, makeSig().sig_); } - def subst(func: Type -> Type) -> Operator2 { if (checkOpenness() == Open.CLOSED) return this; return Operator2.new(Opcodes2.subst(opcode, func)); @@ -17,19 +16,6 @@ class Operator2(opcode: Opcode2) { if (openness != Open.UNKNOWN) return openness; return openness = Opcodes2.checkOpenness(opcode); } - private def substArray(func: Type -> Type, args: Array) -> Array { - for (i < args.length) { - var t = args[i], nt = func(t); - if (t != nt) { - var nargs = Array.new(args.length); - for (j < i) nargs[j] = args[j]; - nargs[i] = nt; - for (j = i + 1; j < args.length; j++) nargs[j] = func(args[j]); - return nargs; - } - } - return args; - } private def makeSig() -> this { match (opcode) { // Boolean operators @@ -100,7 +86,7 @@ class Operator2(opcode: Opcode2) { set(t, [t], e, [e]); } // Array operations - ArrayAlloc(t) => set_x_y(Int.TYPE, t); + ArrayAlloc(t) => set_x_y(TYPE_i, t); ArrayInit(t, length) => { var elemType = t.elementType(); var paramTypes = Array.new(length); @@ -136,13 +122,13 @@ class Operator2(opcode: Opcode2) { var tt = [t, it, etype]; set(Tuple.fromTypeArray(tt), tt, TYPE_v, arr_v); } - ArrayGetLength(t) => set_x_y(t, Int.TYPE); + ArrayGetLength(t) => set_x_y(t, TYPE_i); // Range operations RangeFromTo(t, st, et) => set_arr([t, st, et], [t]); RangeFromPlus(t, st, lt) => set_arr([t, st, lt], [t]); RangeGetElem(t, it) => set_arr([t, it], [t.elementType()]); RangeSetElem(t, it) => set_arr([t, it, t.elementType()], arr_v); - RangeGetLength(t) => set_x_y(t, Int.TYPE); + RangeGetLength(t) => set_x_y(t, TYPE_i); RangeStartPlusIndex(t, it) => set_arr([TYPE_rs, it], arr_rs); RangeStartFromPointer(t, pt) => set_arr([pt], arr_rs); // Normalized Range operations @@ -247,7 +233,7 @@ class Operator2(opcode: Opcode2) { set_arr(Arrays.prepend(t, sig.paramTypes), sig.returnTypes); } CallFunction(t) => { - var sig = t.sig(), ftype = t.prependParam(AnyRef.TYPE); + var sig = t.sig(), ftype = t.prependParam(TYPE_r); set_arr(Arrays.prepend(ftype, sig.paramTypes), sig.returnTypes); } CreateClosure(obj, method) => { @@ -262,7 +248,7 @@ class Operator2(opcode: Opcode2) { set_arr([funcType], [ptrType, closureType]); } // RefLayout operations - RefLayoutAt(t) => set_arr([V3.arrayByteType, Int.TYPE], [t]); + RefLayoutAt(t) => set_arr([V3.arrayByteType, TYPE_i], [t]); RefLayoutOf(t) => set_arr([V3.rangeByteType], [t]); RefLayoutIn(t, offset, rt) => set_x_y(t, rt); RefLayoutGetField(t, offset, ft) => set_x_y(t, ft); @@ -329,7 +315,7 @@ class Operator2(opcode: Opcode2) { set(Tuple.newType(Lists.cons2(x, x)), [x, x], x, [x]); } private def set_xb_x(x: Type) { - set(Tuple.newType(Lists.cons2(x, Byte.TYPE)), [x, Byte.TYPE], x, [x]); + set(Tuple.newType(Lists.cons2(x, TYPE_b)), [x, TYPE_b], x, [x]); } private def set_xx_z(x: Type) { set(Tuple.newType(Lists.cons2(x, x)), [x, x], TYPE_z, arr_z); @@ -345,8 +331,10 @@ class Operator2(opcode: Opcode2) { } } +def TYPE_r = AnyRef.TYPE; def TYPE_v = Void.TYPE; def TYPE_z = Bool.TYPE; +def TYPE_b = Byte.TYPE; def TYPE_i = Int.TYPE; def arr_v: Array = []; def arr_z: Array = [TYPE_z]; From 3236f25f3148983540f7d4cb337281da152abd2e Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 14:37:18 +0200 Subject: [PATCH 14/17] Inline newOp0 and simplify openness check --- aeneas/src/core/Operator.v3 | 244 +++++++++++++++++------------------ aeneas/src/core/Operator2.v3 | 12 +- 2 files changed, 126 insertions(+), 130 deletions(-) diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 89d459ac0..99977807f 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -65,10 +65,6 @@ component V3Op { def sig_zz_z = Signature.new(null, arr_zz, arr_z); def sig_z_z = Signature.new(null, arr_z, arr_z); - private def newOp0(opcode: Opcode, typeArgs: Array, opc2: Opcode2) -> Operator { - return Operator.new(opcode, typeArgs, opc2); - } - //---------------------------------------------------------------------------- def opBoolEq = Operator.new(Opcode.BoolEq, arr_z, Opcode2.BoolEq); def opBoolAnd = Operator.new(Opcode.BoolAnd, arr_v, Opcode2.BoolAnd); @@ -76,92 +72,92 @@ component V3Op { def opBoolNot = Operator.new(Opcode.BoolNot, arr_v, Opcode2.BoolNot); //---------------------------------------------------------------------------- def newIntEq(t: IntType) -> Operator { - return newOp0(Opcode.IntEq, [t], Opcode2.IntEq(t)); + return Operator.new(Opcode.IntEq, [t], Opcode2.IntEq(t)); } def newIntWide(op: Operator, normal: Array, result: Type) -> Operator { - return newOp0(Opcode.IntWide(op), arr_v, Opcode2.IntWide(op, normal, Tuple.toTypeArray(result))); + return Operator.new(Opcode.IntWide(op), arr_v, Opcode2.IntWide(op, normal, Tuple.toTypeArray(result))); } //---------------------------------------------------------------------------- - def opFloatBitEq32 = newOp0(Opcode.FloatBitEq(false), arr_f, Opcode2.FloatBitEq(Float.FLOAT32)); - def opFloatBitEq64 = newOp0(Opcode.FloatBitEq(true), arr_d, Opcode2.FloatBitEq(Float.FLOAT64)); + def opFloatBitEq32 = Operator.new(Opcode.FloatBitEq(false), arr_f, Opcode2.FloatBitEq(Float.FLOAT32)); + def opFloatBitEq64 = Operator.new(Opcode.FloatBitEq(true), arr_d, Opcode2.FloatBitEq(Float.FLOAT64)); //---------------------------------------------------------------------------- def newIntCastF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], Opcode2.IntCastF(IntType.!(tt), FloatType.!(ft))); + return Operator.new(Opcode.IntCastF(V3.isDouble(ft)), [ft, tt], Opcode2.IntCastF(IntType.!(tt), FloatType.!(ft))); } def newIntQueryF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], Opcode2.IntQueryF(IntType.!(tt), FloatType.!(ft))); + return Operator.new(Opcode.IntQueryF(V3.isDouble(ft)), [ft, tt], Opcode2.IntQueryF(IntType.!(tt), FloatType.!(ft))); } def newIntViewI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntViewI, [ft, tt], Opcode2.IntViewI(IntType.!(tt), IntType.!(ft))); + return Operator.new(Opcode.IntViewI, [ft, tt], Opcode2.IntViewI(IntType.!(tt), IntType.!(ft))); } - def opIntViewF32 = newOp0(Opcode.IntViewF(false), arr_f, Opcode2.IntViewF(Int.U32, Float.FLOAT32)); - def opIntViewF64 = newOp0(Opcode.IntViewF(true), arr_d, Opcode2.IntViewF(Long.U64, Float.FLOAT64)); + def opIntViewF32 = Operator.new(Opcode.IntViewF(false), arr_f, Opcode2.IntViewF(Int.U32, Float.FLOAT32)); + def opIntViewF64 = Operator.new(Opcode.IntViewF(true), arr_d, Opcode2.IntViewF(Long.U64, Float.FLOAT64)); def newIntTruncF(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], Opcode2.IntTruncF(IntType.!(tt), FloatType.!(ft))); + return Operator.new(Opcode.IntTruncF(V3.isDouble(ft)), [ft, tt], Opcode2.IntTruncF(IntType.!(tt), FloatType.!(ft))); } //---------------------------------------------------------------------------- def newFloatCastI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatCastI(FloatType.!(tt), IntType.!(ft))); + return Operator.new(Opcode.FloatCastI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatCastI(FloatType.!(tt), IntType.!(ft))); } - def opFloatCastD = newOp0(Opcode.FloatCastD, arr_d, Opcode2.FloatCastD(Float.FLOAT32, Float.FLOAT64)); + def opFloatCastD = Operator.new(Opcode.FloatCastD, arr_d, Opcode2.FloatCastD(Float.FLOAT32, Float.FLOAT64)); def newFloatQueryI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatQueryI(FloatType.!(tt), IntType.!(ft))); + return Operator.new(Opcode.FloatQueryI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatQueryI(FloatType.!(tt), IntType.!(ft))); } - def opFloatQueryD = newOp0(Opcode.FloatQueryD, arr_d, Opcode2.FloatQueryD(Float.FLOAT32, Float.FLOAT64)); + def opFloatQueryD = Operator.new(Opcode.FloatQueryD, arr_d, Opcode2.FloatQueryD(Float.FLOAT32, Float.FLOAT64)); def newFloatPromoteI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatPromoteI(FloatType.!(tt), IntType.!(ft))); + return Operator.new(Opcode.FloatPromoteI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatPromoteI(FloatType.!(tt), IntType.!(ft))); } - def opFloatPromoteF = newOp0(Opcode.FloatPromoteF, arr_f, Opcode2.FloatPromoteF(Float.FLOAT64, Float.FLOAT32)); + def opFloatPromoteF = Operator.new(Opcode.FloatPromoteF, arr_f, Opcode2.FloatPromoteF(Float.FLOAT64, Float.FLOAT32)); def newFloat32ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(false), [ft, type_f], Opcode2.FloatViewI(Float.FLOAT32, ft)); // TODO: ft should be IntType + return Operator.new(Opcode.FloatViewI(false), [ft, type_f], Opcode2.FloatViewI(Float.FLOAT32, ft)); // TODO: ft should be IntType } def newFloat64ViewI(ft: Type) -> Operator { - return newOp0(Opcode.FloatViewI(true), [ft, type_d], Opcode2.FloatViewI(Float.FLOAT64, ft)); // TODO: ft should be IntType + return Operator.new(Opcode.FloatViewI(true), [ft, type_d], Opcode2.FloatViewI(Float.FLOAT64, ft)); // TODO: ft should be IntType } def newFloatRoundI(ft: Type, tt: Type) -> Operator { - return newOp0(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatRoundI(FloatType.!(tt), ft)); // TODO: ft should be IntType + return Operator.new(Opcode.FloatRoundI(V3.isDouble(tt)), [ft, tt], Opcode2.FloatRoundI(FloatType.!(tt), ft)); // TODO: ft should be IntType } def newFloatRound(t: Type) -> Operator { - return newOp0(Opcode.FloatRound(V3.isDouble(t)), [t], Opcode2.FloatRound(FloatType.!(t))); + return Operator.new(Opcode.FloatRound(V3.isDouble(t)), [t], Opcode2.FloatRound(FloatType.!(t))); } - def opFloatRoundD = newOp0(Opcode.FloatRoundD, arr_v, Opcode2.FloatRoundD(Float.FLOAT32, Float.FLOAT64)); + def opFloatRoundD = Operator.new(Opcode.FloatRoundD, arr_v, Opcode2.FloatRoundD(Float.FLOAT32, Float.FLOAT64)); //---------------------------------------------------------------------------- def newRefEq(t: Type) -> Operator { - return newOp0(Opcode.RefEq, [t], Opcode2.RefEq(t)); + return Operator.new(Opcode.RefEq, [t], Opcode2.RefEq(t)); } //---------------------------------------------------------------------------- def newDefaultValue(t: Type) -> Operator { - return newOp0(Opcode.DefaultValue, [t], Opcode2.DefaultValue(t)); + return Operator.new(Opcode.DefaultValue, [t], Opcode2.DefaultValue(t)); } //---------------------------------------------------------------------------- def newIntRepCreate(ft: Type, tt: IntRepType) -> Operator { - return newOp0(Opcode.IntRepCreate, [ft, tt], Opcode2.IntRepCreate(tt, ft)); + return Operator.new(Opcode.IntRepCreate, [ft, tt], Opcode2.IntRepCreate(tt, ft)); } def newIntRepView(ft: IntRepType, tt: Type) -> Operator { - return newOp0(Opcode.IntRepView, [ft, tt], Opcode2.IntRepView(tt, ft)); + return Operator.new(Opcode.IntRepView, [ft, tt], Opcode2.IntRepView(tt, ft)); } //---------------------------------------------------------------------------- def newTupleCreate(tupleType: Type) -> Operator { var paramTypes = Lists.toArray(tupleType.nested); - return newOp0(Opcode.TupleCreate(paramTypes.length), [tupleType], Opcode2.TupleCreate(TupleType.!(tupleType))); + return Operator.new(Opcode.TupleCreate(paramTypes.length), [tupleType], Opcode2.TupleCreate(TupleType.!(tupleType))); } def newTupleGetElem(tupleType: Type, index: int) -> Operator { var tt = [tupleType]; - return newOp0(Opcode.TupleGetElem(index), tt, Opcode2.TupleGetElem(TupleType.!(tupleType), index)); + return Operator.new(Opcode.TupleGetElem(index), tt, Opcode2.TupleGetElem(TupleType.!(tupleType), index)); } //---------------------------------------------------------------------------- def newArrayAlloc(arrayType: Type) -> Operator { - return newOp0(Opcode.ArrayAlloc, [arrayType], Opcode2.ArrayAlloc(ArrayType.!(arrayType))); + return Operator.new(Opcode.ArrayAlloc, [arrayType], Opcode2.ArrayAlloc(ArrayType.!(arrayType))); } def newArrayFill(arrayType: Type) -> Operator { var elemType = V3Array.elementType(arrayType); - return newOp0(Opcode.ArrayFill, [arrayType], Opcode2.ArrayFill(ArrayType.!(arrayType))); + return Operator.new(Opcode.ArrayFill, [arrayType], Opcode2.ArrayFill(ArrayType.!(arrayType))); } def newArrayInit(arrayType: Type, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); var paramTypes = Array.new(length); for (i < paramTypes.length) paramTypes[i] = elemType; - return newOp0(Opcode.ArrayInit(length), [arrayType], Opcode2.ArrayInit(ArrayType.!(arrayType), length)); + return Operator.new(Opcode.ArrayInit(length), [arrayType], Opcode2.ArrayInit(ArrayType.!(arrayType), length)); } def newArrayTupleInit(arrayType: Type, elems: int, length: int) -> Operator { var elemType = V3Array.elementType(arrayType); @@ -173,14 +169,14 @@ component V3Op { paramTypes[i++] = tuple[k]; } } - return newOp0(Opcode.ArrayTupleInit(elems, length), [arrayType], Opcode2.ArrayTupleInit(ArrayType.!(arrayType), elems, length)); + return Operator.new(Opcode.ArrayTupleInit(elems, length), [arrayType], Opcode2.ArrayTupleInit(ArrayType.!(arrayType), elems, length)); } def newArrayGetElem(arrayType: Type, indexType: IntType) -> Operator { var elemType = V3Array.elementType(arrayType); var tt = [arrayType, indexType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArrayGetElem, tt, Opcode2.ArrayGetElem(x, indexType)); - x: RangeType => return newOp0(Opcode.RangeGetElem, tt, Opcode2.RangeGetElem(x, indexType)); + x: ArrayType => return Operator.new(Opcode.ArrayGetElem, tt, Opcode2.ArrayGetElem(x, indexType)); + x: RangeType => return Operator.new(Opcode.RangeGetElem, tt, Opcode2.RangeGetElem(x, indexType)); _ => return null; // TODO: error } } @@ -188,147 +184,147 @@ component V3Op { var elemType = V3Array.elementType(arrayType); var tt = [arrayType, indexType, elemType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArraySetElem, tt, Opcode2.ArraySetElem(x, indexType)); - x: RangeType => return newOp0(Opcode.RangeSetElem, tt, Opcode2.RangeSetElem(x, indexType)); + x: ArrayType => return Operator.new(Opcode.ArraySetElem, tt, Opcode2.ArraySetElem(x, indexType)); + x: RangeType => return Operator.new(Opcode.RangeSetElem, tt, Opcode2.RangeSetElem(x, indexType)); _ => return null; // TODO: error } } def newArrayGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType]; - return newOp0(Opcode.ArrayGetElemElem(index), tt, Opcode2.ArrayGetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); + return Operator.new(Opcode.ArrayGetElemElem(index), tt, Opcode2.ArrayGetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArraySetElemElem(arrayType: Type, indexType: Type, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); var tt = [arrayType, indexType, etype]; - return newOp0(Opcode.ArraySetElemElem(index), tt, Opcode2.ArraySetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); + return Operator.new(Opcode.ArraySetElemElem(index), tt, Opcode2.ArraySetElemElem(ArrayType.!(arrayType), IntType.!(indexType), index)); } def newArrayGetLength(arrayType: Type) -> Operator { var tt = [arrayType]; match (arrayType) { - x: ArrayType => return newOp0(Opcode.ArrayGetLength, tt, Opcode2.ArrayGetLength(x)); - x: RangeType => return newOp0(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(x)); + x: ArrayType => return Operator.new(Opcode.ArrayGetLength, tt, Opcode2.ArrayGetLength(x)); + x: RangeType => return Operator.new(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(x)); _ => return null; // TODO: error } } //---------------------------------------------------------------------------- def newRangeFromPlus(rangeType: Type, startType: Type, lengthType: Type) -> Operator { var tt = [rangeType, startType, lengthType]; - return newOp0(Opcode.RangeFromPlus, tt, Opcode2.RangeFromPlus(RangeType.!(rangeType), IntType.!(startType), IntType.!(lengthType))); + return Operator.new(Opcode.RangeFromPlus, tt, Opcode2.RangeFromPlus(RangeType.!(rangeType), IntType.!(startType), IntType.!(lengthType))); } def newRangeFromTo(rangeType: Type, startType: Type, endType: Type) -> Operator { var tt = [rangeType, startType, endType]; - return newOp0(Opcode.RangeFromTo, tt, Opcode2.RangeFromTo(RangeType.!(rangeType), IntType.!(startType), IntType.!(endType))); + return Operator.new(Opcode.RangeFromTo, tt, Opcode2.RangeFromTo(RangeType.!(rangeType), IntType.!(startType), IntType.!(endType))); } def newRangeGetLength(rangeType: Type) -> Operator { var tt = [rangeType]; - return newOp0(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(RangeType.!(rangeType))); + return Operator.new(Opcode.RangeGetLength, tt, Opcode2.RangeGetLength(RangeType.!(rangeType))); } def newRangeStartPlusIndex(rangeType: Type, indexType: IntType) -> Operator { - return newOp0(Opcode.RangeStartPlusIndex, [rangeType, indexType], Opcode2.RangeStartPlusIndex(RangeType.!(rangeType), indexType)); + return Operator.new(Opcode.RangeStartPlusIndex, [rangeType, indexType], Opcode2.RangeStartPlusIndex(RangeType.!(rangeType), indexType)); } def newRangeStartFromPointer(rangeType: Type, ptrType: PointerType) -> Operator { - return newOp0(Opcode.RangeStartFromPointer, [rangeType, ptrType], Opcode2.RangeStartFromPointer(RangeType.!(rangeType), ptrType)); + return Operator.new(Opcode.RangeStartFromPointer, [rangeType, ptrType], Opcode2.RangeStartFromPointer(RangeType.!(rangeType), ptrType)); } def newNormRangeGetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeGetElem, [arrayType, indexType], Opcode2.NormRangeGetElem(ArrayType.!(arrayType), IntType.!(indexType))); + return Operator.new(Opcode.NormRangeGetElem, [arrayType, indexType], Opcode2.NormRangeGetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeGetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], Opcode2.NormRangeGetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); + return Operator.new(Opcode.NormRangeGetElemElem(index), [arrayType, indexType], Opcode2.NormRangeGetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } def newNormRangeSetElem(arrayType: Type, indexType: Type) -> Operator { var etype = V3Array.elementType(arrayType); - return newOp0(Opcode.NormRangeSetElem, [arrayType, indexType], Opcode2.NormRangeSetElem(ArrayType.!(arrayType), IntType.!(indexType))); + return Operator.new(Opcode.NormRangeSetElem, [arrayType, indexType], Opcode2.NormRangeSetElem(ArrayType.!(arrayType), IntType.!(indexType))); } def newNormRangeSetElemElem(arrayType: Type, indexType: IntType, index: int) -> Operator { var etype = Tuple.elementType(V3Array.elementType(arrayType), index); - return newOp0(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], Opcode2.NormRangeSetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); + return Operator.new(Opcode.NormRangeSetElemElem(index), [arrayType, indexType], Opcode2.NormRangeSetElemElem(ArrayType.!(arrayType), index, IntType.!(indexType))); } //---------------------------------------------------------------------------- def newInit(meth: IrMethod) -> Operator { - return newOp0(Opcode.Init(meth), TypeUtil.NO_TYPES, Opcode2.Init(meth)); + return Operator.new(Opcode.Init(meth), TypeUtil.NO_TYPES, Opcode2.Init(meth)); } def newComponentGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ComponentGetField(fieldRef.asField()), tt, Opcode2.ComponentGetField(fieldRef.asField())); + return Operator.new(Opcode.ComponentGetField(fieldRef.asField()), tt, Opcode2.ComponentGetField(fieldRef.asField())); } def newComponentSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ComponentSetField(fieldRef.asField())); + return Operator.new(Opcode.ComponentSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ComponentSetField(fieldRef.asField())); } //---------------------------------------------------------------------------- def newClassAlloc(newRef: IrSpec) -> Operator { var ftype = newRef.getBoundType(), paramTypes = Function.getParamTypeArray(ftype); - return newOp0(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], Opcode2.ClassAlloc(newRef)); + return Operator.new(Opcode.ClassAlloc(newRef.asMethod()), [newRef.receiver], Opcode2.ClassAlloc(newRef)); } def newEmptyClassAlloc(classType: Type) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), TypeUtil.NO_TYPES)); + return Operator.new(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), TypeUtil.NO_TYPES)); } def newEmptyClassAllocP(classType: Type, paramTypes: Array) -> Operator { - return newOp0(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), paramTypes)); + return Operator.new(Opcode.ClassAlloc(null), [classType], Opcode2.ClassEmptyAlloc(ClassType.!(classType), paramTypes)); } def newClassGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.ClassGetField(fieldRef.asField()), tt, Opcode2.ClassGetField(fieldRef)); + return Operator.new(Opcode.ClassGetField(fieldRef.asField()), tt, Opcode2.ClassGetField(fieldRef)); } def newClassInitField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassInitField(fieldRef)); + return Operator.new(Opcode.ClassInitField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassInitField(fieldRef)); } def newClassSetField(fieldRef: IrSpec) -> Operator { var fieldType = fieldRef.getFieldType(); - return newOp0(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassSetField(fieldRef)); + return Operator.new(Opcode.ClassSetField(fieldRef.asField()), [fieldRef.receiver], Opcode2.ClassSetField(fieldRef)); } def newClassGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, Opcode2.ClassGetMethod(methodRef)); + return Operator.new(Opcode.ClassGetMethod(methodRef.asMethod()), typeArgs, Opcode2.ClassGetMethod(methodRef)); } def newClassGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.ClassGetVirtual(methodRef)); + return Operator.new(Opcode.ClassGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.ClassGetVirtual(methodRef)); } def newClassGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.ClassGetSelector(selector), typeArgs, Opcode2.ClassGetSelector(methodRef)); + return Operator.new(Opcode.ClassGetSelector(selector), typeArgs, Opcode2.ClassGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newVariantGetTag(vtype: Type) -> Operator { var vt = [vtype]; - return newOp0(Opcode.VariantGetTag, vt, Opcode2.VariantGetTag(ClassType.!(vtype))); + return Operator.new(Opcode.VariantGetTag, vt, Opcode2.VariantGetTag(ClassType.!(vtype))); } def newVariantAlloc(t: Type, fieldTypes: Array) -> Operator { - return newOp0(Opcode.VariantAlloc, [t], Opcode2.VariantAlloc(ClassType.!(t), fieldTypes)); + return Operator.new(Opcode.VariantAlloc, [t], Opcode2.VariantAlloc(ClassType.!(t), fieldTypes)); } def newVariantGetField(fieldRef: IrSpec) -> Operator { var tt = [fieldRef.receiver]; - return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, Opcode2.VariantGetField(fieldRef)); + return Operator.new(Opcode.VariantGetField(fieldRef.asField()), tt, Opcode2.VariantGetField(fieldRef)); } def newVariantGetMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, Opcode2.VariantGetMethod(methodRef)); + return Operator.new(Opcode.VariantGetMethod(methodRef.asMethod()), typeArgs, Opcode2.VariantGetMethod(methodRef)); } def newVariantGetVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.VariantGetVirtual(methodRef)); + return Operator.new(Opcode.VariantGetVirtual(methodRef.asMethod()), typeArgs, Opcode2.VariantGetVirtual(methodRef)); } def newVariantGetSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.VariantGetSelector(selector), typeArgs, Opcode2.VariantGetSelector(methodRef)); + return Operator.new(Opcode.VariantGetSelector(selector), typeArgs, Opcode2.VariantGetSelector(methodRef)); } //---------------------------------------------------------------------------- def newNullCheck(rtype: Type) -> Operator { var tt = [rtype]; - return newOp0(Opcode.NullCheck, tt, Opcode2.NullCheck(rtype)); + return Operator.new(Opcode.NullCheck, tt, Opcode2.NullCheck(rtype)); } def newBoundsCheck(rtype: Type) -> Operator { - return newOp0(Opcode.BoundsCheck, [rtype], Opcode2.BoundsCheck(rtype)); + return Operator.new(Opcode.BoundsCheck, [rtype], Opcode2.BoundsCheck(rtype)); } def newConditionalThrow(exception: string) -> Operator { - return newOp0(Opcode.ConditionalThrow(exception), arr_v, Opcode2.ConditionalThrow(exception)); + return Operator.new(Opcode.ConditionalThrow(exception), arr_v, Opcode2.ConditionalThrow(exception)); } //---------------------------------------------------------------------------- def newEqual(t: Type) -> Operator { @@ -348,70 +344,70 @@ component V3Op { VARIANT => { opcode = Opcode.VariantEq; opcode2 = Opcode2.VariantEq(ClassType.!(t)); } _ => { opcode = Opcode.OverloadedEq; opcode2 = Opcode2.OverloadedEq(t); } } - return newOp0(opcode, [t], opcode2); + return Operator.new(opcode, [t], opcode2); } def newTypeCast(f: Type, t: Type) -> Operator { var cast = TypeSystem.newTypeCast(f, t); - return newOp0(Opcode.TypeCast(cast), [f, t], Opcode2.TypeCast(cast, t, f)); + return Operator.new(Opcode.TypeCast(cast), [f, t], Opcode2.TypeCast(cast, t, f)); } def newTypeQuery(f: Type, t: Type) -> Operator { var query = TypeSystem.newTypeQuery(f, t); - return newOp0(Opcode.TypeQuery(query), [f, t], Opcode2.TypeQuery(query, t, f)); + return Operator.new(Opcode.TypeQuery(query), [f, t], Opcode2.TypeQuery(query, t, f)); } def newTypeSubsume(typeFrom: Type, typeTo: Type) -> Operator { - return newOp0(Opcode.TypeSubsume, [typeFrom, typeTo], Opcode2.TypeSubsume(typeTo, typeFrom)); + return Operator.new(Opcode.TypeSubsume, [typeFrom, typeTo], Opcode2.TypeSubsume(typeTo, typeFrom)); } //---------------------------------------------------------------------------- def newCallMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.CallMethod(methodRef.asMethod()), typeArgs, Opcode2.CallMethod(methodRef)); + return Operator.new(Opcode.CallMethod(methodRef.asMethod()), typeArgs, Opcode2.CallMethod(methodRef)); } def newCallClassMethod(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - return newOp0(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, Opcode2.CallClassMethod(methodRef)); + return Operator.new(Opcode.CallClassMethod(methodRef.asMethod()), typeArgs, Opcode2.CallClassMethod(methodRef)); } def newCallClassVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - return newOp0(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallClassVirtual(methodRef)); + return Operator.new(Opcode.CallClassVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallClassVirtual(methodRef)); } def newCallVariantVirtual(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); - return newOp0(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallVariantVirtual(methodRef)); + return Operator.new(Opcode.CallVariantVirtual(methodRef.asMethod()), typeArgs, Opcode2.CallVariantVirtual(methodRef)); } def newCallClassSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallClassSelector(selector), typeArgs, Opcode2.CallClassSelector(methodRef)); + return Operator.new(Opcode.CallClassSelector(selector), typeArgs, Opcode2.CallClassSelector(methodRef)); } def newCallVariantSelector(methodRef: IrSpec) -> Operator { var typeArgs = methodRef.typeArgs, ftype = methodRef.getUnboundType(); var selector = IrSelector.!(methodRef.member); - return newOp0(Opcode.CallVariantSelector(selector), typeArgs, Opcode2.CallVariantSelector(methodRef)); + return Operator.new(Opcode.CallVariantSelector(selector), typeArgs, Opcode2.CallVariantSelector(methodRef)); } def newCallClosure(ftype: Type) -> Operator { - return newOp0(Opcode.CallClosure, [ftype], Opcode2.CallClosure(FuncType.!(ftype))); + return Operator.new(Opcode.CallClosure, [ftype], Opcode2.CallClosure(FuncType.!(ftype))); } def newCallFunction(ftype: Type) -> Operator { ftype = Function.funcRefType(Function.prependParamType(AnyRef.TYPE, ftype)); if (ftype.typeCon.kind != Kind.FUNCREF) return V3.fail("only function types allowed"); - return newOp0(Opcode.CallFunction, [ftype], Opcode2.CallFunction(FuncType.!(ftype))); + return Operator.new(Opcode.CallFunction, [ftype], Opcode2.CallFunction(FuncType.!(ftype))); } def newCreateClosure(methodRef: IrSpec, objType: Type) -> Operator { var typeArgs = methodRef.typeArgs; - return newOp0(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, Opcode2.CreateClosure(objType, methodRef)); + return Operator.new(Opcode.CreateClosure(methodRef.asMethod()), typeArgs, Opcode2.CreateClosure(objType, methodRef)); } def newForgeClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { - return newOp0(Opcode.ForgeClosure, [receiver, param, result], Opcode2.ForgeClosure(PointerType.!(ptrType), receiver, param, result)); + return Operator.new(Opcode.ForgeClosure, [receiver, param, result], Opcode2.ForgeClosure(PointerType.!(ptrType), receiver, param, result)); } def newUnpackClosure(ptrType: Type, receiver: Type, param: Type, result: Type) -> Operator { - return newOp0(Opcode.UnpackClosure, [receiver, param, result], Opcode2.UnpackClosure(PointerType.!(ptrType), receiver, param, result)); + return Operator.new(Opcode.UnpackClosure, [receiver, param, result], Opcode2.UnpackClosure(PointerType.!(ptrType), receiver, param, result)); } def newForgeRange(elementType: Type, ptrType: Type) -> Operator { - return newOp0(Opcode.ForgeRange, [elementType, ptrType], Opcode2.ForgeRange(PointerType.!(ptrType), RangeType.!(V3Range.newType(elementType)))); + return Operator.new(Opcode.ForgeRange, [elementType, ptrType], Opcode2.ForgeRange(PointerType.!(ptrType), RangeType.!(V3Range.newType(elementType)))); } //---------------------------------------------------------------------------- def newSystemCall(syscall: SystemCall, paramTypes: Array, returnType: Type) -> Operator { - return newOp0(Opcode.SystemCall(syscall), arr_v, Opcode2.SystemCall(syscall, Tuple.fromTypeArray(paramTypes), returnType)); + return Operator.new(Opcode.SystemCall(syscall), arr_v, Opcode2.SystemCall(syscall, Tuple.fromTypeArray(paramTypes), returnType)); } //---------------------------------------------------------------------------- def newVstSugar(op: VstOperator, typeParams: Array, paramTypes: Array, result: Type) -> Operator { @@ -419,92 +415,92 @@ component V3Op { } //---------------------------------------------------------------------------- def newPtrAdd(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrAdd, [ptrType, it], Opcode2.PtrAdd(ptrType, IntType.!(it))); + return Operator.new(Opcode.PtrAdd, [ptrType, it], Opcode2.PtrAdd(ptrType, IntType.!(it))); } def newPtrSub(ptrType: Type, it: IntType) -> Operator { - return newOp0(Opcode.PtrSub, [ptrType, it], Opcode2.PtrSub(ptrType, IntType.!(it))); + return Operator.new(Opcode.PtrSub, [ptrType, it], Opcode2.PtrSub(ptrType, IntType.!(it))); } def newPtrLt(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLt, [ptrType], Opcode2.PtrLt(PointerType.!(ptrType))); + return Operator.new(Opcode.PtrLt, [ptrType], Opcode2.PtrLt(PointerType.!(ptrType))); } def newPtrLteq(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrLteq, [ptrType], Opcode2.PtrLteq(PointerType.!(ptrType))); + return Operator.new(Opcode.PtrLteq, [ptrType], Opcode2.PtrLteq(PointerType.!(ptrType))); } def newPtrAtContents(rangeType: Type, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtContents, [rangeType], Opcode2.PtrAtContents(PointerType.!(ptrType), rangeType)); + return Operator.new(Opcode.PtrAtContents, [rangeType], Opcode2.PtrAtContents(PointerType.!(ptrType), rangeType)); } def newPtrAtLength(arrayType: Type, ptrType: Type) -> Operator { var tt = [arrayType]; - return newOp0(Opcode.PtrAtLength, tt, Opcode2.PtrAtLength(PointerType.!(ptrType), ArrayType.!(arrayType))); + return Operator.new(Opcode.PtrAtLength, tt, Opcode2.PtrAtLength(PointerType.!(ptrType), ArrayType.!(arrayType))); } def newPtrAtObject(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtObject, tt, Opcode2.PtrAtObject(PointerType.!(ptrType), objType)); + return Operator.new(Opcode.PtrAtObject, tt, Opcode2.PtrAtObject(PointerType.!(ptrType), objType)); } def newPtrAtArrayElem(arrayType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [arrayType, indexType]; - return newOp0(Opcode.PtrAtArrayElem, tt, Opcode2.PtrAtArrayElem(PointerType.!(ptrType), ArrayType.!(arrayType), IntType.!(indexType))); + return Operator.new(Opcode.PtrAtArrayElem, tt, Opcode2.PtrAtArrayElem(PointerType.!(ptrType), ArrayType.!(arrayType), IntType.!(indexType))); } def newPtrAtRangeElem(rangeType: Type, indexType: IntType, ptrType: Type) -> Operator { var tt = [rangeType, indexType]; - return newOp0(Opcode.PtrAtRangeElem, tt, Opcode2.PtrAtRangeElem(PointerType.!(ptrType), RangeType.!(rangeType), IntType.!(indexType))); + return Operator.new(Opcode.PtrAtRangeElem, tt, Opcode2.PtrAtRangeElem(PointerType.!(ptrType), RangeType.!(rangeType), IntType.!(indexType))); } def newPtrAtEnd(objType: Type, ptrType: Type) -> Operator { var tt = [objType]; - return newOp0(Opcode.PtrAtEnd, tt, Opcode2.PtrAtEnd(PointerType.!(ptrType), objType)); + return Operator.new(Opcode.PtrAtEnd, tt, Opcode2.PtrAtEnd(PointerType.!(ptrType), objType)); } def newPtrAtRef(layoutType: Type, ptrType: Type) -> Operator { var tt = [layoutType]; - return newOp0(Opcode.PtrAtRef, tt, Opcode2.PtrAtRef(PointerType.!(ptrType), layoutType)); + return Operator.new(Opcode.PtrAtRef, tt, Opcode2.PtrAtRef(PointerType.!(ptrType), layoutType)); } def newPtrAtComponentField(spec: IrSpec, ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], Opcode2.PtrAtComponentField(PointerType.!(ptrType), spec)); + return Operator.new(Opcode.PtrAtComponentField(spec.asField()), [spec.receiver], Opcode2.PtrAtComponentField(PointerType.!(ptrType), spec)); } def newPtrAtObjectField(spec: IrSpec, ptrType: Type) -> Operator { var tt = [spec.receiver]; - return newOp0(Opcode.PtrAtObjectField(spec.asField()), tt, Opcode2.PtrAtObjectField(PointerType.!(ptrType), spec)); + return Operator.new(Opcode.PtrAtObjectField(spec.asField()), tt, Opcode2.PtrAtObjectField(PointerType.!(ptrType), spec)); } def newPtrAtRefLayoutField(refType: Type, offset: int, ptrType: Type) -> Operator { var ta = [refType]; - return newOp0(Opcode.PtrAtRefLayoutField(offset), ta, Opcode2.PtrAtRefLayoutField(RefType.!(refType), PointerType.!(ptrType), offset)); + return Operator.new(Opcode.PtrAtRefLayoutField(offset), ta, Opcode2.PtrAtRefLayoutField(RefType.!(refType), PointerType.!(ptrType), offset)); } def newPtrAtUnboxedObjectField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedObjectField(specs, PointerType.!(ptrType))); + return Operator.new(Opcode.PtrAtUnboxedObjectField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedObjectField(specs, PointerType.!(ptrType))); } def newPtrAtUnboxedComponentField(specs: List, ptrType: Type) -> Operator { var ta = [specs.head.receiver]; - return newOp0(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedComponentField(specs, PointerType.!(ptrType))); + return Operator.new(Opcode.PtrAtUnboxedComponentField(Lists.map(specs, IrSpec.asField)), ta, Opcode2.PtrAtUnboxedComponentField(specs, PointerType.!(ptrType))); } def newPtrCmpSwp(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrCmpSwp, [ptrType, valueType], Opcode2.PtrCmpSwp(PointerType.!(ptrType), valueType)); + return Operator.new(Opcode.PtrCmpSwp, [ptrType, valueType], Opcode2.PtrCmpSwp(PointerType.!(ptrType), valueType)); } def newPtrLoad(ptrType: Type, valueType: Type) -> Operator { - return newOp0(Opcode.PtrLoad, [ptrType, valueType], Opcode2.PtrLoad(ptrType, valueType)); + return Operator.new(Opcode.PtrLoad, [ptrType, valueType], Opcode2.PtrLoad(ptrType, valueType)); } def newPtrStore(ptrType: Type, valueType: Type) -> Operator { var tt = [ptrType, valueType]; - return newOp0(Opcode.PtrStore, tt, Opcode2.PtrStore(ptrType, valueType)); + return Operator.new(Opcode.PtrStore, tt, Opcode2.PtrStore(ptrType, valueType)); } def newPtrAddRangeStart(ptrType: Type) -> Operator { - return newOp0(Opcode.PtrAddRangeStart, [ptrType], Opcode2.PtrAddRangeStart(PointerType.!(ptrType))); + return Operator.new(Opcode.PtrAddRangeStart, [ptrType], Opcode2.PtrAddRangeStart(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newCallerIp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerIp, TypeUtil.NO_TYPES, Opcode2.CallerIp(PointerType.!(ptrType))); + return Operator.new(Opcode.CallerIp, TypeUtil.NO_TYPES, Opcode2.CallerIp(PointerType.!(ptrType))); } def newCallerSp(ptrType: Type) -> Operator { - return newOp0(Opcode.CallerSp, TypeUtil.NO_TYPES, Opcode2.CallerSp(PointerType.!(ptrType))); + return Operator.new(Opcode.CallerSp, TypeUtil.NO_TYPES, Opcode2.CallerSp(PointerType.!(ptrType))); } //---------------------------------------------------------------------------- def newAlloc(ptrType: Type) -> Operator { - return newOp0(Opcode.Alloc, [ptrType], Opcode2.Alloc(ptrType)); + return Operator.new(Opcode.Alloc, [ptrType], Opcode2.Alloc(ptrType)); } //---------------------------------------------------------------------------- def newCallAddress(p: PointerType, rep: Mach_FuncRep) -> Operator { var funcType = rep.machType.nested.head; - return newOp0(Opcode.CallAddress(rep), [rep.machType], Opcode2.CallAddress(p, rep)); + return Operator.new(Opcode.CallAddress(rep), [rep.machType], Opcode2.CallAddress(p, rep)); } def newCallKernel(kernel: Kernel, typeParams: Array, sig: Signature) -> Operator { return Operator.new(Opcode.CallKernel(kernel), typeParams, Opcode2.CallKernel(kernel, sig.paramTypes, sig.returnType())); @@ -512,42 +508,42 @@ component V3Op { //---------------------------------------------------------------------------- def newRefLayoutAt(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutAt, at, Opcode2.RefLayoutAt(refType)); + return Operator.new(Opcode.RefLayoutAt, at, Opcode2.RefLayoutAt(refType)); } def newRefLayoutOf(refType: RefType) -> Operator { var at: Array = [refType]; - return newOp0(Opcode.RefLayoutOf, at, Opcode2.RefLayoutOf(refType)); + return Operator.new(Opcode.RefLayoutOf, at, Opcode2.RefLayoutOf(refType)); } def newRefLayoutIn(refType: RefType, offset: int, result: RefType) -> Operator { var at: Array = [refType, result]; - return newOp0(Opcode.RefLayoutIn(offset), at, Opcode2.RefLayoutIn(refType, offset, result)); + return Operator.new(Opcode.RefLayoutIn(offset), at, Opcode2.RefLayoutIn(refType, offset, result)); } def newRefLayoutGetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { - return newOp0(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], Opcode2.RefLayoutGetField(refType, offset, fieldType)); + return Operator.new(Opcode.RefLayoutGetField(offset, order), [refType, fieldType], Opcode2.RefLayoutGetField(refType, offset, fieldType)); } def newRefLayoutSetField(refType: RefType, offset: int, fieldType: Type, order: ByteOrder) -> Operator { var at = [refType, fieldType]; - return newOp0(Opcode.RefLayoutSetField(offset, order), at, Opcode2.RefLayoutSetField(refType, offset, fieldType)); + return Operator.new(Opcode.RefLayoutSetField(offset, order), at, Opcode2.RefLayoutSetField(refType, offset, fieldType)); } 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], Opcode2.RefLayoutAtRepeatedField(refType, offset, scale, max, result)); + return Operator.new(opcode, [refType, result], Opcode2.RefLayoutAtRepeatedField(refType, offset, scale, max, result)); } 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], Opcode2.RefLayoutGetRepeatedField(refType, offset, scale, max, fieldType)); + return Operator.new(opcode, [refType, fieldType], Opcode2.RefLayoutGetRepeatedField(refType, offset, scale, max, fieldType)); } 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], Opcode2.RefLayoutSetRepeatedField(refType, offset, scale, max, fieldType)); + return Operator.new(opcode, [refType, fieldType], Opcode2.RefLayoutSetRepeatedField(refType, offset, scale, max, fieldType)); } def newByteArrayGetField(offset: int, fieldType: Type, order: ByteOrder, startType: Type) -> Operator { var opcode = Opcode.ByteArrayGetField(offset, order); - return newOp0(opcode, [fieldType, startType], Opcode2.ByteArrayGetField(startType, offset, fieldType)); + return Operator.new(opcode, [fieldType, startType], Opcode2.ByteArrayGetField(startType, offset, fieldType)); } def newByteArraySetField(offset: int, fieldType: Type, order: ByteOrder, startType: Type) -> Operator { var opcode = Opcode.ByteArraySetField(offset, order); - return newOp0(opcode, [fieldType, startType], Opcode2.ByteArraySetField(startType, offset, fieldType)); + return Operator.new(opcode, [fieldType, startType], Opcode2.ByteArraySetField(startType, offset, fieldType)); } //---------------------------------------------------------------------------- def bestCallVirtual(spec: IrSpec) -> Operator { diff --git a/aeneas/src/core/Operator2.v3 b/aeneas/src/core/Operator2.v3 index 462969569..243c5aad0 100644 --- a/aeneas/src/core/Operator2.v3 +++ b/aeneas/src/core/Operator2.v3 @@ -9,13 +9,11 @@ class Operator2(opcode: Opcode2) { return if(sig_ != null, sig_, makeSig().sig_); } def subst(func: Type -> Type) -> Operator2 { - if (checkOpenness() == Open.CLOSED) return this; + if (openness == Open.CLOSED) return this; + if (openness == Open.UNKNOWN) openness = Opcodes2.checkOpenness(opcode); + if (openness == Open.CLOSED) return this; return Operator2.new(Opcodes2.subst(opcode, func)); } - def checkOpenness() -> Open { - if (openness != Open.UNKNOWN) return openness; - return openness = Opcodes2.checkOpenness(opcode); - } private def makeSig() -> this { match (opcode) { // Boolean operators @@ -299,7 +297,9 @@ class Operator2(opcode: Opcode2) { } } def isPolymorphic() -> bool { - return checkOpenness() == Open.OPEN; + if (openness == Open.CLOSED) return false; + if (openness == Open.UNKNOWN) openness = Opcodes2.checkOpenness(opcode); + return openness != Open.CLOSED; } private def set_x_x(x: Type) { var arr_x = [x]; From 36d3d4ca611ded82e2525ab08bef6be2ffcfc31a Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Tue, 3 Jun 2025 17:09:22 +0200 Subject: [PATCH 15/17] WIP add Opcodes2.render --- aeneas/src/core/Opcode2.v3 | 171 +++++++++++++++++++++++++++++++++--- aeneas/src/core/Operator.v3 | 4 +- aeneas/src/util/Terminal.v3 | 27 ++++++ 3 files changed, 190 insertions(+), 12 deletions(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index e8a57eab5..a53da1dba 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -160,11 +160,11 @@ type Opcode2 { case PtrAtArrayElem(t: PointerType, arrayType: ArrayType, it: IntType); case PtrAtEnd(t: PointerType, objType: Type); case PtrAtRef(t: PointerType, refType: Type); // TODO: refType: RefType - case PtrAtComponentField(t: PointerType, field: IrSpec); - case PtrAtObjectField(t: PointerType, field: IrSpec); + case PtrAtComponentField(t: PointerType, spec: IrSpec); + case PtrAtObjectField(t: PointerType, spec: IrSpec); case PtrAtRefLayoutField(refType: RefType, t: PointerType, offset: int); - case PtrAtUnboxedObjectField(fields: List, t: PointerType); - case PtrAtUnboxedComponentField(fields: List, t: PointerType); + case PtrAtUnboxedObjectField(specs: List, t: PointerType); + case PtrAtUnboxedComponentField(specs: List, t: PointerType); case PtrCmpSwp(t: PointerType, valType: Type); case PtrLoad(t: Type, valType: Type); case PtrStore(t: Type, valType: Type); @@ -422,10 +422,10 @@ component Opcodes2 { PtrAtArrayElem(t, at, it) => open = isOpenType(at); PtrAtRef(t, refType) => open = isOpenType(refType); PtrAtEnd(t, objType) => open = isOpenType(objType); - PtrAtObjectField(t, field) => open = isOpenType(t); + PtrAtObjectField(t, spec) => open = isOpenType(t); PtrAtRefLayoutField(refType, t, offset) => open = isOpenType(t); - PtrAtUnboxedObjectField(fields, ptrType) => open = isOpenSpecs(fields); - PtrAtUnboxedComponentField(fields, ptrType) => open = isOpenSpecs(fields); + PtrAtUnboxedObjectField(specs, ptrType) => open = isOpenSpecs(specs); + PtrAtUnboxedComponentField(specs, ptrType) => open = isOpenSpecs(specs); PtrCmpSwp(t, valType) => open = isOpenType(valType); PtrLoad(t, valType) => open = isOpenType(valType); PtrStore(t, valType) => open = isOpenType(valType); @@ -516,10 +516,10 @@ component Opcodes2 { PtrAtArrayElem(t, at, it) => return Opcode2.PtrAtArrayElem(t, substArrayType(at, func), it); PtrAtRef(t, refType) => return Opcode2.PtrAtRef(t, func(refType)); PtrAtEnd(t, objType) => return Opcode2.PtrAtEnd(t, func(objType)); - PtrAtObjectField(t, field) => return Opcode2.PtrAtObjectField(t, substSpec(field, func)); + PtrAtObjectField(t, spec) => return Opcode2.PtrAtObjectField(t, substSpec(spec, func)); PtrAtRefLayoutField(refType, t, offset) => return Opcode2.PtrAtRefLayoutField(substRefType(refType, func), t, offset); - PtrAtUnboxedObjectField(fields, ptrType) => return Opcode2.PtrAtUnboxedObjectField(Lists.map(fields, substSpec(_, func)), ptrType); // XXX: optimize closed case - PtrAtUnboxedComponentField(fields, ptrType) => return Opcode2.PtrAtUnboxedComponentField(Lists.map(fields, substSpec(_, func)), ptrType); // XXX: optimize closed case + PtrAtUnboxedObjectField(specs, ptrType) => return Opcode2.PtrAtUnboxedObjectField(Lists.map(specs, substSpec(_, func)), ptrType); // XXX: optimize closed case + PtrAtUnboxedComponentField(specs, ptrType) => return Opcode2.PtrAtUnboxedComponentField(Lists.map(specs, substSpec(_, func)), ptrType); // XXX: optimize closed case PtrCmpSwp(t, valType) => return Opcode2.PtrCmpSwp(t, func(valType)); PtrLoad(t, valType) => return Opcode2.PtrLoad(t, func(valType)); PtrStore(t, valType) => return Opcode2.PtrStore(t, func(valType)); @@ -535,6 +535,157 @@ component Opcodes2 { _ => return opcode; } } + def render(op: Opcode2, buf: TerminalBuffer) -> TerminalBuffer { + buf.puts(op.name); + def ta = buf.putTypeArg, tf = buf.putToFrom, ta2 = buf.putTypeArg2, tas = buf.putTypeArgs; + match (op) { + IntEq(t) => ta(t); + IntAdd(t) => ta(t); + IntSub(t) => ta(t); + IntMul(t) => ta(t); + IntDiv(t) => ta(t); + IntMod(t) => ta(t); + IntAnd(t) => ta(t); + IntOr(t) => ta(t); + IntXor(t) => ta(t); + IntShl(t) => ta(t); + IntSar(t) => ta(t); + IntShr(t) => ta(t); + IntLt(t) => ta(t); + IntLteq(t) => ta(t); + IntWide(op, paramTypes, resultTypes) => ; + FloatAdd(t) => ta(t); + FloatSub(t) => ta(t); + FloatMul(t) => ta(t); + FloatDiv(t) => ta(t); + FloatBitEq(t) => ta(t); + FloatEq(t) => ta(t); + FloatNe(t) => ta(t); + FloatLt(t) => ta(t); + FloatLteq(t) => ta(t); + FloatAbs(t) => ta(t); + FloatCeil(t) => ta(t); + FloatFloor(t) => ta(t); + FloatSqrt(t) => ta(t); + IntCastF(to, from) => tf(to, from); + IntQueryF(to, from) => tf(to, from); + IntViewI(to, from) => tf(to, from); + IntViewF(to, from) => tf(to, from); + IntTruncF(to, from) => tf(to, from); + FloatCastI(to, from) => tf(to, from); + FloatCastD(to, from) => tf(to, from); + FloatQueryI(to, from) => tf(to, from); + FloatQueryD(to, from) => tf(to, from); + FloatPromoteI(to, from) => tf(to, from); + FloatPromoteF(to, from) => tf(to, from); + FloatViewI(to, from) => tf(to, from); + FloatRoundI(to, from) => tf(to, from); + FloatRound(t) => ta(t); + FloatRoundD(to, from) => tf(to, from); + RefEq(t) => ta(t); + DefaultValue(t) => ta(t); + IntRepCreate(to, from) => tf(to, from); + IntRepView(to, from) => tf(to, from); + TupleCreate(t) => ta(t); + TupleGetElem(t, index) => ; + ArrayAlloc(t) => ta(t); + ArrayFill(t) => ta(t); + ArrayInit(t, length) => ; + ArrayTupleInit(t, elems, length) => ; + ArrayGetElem(t, it) => ta2(t, it); + ArraySetElem(t, it) => ta2(t, it); + ArrayGetElemElem(t, it, index) => ta2(t, it).putd(index); // TODO [ + ArraySetElemElem(t, it, index) => ta2(t, it).putd(index); // TODO [ + ArrayGetLength(t) => ta(t); + RangeFromTo(t, startType, lengthType) => tas([t, startType, lengthType]); + RangeFromPlus(t, startType, endType) => tas([t, startType, endType]); + RangeGetElem(t, it) => ta2(t, it); + RangeSetElem(t, it) => ta2(t, it); + RangeGetLength(t) => ta(t); + RangeStartPlusIndex(t, it) => ta2(t, it); + RangeStartFromPointer(t, pt) => tf(t, pt); + NormRangeGetElem(t, it) => ta2(t, it); + NormRangeGetElemElem(t, index, it) => ; + NormRangeSetElem(t, it) => ta2(t, it); + NormRangeSetElemElem(t, index, it) => ; + Init(method) => ; + ComponentGetField(field) => ; + ComponentSetField(field) => ; + ClassAlloc(spec) => ; + ClassEmptyAlloc(t, paramTypes) => ta(t); + ClassGetField(spec) => ; + ClassInitField(spec) => ; + ClassSetField(spec) => ; + ClassGetMethod(spec) => ; + ClassGetVirtual(spec) => ; + ClassGetSelector(spec) => ; + VariantEq(t) => ta(t); + VariantGetTag(t) => ta(t); + VariantAlloc(t, paramTypes) => ta(t); + VariantGetField(spec) => ; + VariantGetMethod(spec) => ; + VariantGetVirtual(spec) => ; + VariantGetSelector(spec) => ; + NullCheck(t) => ta(t); + BoundsCheck(t) => ta(t); + ConditionalThrow(exception) => ; + OverloadedEq(t) => ta(t); + TypeCast(cast, to, from) => tf(to, from); + TypeQuery(query, to, from) => tf(to, from); + TypeSubsume(to, from) => tf(to, from); + CallMethod(spec) => ; + CallClassMethod(spec) => ; + CallClassVirtual(spec) => ; + CallClassSelector(spec) => ; + CallVariantVirtual(spec) => ; + CallVariantSelector(spec) => ; + CallClosure(t) => ta(t); + CallFunction(t) => ta(t); + CreateClosure(obj, method) => ; + ForgeClosure(ptrType, closureType, paramType, resultType) => ; + UnpackClosure(ptrType, closureType, paramType, resultType) => ; + RefLayoutAt(t) => ta(t); + RefLayoutOf(t) => ta(t); + RefLayoutIn(t, offset, rt) => ; + RefLayoutGetField(t, offset, ft) => ; + RefLayoutSetField(t, offset, ft) => ; + RefLayoutAtRepeatedField(t, offset, scale, max, rt) => ; + RefLayoutGetRepeatedField(t, offset, scale, max, ft) => ; + RefLayoutSetRepeatedField(t, offset, scale, max, ft) => ; + ByteArrayGetField(st, offset, ft) => ; + ByteArraySetField(st, offset, ft) => ; + ForgeRange(ptrType, t) => ta2(ptrType, t); + SystemCall(syscall, paramType, resultType) => ; + VstSugar(op, paramTypes, resultType) => ; + PtrAdd(t, it) => ta2(t, it); + PtrSub(t, it) => ta2(t, it); + PtrLt(t) => ta(t); + PtrLteq(t) => ta(t); + PtrAtContents(t, at) => ta2(t, at); + PtrAtLength(t, arrayType) => ta2(t, arrayType); + PtrAtObject(t, objType) => ta2(t, objType); + PtrAtRangeElem(t, rangeType, it) => tas([t, rangeType, it]); + PtrAtArrayElem(t, arrayType, it) => tas([t, arrayType, it]); + PtrAtEnd(t, objType) => ta2(t, objType); + PtrAtRef(t, refType) => ta2(t, refType); + PtrAtComponentField(t, spec) => ; + PtrAtObjectField(t, spec) => ; + PtrAtRefLayoutField(refType, t, offset) => ; + PtrAtUnboxedObjectField(specs, t) => ; + PtrAtUnboxedComponentField(specs, t) => ; + PtrCmpSwp(t, valType) => ta2(t, valType); + PtrLoad(t, valType) => ta2(t, valType); + PtrStore(t, valType) => ta2(t, valType); + PtrAddRangeStart(t) => ta(t); + CallerIp(t) => ta(t); + CallerSp(t) => ta(t); + Alloc(t) => ta(t); + CallAddress(p, rep) => ; + CallKernel(kernel, paramTypes, resultType) => ; + _ => ; + } + return buf; + } def isOpenType(t: Type) -> Open { return if(t.open(), Open.OPEN, Open.CLOSED); } diff --git a/aeneas/src/core/Operator.v3 b/aeneas/src/core/Operator.v3 index 99977807f..c7b1fbf3b 100644 --- a/aeneas/src/core/Operator.v3 +++ b/aeneas/src/core/Operator.v3 @@ -30,7 +30,7 @@ class Operator(opcode: Opcode, typeArgs: Array, opc2: Opcode2) { if (this == that) return true; return this.opcode == that.opcode && Arrays.equal(this.typeArgs, that.typeArgs); } - def render(buf: StringBuilder) -> StringBuilder { + def render(buf: TerminalBuffer) -> StringBuilder { return renderOp(this, buf); } def sig() -> Signature { @@ -587,7 +587,7 @@ def renderList(sb: StringBuilder, lst: List, return sb; } -def renderOp(op: Operator, buf: StringBuilder) -> StringBuilder { +def renderOp(op: Operator, buf: TerminalBuffer) -> StringBuilder { buf.puts(op.opcode.name); if (TerminalBuffer.?(buf)) TerminalBuffer.!(buf).green(); diff --git a/aeneas/src/util/Terminal.v3 b/aeneas/src/util/Terminal.v3 index d7da423e4..8ed20448a 100644 --- a/aeneas/src/util/Terminal.v3 +++ b/aeneas/src/util/Terminal.v3 @@ -107,6 +107,33 @@ class TerminalBuffer extends StringBuilder { putd(i.uid); end(); } + def putTypeArg(t: Type) -> this { + putc('<'); + t.render(this); + putc('>'); + } + def putTypeArg2(a: Type, b: Type) -> this { + putc('<'); + a.render(this); + csp(); + b.render(this); + putc('>'); + } + def putTypeArgs(a: Range) -> this { + putc('<'); + for (i < a.length) { + if (i > 0) csp(); + a[i].render(this); + } + putc('>'); + } + def putToFrom(to: Type, from: Type) -> this { + putc('<'); + from.render(this); + puts(" -> "); + to.render(this); + putc('>'); + } // Selectable palette def valColor() -> this { puts(color = Terminal.CTRL_MAGENTA); From 2a8b695dd3713242710138902d360b8888325872 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Wed, 4 Jun 2025 08:37:37 +0200 Subject: [PATCH 16/17] WIP visitor --- aeneas/src/core/Opcode2.v3 | 156 ++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/aeneas/src/core/Opcode2.v3 b/aeneas/src/core/Opcode2.v3 index a53da1dba..a6ba8a347 100644 --- a/aeneas/src/core/Opcode2.v3 +++ b/aeneas/src/core/Opcode2.v3 @@ -4,7 +4,7 @@ // Represents the statically-known part of an operation, not including the types. type Opcode2 { // Boolean operators - case BoolEq; + case BoolEq { def accept(v: Opcode2Visitor, p: P) -> R { return v.visitBoolEq(this, p); } } case BoolAnd; case BoolOr; case BoolNot; @@ -177,6 +177,160 @@ type Opcode2 { // Call case CallAddress(p: PointerType, rep: Mach_FuncRep); case CallKernel(kernel: Kernel, paramTypes: Array, resultType: Type); + + def accept(v: Opcode2Visitor, p: P) -> R; +} + +class Opcode2Visitor { + def visitOp(op: Opcode2, p: P) -> R; + + def visitBoolEq(op: Opcode2.BoolEq, p: P) -> R { return visitOp(op, p); } + def visitBoolAnd(op: Opcode2.BoolAnd, p: P) -> R { return visitOp(op, p); } + def visitBoolOr(op: Opcode2.BoolOr, p: P) -> R { return visitOp(op, p); } + def visitBoolNot(op: Opcode2.BoolNot, p: P) -> R { return visitOp(op, p); } + def visitIntEq(op: Opcode2.IntEq, p: P) -> R { return visitOp(op, p); } + def visitIntAdd(op: Opcode2.IntAdd, p: P) -> R { return visitOp(op, p); } + def visitIntSub(op: Opcode2.IntSub, p: P) -> R { return visitOp(op, p); } + def visitIntMul(op: Opcode2.IntMul, p: P) -> R { return visitOp(op, p); } + def visitIntDiv(op: Opcode2.IntDiv, p: P) -> R { return visitOp(op, p); } + def visitIntMod(op: Opcode2.IntMod, p: P) -> R { return visitOp(op, p); } + def visitIntAnd(op: Opcode2.IntAnd, p: P) -> R { return visitOp(op, p); } + def visitIntOr(op: Opcode2.IntOr, p: P) -> R { return visitOp(op, p); } + def visitIntXor(op: Opcode2.IntXor, p: P) -> R { return visitOp(op, p); } + def visitIntShl(op: Opcode2.IntShl, p: P) -> R { return visitOp(op, p); } + def visitIntSar(op: Opcode2.IntSar, p: P) -> R { return visitOp(op, p); } + def visitIntShr(op: Opcode2.IntShr, p: P) -> R { return visitOp(op, p); } + def visitIntLt(op: Opcode2.IntLt, p: P) -> R { return visitOp(op, p); } + def visitIntLteq(op: Opcode2.IntLteq, p: P) -> R { return visitOp(op, p); } + def visitIntWide(op: Opcode2.IntWide, p: P) -> R { return visitOp(op, p); } + def visitFloatAdd(op: Opcode2.FloatAdd, p: P) -> R { return visitOp(op, p); } + def visitFloatSub(op: Opcode2.FloatSub, p: P) -> R { return visitOp(op, p); } + def visitFloatMul(op: Opcode2.FloatMul, p: P) -> R { return visitOp(op, p); } + def visitFloatDiv(op: Opcode2.FloatDiv, p: P) -> R { return visitOp(op, p); } + def visitFloatBitEq(op: Opcode2.FloatBitEq, p: P) -> R { return visitOp(op, p); } + def visitFloatEq(op: Opcode2.FloatEq, p: P) -> R { return visitOp(op, p); } + def visitFloatNe(op: Opcode2.FloatNe, p: P) -> R { return visitOp(op, p); } + def visitFloatLt(op: Opcode2.FloatLt, p: P) -> R { return visitOp(op, p); } + def visitFloatLteq(op: Opcode2.FloatLteq, p: P) -> R { return visitOp(op, p); } + def visitFloatAbs(op: Opcode2.FloatAbs, p: P) -> R { return visitOp(op, p); } + def visitFloatCeil(op: Opcode2.FloatCeil, p: P) -> R { return visitOp(op, p); } + def visitFloatFloor(op: Opcode2.FloatFloor, p: P) -> R { return visitOp(op, p); } + def visitFloatSqrt(op: Opcode2.FloatSqrt, p: P) -> R { return visitOp(op, p); } + def visitIntCastF(op: Opcode2.IntCastF, p: P) -> R { return visitOp(op, p); } + def visitIntQueryF(op: Opcode2.IntQueryF, p: P) -> R { return visitOp(op, p); } + def visitIntViewI(op: Opcode2.IntViewI, p: P) -> R { return visitOp(op, p); } + def visitIntViewF(op: Opcode2.IntViewF, p: P) -> R { return visitOp(op, p); } + def visitIntTruncF(op: Opcode2.IntTruncF, p: P) -> R { return visitOp(op, p); } + def visitFloatCastI(op: Opcode2.FloatCastI, p: P) -> R { return visitOp(op, p); } + def visitFloatCastD(op: Opcode2.FloatCastD, p: P) -> R { return visitOp(op, p); } + def visitFloatQueryI(op: Opcode2.FloatQueryI, p: P) -> R { return visitOp(op, p); } + def visitFloatQueryD(op: Opcode2.FloatQueryD, p: P) -> R { return visitOp(op, p); } + def visitFloatPromoteI(op: Opcode2.FloatPromoteI, p: P) -> R { return visitOp(op, p); } + def visitFloatPromoteF(op: Opcode2.FloatPromoteF, p: P) -> R { return visitOp(op, p); } + def visitFloatViewI(op: Opcode2.FloatViewI, p: P) -> R { return visitOp(op, p); } + def visitFloatRoundI(op: Opcode2.FloatRoundI, p: P) -> R { return visitOp(op, p); } + def visitFloatRound(op: Opcode2.FloatRound, p: P) -> R { return visitOp(op, p); } + def visitFloatRoundD(op: Opcode2.FloatRoundD, p: P) -> R { return visitOp(op, p); } + def visitRefEq(op: Opcode2.RefEq, p: P) -> R { return visitOp(op, p); } + def visitDefaultValue(op: Opcode2.DefaultValue, p: P) -> R { return visitOp(op, p); } + def visitIntRepCreate(op: Opcode2.IntRepCreate, p: P) -> R { return visitOp(op, p); } + def visitIntRepView(op: Opcode2.IntRepView, p: P) -> R { return visitOp(op, p); } + def visitTupleCreate(op: Opcode2.TupleCreate, p: P) -> R { return visitOp(op, p); } + def visitTupleGetElem(op: Opcode2.TupleGetElem, p: P) -> R { return visitOp(op, p); } + def visitArrayAlloc(op: Opcode2.ArrayAlloc, p: P) -> R { return visitOp(op, p); } + def visitArrayFill(op: Opcode2.ArrayFill, p: P) -> R { return visitOp(op, p); } + def visitArrayInit(op: Opcode2.ArrayInit, p: P) -> R { return visitOp(op, p); } + def visitArrayTupleInit(op: Opcode2.ArrayTupleInit, p: P) -> R { return visitOp(op, p); } + def visitArrayGetElem(op: Opcode2.ArrayGetElem, p: P) -> R { return visitOp(op, p); } + def visitArraySetElem(op: Opcode2.ArraySetElem, p: P) -> R { return visitOp(op, p); } + def visitArrayGetElemElem(op: Opcode2.ArrayGetElemElem, p: P) -> R { return visitOp(op, p); } + def visitArraySetElemElem(op: Opcode2.ArraySetElemElem, p: P) -> R { return visitOp(op, p); } + def visitArrayGetLength(op: Opcode2.ArrayGetLength, p: P) -> R { return visitOp(op, p); } + def visitRangeFromTo(op: Opcode2.RangeFromTo, p: P) -> R { return visitOp(op, p); } + def visitRangeFromPlus(op: Opcode2.RangeFromPlus, p: P) -> R { return visitOp(op, p); } + def visitRangeGetElem(op: Opcode2.RangeGetElem, p: P) -> R { return visitOp(op, p); } + def visitRangeSetElem(op: Opcode2.RangeSetElem, p: P) -> R { return visitOp(op, p); } + def visitRangeGetLength(op: Opcode2.RangeGetLength, p: P) -> R { return visitOp(op, p); } + def visitRangeStartPlusIndex(op: Opcode2.RangeStartPlusIndex, p: P) -> R { return visitOp(op, p); } + def visitRangeStartFromPointer(op: Opcode2.RangeStartFromPointer, p: P) -> R { return visitOp(op, p); } + def visitNormRangeGetElem(op: Opcode2.NormRangeGetElem, p: P) -> R { return visitOp(op, p); } + def visitNormRangeGetElemElem(op: Opcode2.NormRangeGetElemElem, p: P) -> R { return visitOp(op, p); } + def visitNormRangeSetElem(op: Opcode2.NormRangeSetElem, p: P) -> R { return visitOp(op, p); } + def visitNormRangeSetElemElem(op: Opcode2.NormRangeSetElemElem, p: P) -> R { return visitOp(op, p); } + def visitInit(op: Opcode2.Init, p: P) -> R { return visitOp(op, p); } + def visitComponentGetField(op: Opcode2.ComponentGetField, p: P) -> R { return visitOp(op, p); } + def visitComponentSetField(op: Opcode2.ComponentSetField, p: P) -> R { return visitOp(op, p); } + def visitClassAlloc(op: Opcode2.ClassAlloc, p: P) -> R { return visitOp(op, p); } + def visitClassEmptyAlloc(op: Opcode2.ClassEmptyAlloc, p: P) -> R { return visitOp(op, p); } + def visitClassGetField(op: Opcode2.ClassGetField, p: P) -> R { return visitOp(op, p); } + def visitClassInitField(op: Opcode2.ClassInitField, p: P) -> R { return visitOp(op, p); } + def visitClassSetField(op: Opcode2.ClassSetField, p: P) -> R { return visitOp(op, p); } + def visitClassGetMethod(op: Opcode2.ClassGetMethod, p: P) -> R { return visitOp(op, p); } + def visitClassGetVirtual(op: Opcode2.ClassGetVirtual, p: P) -> R { return visitOp(op, p); } + def visitClassGetSelector(op: Opcode2.ClassGetSelector, p: P) -> R { return visitOp(op, p); } + def visitVariantEq(op: Opcode2.VariantEq, p: P) -> R { return visitOp(op, p); } + def visitVariantGetTag(op: Opcode2.VariantGetTag, p: P) -> R { return visitOp(op, p); } + def visitVariantAlloc(op: Opcode2.VariantAlloc, p: P) -> R { return visitOp(op, p); } + def visitVariantGetField(op: Opcode2.VariantGetField, p: P) -> R { return visitOp(op, p); } + def visitVariantGetMethod(op: Opcode2.VariantGetMethod, p: P) -> R { return visitOp(op, p); } + def visitVariantGetVirtual(op: Opcode2.VariantGetVirtual, p: P) -> R { return visitOp(op, p); } + def visitVariantGetSelector(op: Opcode2.VariantGetSelector, p: P) -> R { return visitOp(op, p); } + def visitNullCheck(op: Opcode2.NullCheck, p: P) -> R { return visitOp(op, p); } + def visitBoundsCheck(op: Opcode2.BoundsCheck, p: P) -> R { return visitOp(op, p); } + def visitConditionalThrow(op: Opcode2.ConditionalThrow, p: P) -> R { return visitOp(op, p); } + def visitOverloadedEq(op: Opcode2.OverloadedEq, p: P) -> R { return visitOp(op, p); } + def visitTypeCast(op: Opcode2.TypeCast, p: P) -> R { return visitOp(op, p); } + def visitTypeQuery(op: Opcode2.TypeQuery, p: P) -> R { return visitOp(op, p); } + def visitTypeSubsume(op: Opcode2.TypeSubsume, p: P) -> R { return visitOp(op, p); } + def visitCallMethod(op: Opcode2.CallMethod, p: P) -> R { return visitOp(op, p); } + def visitCallClassMethod(op: Opcode2.CallClassMethod, p: P) -> R { return visitOp(op, p); } + def visitCallClassVirtual(op: Opcode2.CallClassVirtual, p: P) -> R { return visitOp(op, p); } + def visitCallClassSelector(op: Opcode2.CallClassSelector, p: P) -> R { return visitOp(op, p); } + def visitCallVariantVirtual(op: Opcode2.CallVariantVirtual, p: P) -> R { return visitOp(op, p); } + def visitCallVariantSelector(op: Opcode2.CallVariantSelector, p: P) -> R { return visitOp(op, p); } + def visitCallClosure(op: Opcode2.CallClosure, p: P) -> R { return visitOp(op, p); } + def visitCallFunction(op: Opcode2.CallFunction, p: P) -> R { return visitOp(op, p); } + def visitCreateClosure(op: Opcode2.CreateClosure, p: P) -> R { return visitOp(op, p); } + def visitForgeClosure(op: Opcode2.ForgeClosure, p: P) -> R { return visitOp(op, p); } + def visitUnpackClosure(op: Opcode2.UnpackClosure, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutAt(op: Opcode2.RefLayoutAt, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutOf(op: Opcode2.RefLayoutOf, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutIn(op: Opcode2.RefLayoutIn, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutGetField(op: Opcode2.RefLayoutGetField, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutSetField(op: Opcode2.RefLayoutSetField, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutAtRepeatedField(op: Opcode2.RefLayoutAtRepeatedField, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutGetRepeatedField(op: Opcode2.RefLayoutGetRepeatedField, p: P) -> R { return visitOp(op, p); } + def visitRefLayoutSetRepeatedField(op: Opcode2.RefLayoutSetRepeatedField, p: P) -> R { return visitOp(op, p); } + def visitByteArrayGetField(op: Opcode2.ByteArrayGetField, p: P) -> R { return visitOp(op, p); } + def visitByteArraySetField(op: Opcode2.ByteArraySetField, p: P) -> R { return visitOp(op, p); } + def visitForgeRange(op: Opcode2.ForgeRange, p: P) -> R { return visitOp(op, p); } + def visitSystemCall(op: Opcode2.SystemCall, p: P) -> R { return visitOp(op, p); } + def visitVstSugar(op: Opcode2.VstSugar, p: P) -> R { return visitOp(op, p); } + def visitPtrAdd(op: Opcode2.PtrAdd, p: P) -> R { return visitOp(op, p); } + def visitPtrSub(op: Opcode2.PtrSub, p: P) -> R { return visitOp(op, p); } + def visitPtrLt(op: Opcode2.PtrLt, p: P) -> R { return visitOp(op, p); } + def visitPtrLteq(op: Opcode2.PtrLteq, p: P) -> R { return visitOp(op, p); } + def visitPtrAtContents(op: Opcode2.PtrAtContents, p: P) -> R { return visitOp(op, p); } + def visitPtrAtLength(op: Opcode2.PtrAtLength, p: P) -> R { return visitOp(op, p); } + def visitPtrAtObject(op: Opcode2.PtrAtObject, p: P) -> R { return visitOp(op, p); } + def visitPtrAtRangeElem(op: Opcode2.PtrAtRangeElem, p: P) -> R { return visitOp(op, p); } + def visitPtrAtArrayElem(op: Opcode2.PtrAtArrayElem, p: P) -> R { return visitOp(op, p); } + def visitPtrAtEnd(op: Opcode2.PtrAtEnd, p: P) -> R { return visitOp(op, p); } + def visitPtrAtRef(op: Opcode2.PtrAtRef, p: P) -> R { return visitOp(op, p); } + def visitPtrAtComponentField(op: Opcode2.PtrAtComponentField, p: P) -> R { return visitOp(op, p); } + def visitPtrAtObjectField(op: Opcode2.PtrAtObjectField, p: P) -> R { return visitOp(op, p); } + def visitPtrAtRefLayoutField(op: Opcode2.PtrAtRefLayoutField, p: P) -> R { return visitOp(op, p); } + def visitPtrAtUnboxedObjectField(op: Opcode2.PtrAtUnboxedObjectField, p: P) -> R { return visitOp(op, p); } + def visitPtrAtUnboxedComponentField(op: Opcode2.PtrAtUnboxedComponentField, p: P) -> R { return visitOp(op, p); } + def visitPtrCmpSwp(op: Opcode2.PtrCmpSwp, p: P) -> R { return visitOp(op, p); } + def visitPtrLoad(op: Opcode2.PtrLoad, p: P) -> R { return visitOp(op, p); } + def visitPtrStore(op: Opcode2.PtrStore, p: P) -> R { return visitOp(op, p); } + def visitPtrAddRangeStart(op: Opcode2.PtrAddRangeStart, p: P) -> R { return visitOp(op, p); } + def visitCallerIp(op: Opcode2.CallerIp, p: P) -> R { return visitOp(op, p); } + def visitCallerSp(op: Opcode2.CallerSp, p: P) -> R { return visitOp(op, p); } + def visitAlloc(op: Opcode2.Alloc, p: P) -> R { return visitOp(op, p); } + def visitCallAddress(op: Opcode2.CallAddress, p: P) -> R { return visitOp(op, p); } + def visitCallKernel(op: Opcode2.CallKernel, p: P) -> R { return visitOp(op, p); } } component Opcodes2 { From 5c0af9b9bc08bdcd15054ebf31042a60ecbe3841 Mon Sep 17 00:00:00 2001 From: "Ben L. Titzer" Date: Thu, 14 Aug 2025 09:07:14 -0400 Subject: [PATCH 17/17] Fix sig --- aeneas/src/ir/Packing.v3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aeneas/src/ir/Packing.v3 b/aeneas/src/ir/Packing.v3 index e604a19fd..16ffff5b7 100644 --- a/aeneas/src/ir/Packing.v3 +++ b/aeneas/src/ir/Packing.v3 @@ -57,7 +57,7 @@ class SsaPacker(builder: SsaBuilder, result: IntType) { } x: FloatType => { var op = if(x.width == 32, V3Op.opIntViewF32, V3Op.opIntViewF64); - ft = IntType.!(op.sig.returnType()); + ft = IntType.!(op.sig().returnType()); i = builder.pure(op, [i]); } _ => {