Skip to content

Instantly share code, notes, and snippets.

@AdrianV
Created May 20, 2020 10:47
Show Gist options
  • Save AdrianV/49ccc5a7939247ee55a5f33daea96870 to your computer and use it in GitHub Desktop.
Save AdrianV/49ccc5a7939247ee55a5f33daea96870 to your computer and use it in GitHub Desktop.
fast expression evaluation
import VExpr;
import VExpr.C.*;
@:access(VExpr)
class Main {
macro static public function benchmark(test, start, done) {
return macro {
trace($start);
var dt = haxe.Timer.stamp();
$test;
var dur = haxe.Timer.stamp() - dt;
trace($done);
}
}
static inline var cloop = 1000;
static function main() {
var a = VExprInt.Val(0);
var b = VExprInt.Val(0);
var c = VExprInt.Val(0);
var i = VExprInt.Val(0);
var x1 = Set_I(a, VExprInt.Val(10));
trace(x1.code);
x1.run();
trace(a.value);
var loop = ForLoop(Set_I(a, VExprInt.Val(0)),
LessI(a, VExprInt.Val(cloop)),
Inc(a), [
ForLoop(Set_I(b, VExprInt.Val(0)),
LessI(b, VExprInt.Val(cloop)),
Inc(b), [
ForLoop(Set_I(c, VExprInt.Val(0)),
LessI(c, VExprInt.Val(cloop)),
Inc(c), [
Inc(i)
])
]
)
]
);
benchmark(loop.run(), "for loop nested:", 'completed in $dur');
trace(a.value);
trace(b.value);
trace(c.value);
trace(i.value);
i.value = 0;
loop = ForLoop(Set_I(a, VExprInt.Val(0)),
LessI(a, VExprInt.Val(cloop * cloop * cloop)),
Inc(a), [
Inc(i)
]
);
benchmark(loop.run(), "for loop:", 'completed in $dur');
trace(a.value);
trace(b.value);
trace(c.value);
trace(i.value);
}
}
typedef VRunner = Null<Void->Void>;
@:structInit
class VExprInfo {
public var r: VRunner;
public var flat: Bool = true;
}
class VExpr {
var runner: VRunner;
var next: VExpr;
var code: VExpr;
var runNext: VExpr;
var info: VExprInfo;
static public function make() return new VExpr();
public function run() {
if (runner != null) {
var op = runNext;
while (op != null) {
op.runner();
op = op.runNext;
}
runner();
}
}
public function process() {
var op = code;
while (op != null) {
op.run();
op = op.next;
}
}
public function compileRun(prog: Array<VRunner>) {
if (runner != null) {
var op = runNext;
while (op != null) {
if (op.runner != null) prog.push(op.runner);
op = op.runNext;
}
prog.push(runner);
}
}
public function compileProcess(prog: Array<VRunner>) {
var op = code;
while (op != null) {
op.compileRun(prog);
op = op.next;
}
}
static function flatten(op: VExpr) {
op.runNext = null;
if (op.runner == null) return;
var last = op;
op = op.code;
while (op != null) {
if (op.runner != null) {
final x = op;
if ( op.info.flat ) {
last.runNext = x;
last = x.runNext != null ? x.runNext : x;
}
}
op = op.next;
}
}
public inline function new() {}
public function create(info: VExprInfo, ? ops: Array<VExpr>): VExpr {
this.runner = info.r;
this.info = info;
if (ops != null && ops.length > 0) {
var p: VExpr = ops[0];
code = p;
for (x in 1 ... ops.length) {
p.next = ops[x];
p = p.next;
}
if (p != null) p.next = null;
if (info.flat) flatten(this);
} else code = null;
return this;
}
}
class VExprLoop extends VExpr {
public function forLoop() {
this.code.run();
final test = (cast this.code.next: VExprBool);
final next = test.next;
final loop = next.next;
test.run();
while (test.value) {
inline loop.process();
inline next.run();
inline test.run();
}
}
}
class VExprInt extends VExpr {
public var value: Int;
static public function make() return new VExprInt();
static public function Val(v: Int): VExprInt {
var res = new VExprInt();
res.value = v;
return res;
}
public function valOf() {
this.value = (cast this.code: VExprIntVar).value.value;
}
}
class VExprIntVar extends VExpr {
public var value: VExprInt;
static public function make() return new VExprIntVar();
static public function Val(v: VExprInt): VExprIntVar {
var res = new VExprIntVar();
res.value = v;
return res;
}
public function inc1() {
this.value.value++;
}
public function incX() {
this.value.value += (cast this.code: VExprInt).value;
}
public function set() {
this.value.value = (cast this.code: VExprInt).value;
}
}
class VExprFloat extends VExpr {
public var value: Float;
static public function make() return new VExprFloat();
}
class VExprBool extends VExpr {
public var value: Bool;
static public function make() return new VExprBool();
public function lessII() {
this.value = (cast this.code: VExprInt).value < (cast this.code.next: VExprInt).value;
}
}
class C {
static var EMPTY: VExprInfo = {r: null};
static public function Block(block: Array<VExpr>): VExpr {
return new VExpr().create(EMPTY, block);
}
static public function ForLoop(init: VExpr, test: VExprBool, next: VExpr, block: Array<VExpr>): VExpr {
final op = new VExprLoop();
return op.create({r: op.forLoop, flat: false}, [init, test, next, Block(block)]);
}
static public function Set_I(a: VExprInt, v: VExprInt): VExpr {
final op = VExprIntVar.Val(a);
return op.create({r: op.set}, [v]);
}
static public function Inc(a: VExprInt): VExpr {
final op = VExprIntVar.Val(a);
return op.create({r: op.inc1}, []);
}
static public function IncX(a: VExprInt, v: VExprInt): VExpr {
final op = VExprIntVar.Val(a);
return op.create({r: op.incX}, [v]);
}
static public function LessI(a: VExprInt, b: VExprInt): VExprBool {
final op = new VExprBool();
op.create({r: op.lessII}, [a,b]);
return op;
}
static public function ValOf(x: VExprIntVar): VExprInt {
final op = new VExprInt();
op.create({r: op.valOf}, [x]);
return op;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment