1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
use core:asm;
use core:lang;
use lang:bs:macro;
// Hints for the C++ module.
progvis:program:Hints hints() {
progvis:program:Hints(CppCodeHints(), CppViewHints());
}
/**
* Code hints.
*
* We can take all local variables and just put them inside a Variant directly, since they are
* already allocated that way.
*/
class CppCodeHints extends progvis:program:CodeHints {
init() {
init() {
// Anything not starting with a letter is an operator.
operators("[^a-zA-Z_].*");
}
}
// Regex for matching operators.
lang:bnf:Regex operators;
Fn<void>? findMain(Package pkg) : override {
if (fn = pkg.find(SimplePart("main"), Scope(pkg)) as Function) {
var ptr = fn.pointer;
if (ptr as Fn<void>)
return ptr;
// TODO: Wrap output in a better way.
if (ptr as Fn<Int>)
return &ptr.wrapMain();
}
// TODO: Perhaps support "argc, argv" parameters as well!
null;
}
Bool handlesFunction(Function fn) : override {
if (fn as CppFunction)
true;
else
false;
}
Str cleanName(Function fn, Package pkg) : override {
Str name = fn.name;
if (fn.isMember()) {
if (t = fn.params[0].type) {
if (fn.name == "__destroy") {
return "~" + t.name + "()";
} else if (fn.name == "__init") {
name = t.name;
} else if (operators.match(fn.name)) {
name = "operator " + fn.name;
}
}
}
// TODO!
name + "(...)";
}
Bool patchExternal(Function fn) : override {
// Patch functions in our runtime. Otherwise memory accesses are not tracked very
// well. Additionally, we need to patch things inside the Ptr<> classes.
if (fn.hasParent(named{runtime}))
return true;
if (ptr = fn.parent as PtrType)
return true;
false;
}
progvis:program:Barrier functionBarrier(Function fn) : override {
// No extra barriers for functions in our runtime.
if (fn.hasParent(named{runtime}))
return progvis:program:Barrier:none;
// Neither for things in core.
if (fn.hasParent(named{core}))
return progvis:program:Barrier:none;
// For other functions in Progvis, no barrier there either. These are implementation details
// that we don't want to be visible.
if (fn.hasParent(named{progvis}))
return progvis:program:Barrier:none;
// All other functions, we insert a barrier for. We don't know what they do.
return progvis:program:Barrier:full;
}
Save saveVariable(Listing to, Var var, Listing:VarInfo info, Operand dest) : override {
if (!info.ref)
return Save:none;
// If the variable is a reference to a value and a parameter, we assume that it originates
// from a pointer allocation somewhere. It could, however, be allocated on the stack, which
// in itself is fine as long as we don't try to read the type information from the RawPtr
// created in the end.
if (to.isParam(var)) {
// Variables like this are followed by an integer variable specifying their original offset.
Var next = nextParam(var, to);
if (next == Var())
return Save:none;
if (next.size != sNat)
return Save:none;
unless (type = (named{}).find(SimplePart("Ptr", [Value(info.type)]), Scope()) as Type)
throw InternalError("Could not find a pointer type for ${info.type}.");
to << fnParam(ptrDesc, type.typeRef);
to << fnParam(ptrDesc, ptrConst(1));
to << fnCall(ref(BuiltIn:allocArray), false, ptrDesc, ptrA);
to << mov(ptrB, var);
to << ucast(ptrC, next);
to << sub(ptrB, ptrC);
to << mov(ptrRel(ptrA, Offset(sPtr)), ptrConst(1)); // filled
to << mov(ptrRel(ptrA, Offset(sPtr*2)), ptrB); // base
to << mov(intRel(ptrA, Offset(sPtr*3)), next); // offset
to << mov(dest, ptrA);
} else {
to << mov(dest, var);
}
Save:ref;
}
// Find the next parameter.
private Var nextParam(Var param, Listing in) : static {
Var[] params = in.allParams();
for (i, v in params) {
if (v == param) {
if (i + 1 < params.count)
return params[i + 1];
}
}
return Var();
}
}
void wrapMain(Fn<Int> fn) {
var program = progvis:program:findProgram();
var result = fn.call.toS();
if (program) {
program.addOutput("\nMain returned ${result}\n");
program.notifyChange(true);
}
}
|