Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve scripts (pull request) #373

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
61486a1
Small fix to the aeneas script to make it a little more robust
eliotmoss Nov 18, 2024
1c90622
Merge branch 'master' of github.com:eliotmoss/virgil
eliotmoss Nov 19, 2024
a5aae35
Merge branch 'master' of github.com:eliotmoss/virgil
eliotmoss Dec 3, 2024
b809701
Work to date on the Wasm GC beck end. Will continue this work on thi…
eliotmoss Feb 24, 2025
18c9f4f
Changes to make scripts more robust to users changing cd, etc.
eliotmoss Mar 5, 2025
19140a5
Merge branch 'master' into improve_scripts_PR
eliotmoss Mar 5, 2025
6442930
Update Ir.v3
eliotmoss Mar 5, 2025
9af8edc
Update WasmGcTarget.v3
eliotmoss Mar 5, 2025
493ef54
Update WasmGcTarget.v3
eliotmoss Mar 5, 2025
3fc3bbb
Lack of quotes seems to break things - testing with quotes added
eliotmoss Mar 5, 2025
5ad14fd
Problem seems to be changed directory name, not quotes (makes more se…
eliotmoss Mar 5, 2025
c54417f
These had directory name changes too
eliotmoss Mar 5, 2025
c080e28
This seemed not to be used, but I'm still seeing failures, so trying …
eliotmoss Mar 5, 2025
c5f9ace
Had messed up one of the directory names
eliotmoss Mar 6, 2025
6c922ee
A ci file needs a slight change - it references a non-existent target
eliotmoss Mar 6, 2025
8b9f0e3
[ideas] Convert InitSyntax.v3 to more JSON-like syntax
titzer Mar 6, 2025
b01e8f4
Use VariantAlloc operator instead of ClassAlloc, which enables better…
titzer Mar 7, 2025
e64483e
[test] Move test/core tests that use variants to test/variants (#377)
titzer Mar 9, 2025
01f78fa
Add x86-64 syscall numbers to LinuxConst (#374)
MSMazaya Mar 10, 2025
1da7ea3
[test] Prune test/fail (#378)
titzer Mar 11, 2025
bdfae00
[doc] Add item for representing closures with variants
titzer Mar 14, 2025
597b2de
[doc] Add item to enable register coalescing
titzer Mar 14, 2025
d013793
Removing extraneous WASM GC stuff
eliotmoss Feb 24, 2025
3dbe55e
Changes to make scripts more robust to users changing cd, etc.
eliotmoss Mar 5, 2025
f40473e
Update WasmGcTarget.v3
eliotmoss Mar 5, 2025
60cf463
Update WasmGcTarget.v3
eliotmoss Mar 5, 2025
e94899a
Lack of quotes seems to break things - testing with quotes added
eliotmoss Mar 5, 2025
20862c1
Problem seems to be changed directory name, not quotes (makes more se…
eliotmoss Mar 5, 2025
90d3db1
These had directory name changes too
eliotmoss Mar 5, 2025
51e23ea
This seemed not to be used, but I'm still seeing failures, so trying …
eliotmoss Mar 5, 2025
d38be7b
Had messed up one of the directory names
eliotmoss Mar 6, 2025
afb2317
A ci file needs a slight change - it references a non-existent target
eliotmoss Mar 6, 2025
f4a10ac
Changes to make scripts more robust to users changing cd, etc.
eliotmoss Mar 5, 2025
7d1f2eb
A ci file needs a slight change - it references a non-existent target
eliotmoss Mar 6, 2025
ad1ae11
Merge branch 'improve_scripts_PR' of github.com:eliotmoss/virgil into…
eliotmoss Mar 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions aeneas/src/core/Eval.v3
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,32 @@ def evalOp(op: Operator, args: Arguments) -> Result {
var val = args.vals[0];
return if(Record.?(val), Int.box(V3.getVariantTag(Record.!(val).rtype)));
}
VariantAlloc => {
var receiver = args.getTypeArg(0);
var prog = args.getProgram();
var ic = prog.ir.makeIrClass(receiver), num_args = args.vals.length, num_fields = ic.fields.length;
var record = prog.newRecord(receiver, num_fields);
// XXX: factor out argument adaption logic somewhere shared
if (args.vals.length == num_fields) {
// arity match; just copy values
for (i < record.values.length) record.values[i] = args.vals[i];
} else if (num_fields == 0) {
// nothing to do (could have been passed explicit void)
} else if (num_fields == 1) {
// box arguments into tuple if necessary
if (num_args > 0) record.values[0] = BoxVal.new(null, Ranges.dup(args.vals));
} else {
// unpack tuple value into individual fields
if (num_args != 1) return args.throw(V3Exception.InternalError, Strings.format2("expected %d values, got %d", num_fields, num_args));
var val = args.vals[0];
match (val) {
null => ; // empty tuple, nothing to do
x: BoxVal => for (i < record.values.length) record.values[i] = x.values[i];
_ => return args.throw(V3Exception.InternalError, Strings.format1("expected tuple value, got %q", V3.renderResult(val, null, _)));
}
}
return record;
}
VariantGetField(field) => {
var object = args.r(0);
return if(object != null, object.values[field.index]);
Expand Down
1 change: 1 addition & 0 deletions aeneas/src/core/Opcode.v3
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type Opcode {
// Variant operations
case VariantEq;
case VariantGetTag;
case VariantAlloc;
case VariantGetField(field: IrField);
case VariantGetMethod(method: IrMethod);
case VariantGetVirtual(method: IrMethod);
Expand Down
3 changes: 3 additions & 0 deletions aeneas/src/core/Operator.v3
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ component V3Op {
var vt = [vtype];
return newOp0(Opcode.VariantGetTag, vt, vt, V3.classDecl(vtype).tagType);
}
def newVariantAlloc(t: Type, fieldTypes: Array<Type>) -> Operator {
return newOp0(Opcode.VariantAlloc, [t], fieldTypes, t);
}
def newVariantGetField(fieldRef: IrSpec) -> Operator {
var tt = [fieldRef.receiver];
return newOp0(Opcode.VariantGetField(fieldRef.asField()), tt, tt, fieldRef.getFieldType());
Expand Down
1 change: 1 addition & 0 deletions aeneas/src/core/Program.v3
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Program {
var mainRootIndex = -1;
var explicitName: string;
var tprog: TargetProgram;
var ra: ReachabilityAnalyzer; // kept upon request
// dynamic portion of the program, including initialized state
var initState: Array<InitState>;
var compRecords: Array<Record>;
Expand Down
3 changes: 2 additions & 1 deletion aeneas/src/ir/Ir.v3
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ class IrSpec(receiver: Type, typeArgs: Array<Type>, member: IrMember) {
return null;
}
}
class IrRoot(name: string, spec: IrSpec) { }
class IrRoot(name: string, spec: IrSpec) {
}
// Utility methods for dealing with Ir classes, methods, and fields
component IrUtil {
def EQUALS_METHOD_INDEX = 1;
Expand Down
118 changes: 65 additions & 53 deletions aeneas/src/ir/Normalization.v3
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
var oldRecord = rc.instances.head;
newRecord = ra.prog.newRecord(tn.newType, rc.liveFields.length);
complexRecordMap[oldRecord] = NO_VALUES;
ra.queue.add(normClassRecord, (rc, oldRecord, newRecord));
ra.queue.add(normClassRecord, (rc, oldRecord, newRecord)); // XXX: inline normClassRecord
}
ra.prog.setComponentRecord(comp, newRecord);
} 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.liveFields.length);
recordMap[oldRecord] = newRecord;
ra.queue.add(normClassRecord, (rc, oldRecord, newRecord));
ra.queue.add(normClassRecord, (rc, oldRecord, newRecord)); // XXX: inline normClassRecord
}
} else {
// synthesize a component type for flattened data types and variants
Expand Down Expand Up @@ -339,28 +339,16 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
}
rc.liveFields = fields.extract();
}
private def getClassAllocIr(rc: RaClass, vn: VariantNorm) -> IrMethod {
if (constructors[vn.oldType] != null) return constructors[vn.oldType];
var context = SsaContext.new(ra.compiler, ra.prog);
var meth = IrMethod.new(vn.oldType, null, Function.siga(rc.origFieldTypes, vn.newType));

var params = Array<SsaParam>.new(meth.sig.paramTypes.length + 1);
var inputs = Array<SsaInstr>.new(meth.sig.paramTypes.length);
params[0] = SsaParam.new(0, vn.oldType);
for (i < inputs.length) inputs[i] = params[i + 1] = SsaParam.new(i + 1, meth.sig.paramTypes[i]);

meth.ssa = SsaGraph.new(params, meth.sig.returnType());
context.enterMethod(meth);

var s = SsaRaNormalizer.new(context, this);
s.newGraph = meth.ssa;
s.curBlock = SsaBuilder.new(context, meth.ssa, meth.ssa.startBlock);

var r = s.genVariantClassAlloc(vn, inputs);
s.curBlock.addReturn(r);
context.printSsa("ClassAlloc");

return constructors[vn.oldType] = meth;
// Compute the normalization of the original field types of a class.
def makeOrigFieldTypes(rc: RaClass) {
if (rc.origFieldTypes != null) return;
var flat = NormFlattener.new(context, norm);
for (i < rc.fields.length) {
var indices = flat.addField(rc, i);
var rf = rc.fields[i];
if (rf != null) rf.origIndices = indices;
}
rc.origFieldTypes = flat.result.extract();
}
// normalize an old record of a class into a new record of a class
def normClassRecord(rc: RaClass, oldRecord: Record, newRecord: Record) {
Expand All @@ -373,42 +361,66 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
result = Array<Val>.new(vn.size);

var rc = ra.getClass(oldRecord.rtype);
vn = VariantNorm.!(norm(oldRecord.rtype));
if (vn.isEnum()) {
return complexRecordMap[oldRecord] = [Int.box(vn.tagValue)];
} else if (rc.isUnboxed()) {
var inputs = Vector<Val>.new().grow(rc.liveFields.length); // XXX: cache cumulative normalized size
var ofs = rc.orig.fields;
for (i < ofs.length) {
var rf = rc.fields[i];
if (rf != null && rf.normIndices.0 >= 0) { // live field
var pos = inputs.length, size = rf.normIndices.1 - rf.normIndices.0;
inputs.resize(pos + size);
normValIntoArray(oldRecord.values[i], rf.typeNorm, inputs.array, pos);
} else { // dead field, supply bottoms
var ft = ofs[i].fieldType;
if (ft.open()) ft = ft.substitute(V3.getTypeArgs(vn.oldType));
var tn = norm(ft);
inputs.putn(Values.BOTTOM, tn.size);
}
}

// Unboxed variants might require some type conversions; generate and run the constructor to do so.
// XXX: Cache constructor; we can't put the constructor in the first slot of rc.orig.methods, since multiple RaClasses could map to the same IrClass
var constructor = getClassAllocIr(rc, vn);
var r = variantInterp.invoke(Closure.new(Values.BOTTOM, IrSpec.new(vn.oldType, TypeUtil.NO_TYPES, constructor)), inputs.extract());
match (r) {
x: BoxVal => for (i < x.values.length) result[i] = x.values[i];
x: Val => result[0] = x;
}
} else {
if (rc.variantNorm == null) {
// Variant is boxed, just normalize it as a record.
var newRecord = ra.prog.newRecord(vn.newType, rc.liveFields.length);
normalizeFields(rc.fields, oldRecord.values, newRecord.values);
recordMap[oldRecord] = newRecord;
result[0] = newRecord;
} else if (vn.isEnum()) {
// Variant is represented by a simple enum.
result[0] = Int.box(rc.variantNorm.tagValue);
} else {
// Variant is unboxed. First normalize fields and then pack them into scalars with a tag.
vn = rc.variantNorm;
var values = Array<Val>.new(rc.liveFields.length);
normalizeFields(rc.fields, oldRecord.values, values);

if (vn.hasExplicitTag()) {
var val = Int.box(vn.tagValue);
var tagIdx = vn.tag.indexes[0];
result[tagIdx] = packScalar(vn.tag.tn.at(0), vn.at(tagIdx), null, val, if(vn.tag.intervals != null, vn.tag.intervals[0]));
}

for (i < vn.fields.length) {
var f = vn.fields[i];
if (f.rf == null) continue;
var from = f.rf.normIndices.0;
for (j < f.indexes.length) {
var idx = f.indexes[j];
var val = values[from + j];
result[idx] = packScalar(f.tn.at(j), vn.at(idx), result[idx], val, if(f.intervals != null, f.intervals[j]));
}
}
}
return complexRecordMap[oldRecord] = result;
}
def packScalar(field_type: Type, scalar_type: Type, scalar: Val, val: Val, interval: Interval) -> Val {
match (scalar_type) {
// TODO: masking of negative integer values
it: IntType => {
match (val) {
x: Float64Val => val = boxL(it.width, long.view(x.bits) << interval.start);
x: Float32Val => val = boxL(it.width, long.view(x.bits) << interval.start);
x: Box<int> => val = boxL(it.width, long.view(x.val) << interval.start);
x: Box<long> => val = boxL(it.width, x.val << interval.start);
x: Box<bool> => val = boxL(it.width, if(x.val, 1L << interval.start));
}
if (scalar != null) match (it.rank) {
SUBI32, SUBU32, I32, U32 => val = Int.box(Int.unbox(scalar) | Int.unbox(val));
SUBI64, SUBU64, I64, U64 => val = Long.box(Long.unboxSU(scalar, false) | Long.unboxSU(val, false));
}
}
_ => if (scalar != null) {
context.fail(Strings.format3("cannot pack field %q into scalar %q with val %q",
field_type.render, scalar_type.render, V3.render(scalar)));
}
}
return val;
}
def boxL(width: byte, v: long) -> Val {
return if(width > 32, Box<long>.new(v), Box<int>.new(int.view(v)));
}
def normalizeFields(rfs: Array<RaField>, oldVals: Array<Val>, newVals: Array<Val>) {
for (i < rfs.length) {
var rf = rfs[i];
Expand Down
30 changes: 24 additions & 6 deletions aeneas/src/ir/Reachability.v3
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ enum RaFact {
}

def DUMP: Terminal;
def XXX: Terminal;
def NONE: RaFact.set;
def countVals(facts: RaFact.set) -> int {
return if(facts.RF_VAL_MANY, 2, if(facts.RF_VAL_ONE, 1));
Expand Down Expand Up @@ -100,6 +99,7 @@ class ReachabilityAnalyzer(compilation: Compilation) {
if (facts.RF_READ) DUMP.put(" read");
if (facts.RF_WRITTEN) DUMP.put(" written");
if (facts.RF_INIT) DUMP.put(" init");
if (facts.RF_VAL_MANY) DUMP.put(" many");
if (facts.RM_LIVE) DUMP.put(" live");
if (virtual != null) DUMP.put(" virtual");
if (facts.RC_LIVE) DUMP.put(" live");
Expand Down Expand Up @@ -318,6 +318,22 @@ class ReachabilityAnalyzer(compilation: Compilation) {
ClassGetMethod(method) => getMethod(op, closureMethod(opMethod(op, method, context)));
CreateClosure(method) => getMethod(op, closureMethod(opMethod(op, method, context)));
ClassGetField(field) => if (op.useList != null) getField(makeField(op, field, context));
VariantAlloc => {
var rc = RaClass.!(makeType(mono(op.op.typeArgs[0], context)));
allocation(rc);
if (op.inputs.length == rc.fields.length) {
for (i < rc.orig.fields.length) {
var rf = makeField2(rc, rc.orig.fields[i]);
initField2(rf, op.inputs[i].dest);
}
} else { // tuple/arity mismatch, be conservative
for (f in rc.orig.fields) {
var rf = makeField2(rc, f);
rf.setFact(RaFact.RF_VAL_MANY);
rf.initFacts = Facts.NONE;
}
}
}
VariantGetField(field) => if (op.useList != null) getField(makeField(op, field, context));
VariantGetVirtual(method) => getVirtual(closureMethod(opMethod(op, method, context)));
VariantGetMethod(method) => getMethod(op, closureMethod(opMethod(op, method, context)));
Expand Down Expand Up @@ -464,7 +480,9 @@ class ReachabilityAnalyzer(compilation: Compilation) {
else rf.setFact(RaFact.RF_VAL_MANY);
}
def initField(op: SsaApplyOp, rf: RaField) {
var val = op.input1();
initField2(rf, op.input1());
}
def initField2(rf: RaField, val: SsaInstr) {
if (SsaConst.?(val)) rf.addValue(SsaConst.!(val).val);
else rf.setFact(RaFact.RF_VAL_MANY);
if (!rf.raFacts.RF_INIT) {
Expand Down Expand Up @@ -577,9 +595,6 @@ class ReachabilityAnalyzer(compilation: Compilation) {
var superType = V3.getSuperType(t), parent: RaClass;
if (superType != null) {
parent = makeClass(superType);
} else {
// make the default variant record for field analysis
deferRecord(V3.makeDefaultVariantRecord(prog, t));
}
var rc = newRaClass(t, ic, parent);
rc.raFacts |= RaFact.RC_VARIANT;
Expand Down Expand Up @@ -657,7 +672,6 @@ class RaClass extends RaType {
}
def makeField(f: IrField, fieldType: Type) -> RaField {
var rf = addField(RaField.new(oldType, f, fieldType));
if (oldType.typeCon.kind == Kind.VARIANT) rf.addValue(null); // TODO: hack for default variant value
return rf;
}
private def addField(rf: RaField) -> RaField {
Expand All @@ -673,6 +687,10 @@ class RaClass extends RaType {
var i = rf.orig.index;
return i < parent.fields.length && parent.fields[i] == rf;
}
def fieldRequiresStorage(i: int) -> bool {
var rf = fields[i];
return rf != null && !rf.isConst() && rf.raFacts.RF_READ;
}
def makeMethod(m: IrMethod, spec: IrSpec) -> RaMethod {
if (m.index >= methods.length) methods = Arrays.grow(methods, methods.length + m.index + 1);
var rm = RaMethod.new(oldType, m, spec);
Expand Down
Loading