Skip to content

Commit

Permalink
Minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
btwj committed Feb 12, 2024
1 parent e5e6e00 commit e33fbdd
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 41 deletions.
39 changes: 20 additions & 19 deletions aeneas/src/ir/Normalization.v3
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
ra.queue.add(normClassRecord, (rc, oldRecord, newRecord.values));
}
ra.prog.setComponentRecord(comp, newRecord);
} else if (rc.variantNorm == null) {
} else if (!rc.isUnboxed()) {
// create and map new records to be normalized
for (l = rc.instances; l != null; l = l.tail) {
var oldRecord = l.head, newRecord = ra.prog.newRecord(tn.newType, rc.normFields.length);
Expand All @@ -108,7 +108,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
var rm = l.head, m = rm.orig;
if (rm.norm != null) continue; // already done
var ftype = if(rm.spec == null, m.sig.funcType(), rm.spec.getMethodType());
if (rc.variantNorm != null) {
if (rc.isUnboxed()) {
// move flattened data type receiver to function sig
ftype = Function.prependParamTypes(rc.variantNorm.sub, ftype);
}
Expand Down Expand Up @@ -348,21 +348,22 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
return;
}

if (!vn.isEnum()) {
var rfs = vrc.fields;
for (i < vrc.fields.length) {
var rf = vrc.fields[i];
if (rf != null && rf.normIndex >= 0) {
var v = oldRecord.values[i];
var indexes = vn.fields[i].indexes;
var fieldArray = Array<Val>.new(indexes.length);
if (rf.fieldType == null) fieldArray[0] = normSimpleVal(null, v);
else normValIntoArray(v, rf.typeNorm, fieldArray, 0);
for (j < indexes.length) array[indexes[j]] = fieldArray[j];
}
if (!vn.isTagless()) array[vn.tagIndex()] = Int.box(vn.tagValue);
if (vn.isEnum()) return;

var rfs = vrc.fields;
for (i < vrc.fields.length) {
var rf = vrc.fields[i];
if (rf != null && rf.normIndex >= 0) {
var v = oldRecord.values[i];
var indexes = vn.fields[i].indexes;
// XXX: get rid of fieldArray or reuse
var fieldArray = Array<Val>.new(indexes.length);
if (rf.fieldType == null) fieldArray[0] = normSimpleVal(null, v);
else normValIntoArray(v, rf.typeNorm, fieldArray, 0);
for (j < indexes.length) array[indexes[j]] = fieldArray[j];
}
}
if (!vn.isTagless()) array[vn.tagIndex()] = Int.box(vn.tagValue);
}
// normalize the live instances of a simple (i.e. size-1 element) array type
def normSimpleArrayRecord(record: Record) {
Expand Down Expand Up @@ -391,7 +392,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
def normSimpleVal(tn: TypeNorm, v: Val) -> Val {
match (v) {
x: Record => {
if (tn != null && VariantNorm.?(tn) && VariantNorm.!(tn).isEnum()) return normVariantVal(VariantNorm.!(tn), x)[0];
if (VariantNorm.?(tn) && VariantNorm.!(tn).isEnum()) return normVariantVal(VariantNorm.!(tn), x)[0];
var r = recordMap[x];
return if(r == null, x, r);
}
Expand Down Expand Up @@ -450,7 +451,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
var table = Array<IrMethod>.new(size), mtable = IrMtable.new(rm.norm, rc.minClassId, table);
rv.mtable = mtable;

if (rc.variantNorm != null) {
if (rc.isUnboxed()) {
var ft = Function.funcRefType(rm.norm.getMethodType());
mtable.record = ra.prog.newRecord(V3Array.newType(ft), size);
}
Expand Down Expand Up @@ -550,7 +551,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
}
def createIrClass(rc: RaClass) {
var sc = if(rc.parent != null, rc.parent.normClass);
var normFields = if(rc.variantNorm != null, NO_FIELDS, rc.normFields);
var normFields = if(rc.isUnboxed(), NO_FIELDS, rc.normFields);
var ic = IrClass.new(rc.newIrType, null, sc, normFields, rc.normMethods);
ic.minClassId = rc.minClassId;
ic.maxClassId = rc.maxClassId;
Expand All @@ -574,7 +575,7 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
var receiver = ra.oldIr.getIrClass(ctype);
var root = ra.oldIr.getIrClass(V3.getRootType(ctype));
var rc = ra.getClass(rm.receiver);
if (false && rc.variantNorm != null) { // TODO: disable generation of compare method bodies
if (false && rc.isUnboxed()) { // TODO: disable generation of compare method bodies
// flattened data types will have inlined compare
rm.orig.ssa = SsaGraph.new([], Bool.TYPE);
rm.orig.ssa.startBlock.append(SsaReturn.new([rm.orig.ssa.falseConst()]));
Expand Down
1 change: 1 addition & 0 deletions aeneas/src/ir/Reachability.v3
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ class RaClass extends RaType {
}
return true;
}
def isUnboxed() -> bool { return variantNorm != null; }
}
// Tracks instances of an array type.
class RaArray extends RaType {
Expand Down
12 changes: 6 additions & 6 deletions aeneas/src/ir/SsaNormalizer.v3
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ class SsaRaNormalizer extends SsaRebuilder {
var newOp = V3Op.newCallMethod(m);
var newArgs = normArgs(funcNorm, genRefs(app.inputs));
if (V3.isVariant(rc.oldType)) {
if (rc.variantNorm != null) {
if (rc.isUnboxed()) {
// flattened data type becomes component call and needs new receiver
newArgs = Arrays.prepend(newGraph.nullReceiver(), newArgs);
} else {
Expand Down Expand Up @@ -281,7 +281,7 @@ class SsaRaNormalizer extends SsaRebuilder {
var t = extractVirtualRef(orig, method), funcNorm = t.0, m = t.1;
var newArgs = normArgs(funcNorm, genRefs(app.inputs));
if (t.2) { // still a virtual dispatch
if (rc.variantNorm != null) {
if (rc.isUnboxed()) {
// use the variant tag as an index into a table of functions
var tag = newArgs[0];
var record = IrSelector.!(m.member).mtable.record;
Expand All @@ -293,7 +293,7 @@ class SsaRaNormalizer extends SsaRebuilder {
normCall(app, funcNorm, V3Op.newCallVariantSelector(m), newArgs);
}
} else {
if (rc.variantNorm != null) {
if (rc.isUnboxed()) {
// flattened data type becomes component call and needs new receiver
newArgs = Arrays.prepend(newGraph.nullReceiver(), newArgs);
} else {
Expand Down Expand Up @@ -1218,9 +1218,9 @@ class SsaRaNormalizer extends SsaRebuilder {
if (!isVariant) addNullCheck(oldApp, ninputs[0]);
return map0(oldApp);
}
normType(raField.receiver); // XXX: normType() side-effect of flattening
var rc = norm.ra.getClass(raField.receiver);
if (isVariant && raField != null && rc.variantNorm != null) {
normType(raField.receiver); // XXX: normType() side-effect of flattening
if (isVariant && raField != null && rc.isUnboxed()) {
// field of unboxed data type
var vals = Array<SsaInstr>.new(nf.length);
var field = rc.variantNorm.fields[raField.orig.index];
Expand Down Expand Up @@ -1253,7 +1253,7 @@ class SsaRaNormalizer extends SsaRebuilder {
// OPT: remove write of zero-width field
// OPT: remove write of write-only field
return addNullCheck(oldApp, receiver);
} else if (rc.variantNorm != null) {
} else if (rc.isUnboxed()) {
// init/set of field of flattened data type
return map0(oldApp);
} else if (nf.length == 1) {
Expand Down
40 changes: 26 additions & 14 deletions aeneas/src/ir/VariantSolver.v3
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ class VariantField {
def ON_STACK = -1;

class VariantSolver(nc: NormalizerConfig, rn: ReachabilityNormalizer, verbose: bool) {
def variantUnboxMatcher = GlobMatcher.new(CLOptions.UNBOX_VARIANTS.get());

// Normalizes a non-recursive variant, returns either a VariantNorm for an unboxed variant,
// or a simple TypeNorm for a boxed variant
def normVariant(t: Type, rc: RaClass) -> TypeNorm {
if (rc.variantNorm != null) return rc.variantNorm;
if (rc.orig.boxing == Boxing.BOXED) rn.mapSimple(t);
Expand All @@ -83,17 +87,10 @@ class VariantSolver(nc: NormalizerConfig, rn: ReachabilityNormalizer, verbose: b
}
return rn.mapSimple(t);
}
def setVariantNormForChildren(rc: RaClass, tagType: IntType, tagField: VariantField) {
var vn = VariantNorm.new(rc.oldType, tagType, [tagType], [], tagField);
vn.tagValue = V3.getVariantTag(rc.oldType);
rc.raFacts |= RaFact.RC_ENUM;
rc.variantNorm = vn;

for (l = rc.children; l != null; l = l.tail) {
setVariantNormForChildren(l.head, tagType, tagField);
}
}
def tryUnboxing(rc: RaClass) -> bool {
// Try to unbox a variant in one of two ways:
// 1. If a (non-closure) variant has all empty fields in all cases, represent it as a single uN tag (enum representation).
// 2. If a variant has only one case, represent it as a tagless tuple of scalars (data representation).
private def tryUnboxing(rc: RaClass) -> bool {
if (rc.variantNorm != null) return true; // already done
while (rc.parent != null) rc = rc.parent;

Expand All @@ -114,7 +111,7 @@ class VariantSolver(nc: NormalizerConfig, rn: ReachabilityNormalizer, verbose: b
var tagType = V3.getVariantTagType(rc.oldType);
var tagTypeNorm = rn.norm(tagType);
var tagField = VariantField.new(tagTypeNorm, [0]);
setVariantNormForChildren(rc, tagType, tagField);
unboxUsingEnumVariantNorm(rc, tagType, tagField);
return true;
}
if (rc.children != null) {
Expand All @@ -123,14 +120,19 @@ class VariantSolver(nc: NormalizerConfig, rn: ReachabilityNormalizer, verbose: b
}
match (rc.orig.boxing) {
BOXED => return false;
AUTO => if (rc.normFields.length > nc.MaxFlatDataValues && CLOptions.UNBOX_ALL.get()) return false;
AUTO => {
if (rc.normFields.length > nc.MaxFlatDataValues) {
var classDecl = ClassType.!(rc.orig.ctype).classDecl;
if (!variantUnboxMatcher.matches(classDecl.token.image)) return false;
}
}
UNBOXED => ; // program specified unboxed; TODO: recursion or closure should be an error
}
if (rc.recursive > 1 || closure) return false; // recursive or closed over
unboxUsingTaglessVariantNorm(rc);
return true;
}
def unboxUsingTaglessVariantNorm(rc: RaClass) {
private def unboxUsingTaglessVariantNorm(rc: RaClass) {
var ofs = rc.orig.fields;
var fields = Array<VariantField>.new(ofs.length);
var fieldRanges = Array<(int, int)>.new(ofs.length);
Expand Down Expand Up @@ -168,4 +170,14 @@ class VariantSolver(nc: NormalizerConfig, rn: ReachabilityNormalizer, verbose: b

if (verbose) Terminal.put1("variant norm %q\n", rc.variantNorm.render);
}
private def unboxUsingEnumVariantNorm(rc: RaClass, tagType: IntType, tagField: VariantField) {
var vn = VariantNorm.new(rc.oldType, tagType, [tagType], [], tagField);
vn.tagValue = V3.getVariantTag(rc.oldType);
rc.raFacts |= RaFact.RC_ENUM;
rc.variantNorm = vn;

for (l = rc.children; l != null; l = l.tail) {
unboxUsingEnumVariantNorm(l.head, tagType, tagField);
}
}
}
4 changes: 2 additions & 2 deletions aeneas/src/main/CLOptions.v3
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ component CLOptions {
"Automatically set execute permission for compiled binaries.");
def USE_GLOBALREGALLOC = compileOpt.newMatcherOption("global-regalloc",
"Enable global register allocator.");
def UNBOX_VARIANTS = compileOpt.newBoolOption("unbox-variants", false,
def UNBOX_VARIANTS = compileOpt.newStringOption("unbox-variants", "*",
"Enable variant unboxing features.");
def UNBOX_ALL = compileOpt.newBoolOption("unbox-all", false,
def UNBOX_VARIANT_CASES = compileOpt.newStringOption("unbox-variant-cases", "",
"Unbox all non-recursive variants.");
// JVM target options
def JVM_RT_PATH = jvmOpt.newStringOption("jvm.rt-path", null,
Expand Down

0 comments on commit e33fbdd

Please sign in to comment.