const assert = require("assert"); const bigInt = require("big-integer"); module.exports = function buildTomCook(module, _prefix) { const prefix = _prefix || "tomcook"; const definedFunctions = {}; const CHUNK_BITS = 29; const CHUNK_BASE = 1 << CHUNK_BITS; const CHUNK_BASE_MAX = "9223372036317904896"; const CHUNK_MASK = CHUNK_BASE -1; function load(size, c, localVar, pos) { if (size == "l") { return c.i64_load(c.getLocal(localVar), pos*8); } else if (size=="s") { return c.i64_load32_s(c.getLocal(localVar), pos*4); } else { assert(false, "invalid size: "+size); } } function store(size, c, localVar, pos, value) { if (size == "l") { return c.i64_store(c.getLocal(localVar), pos*8, value); } else if (size == "s") { return c.i64_store32(c.getLocal(localVar), pos*4, value); } else { assert(false, "invalid size: "+size); } } function storeAdjusting(size, c, carryVar, dstVar, auxVar, pos) { return c.if( c.i64_lt_s( c.getLocal(carryVar), c.i64_const(0) ), [ ...c.setLocal(auxVar, c.i64_rem_s( c.i64_add( c.i64_const(CHUNK_BASE_MAX), c.getLocal(carryVar) ), c.i64_const(CHUNK_BASE) ) ), ...store(size, c, dstVar, pos, c.getLocal(auxVar)), ...c.setLocal(carryVar, c.i64_sub( c.getLocal(carryVar), c.getLocal(auxVar) ) ) ] , // elsif [ ...store(size, c, dstVar, pos, c.i64_rem_s( c.getLocal(carryVar), c.i64_const(CHUNK_BASE) ) ), ] ); } function buildMul3(sizes) { const fnName = prefix+"_mul3"+sizes; if (definedFunctions[fnName]) return; definedFunctions[fnName] = true; const f = module.addFunction(fnName); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); f.addLocal("a0", "i64"); f.addLocal("a1", "i64"); f.addLocal("a2", "i64"); f.addLocal("b0", "i64"); f.addLocal("b1", "i64"); f.addLocal("b2", "i64"); f.addLocal("c", "i64"); const c = f.getCodeBuilder(); f.addCode( // calculate p c.setLocal("a0", load(sizes[0], c, "x", 0)), c.setLocal("b0", load(sizes[1], c, "y", 0)), c.setLocal("c", c.i64_mul( c.getLocal("a0"), c.getLocal("b0") )), store(sizes[2], c, "r", 0, c.i64_rem_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)) ), c.setLocal("a1", load(sizes[0], c, "x", 1)), c.setLocal("b1", load(sizes[1], c, "y", 1)), c.setLocal("c", c.i64_add( c.i64_div_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)), c.i64_add( c.i64_mul( c.getLocal("a0"), c.getLocal("b1") ), c.i64_mul( c.getLocal("a1"), c.getLocal("b0") ) ) )), store(sizes[2], c, "r", 1, c.i64_rem_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)) ), c.setLocal("a2", load(sizes[0], c, "x", 2)), c.setLocal("b2", load(sizes[1], c, "y", 2)), c.setLocal("c", c.i64_add( c.i64_add( c.i64_mul( c.getLocal("a0"), c.getLocal("b2") ), c.i64_mul( c.getLocal("a2"), c.getLocal("b0") ) ), c.i64_add( c.i64_div_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)), c.i64_mul( c.getLocal("a1"), c.getLocal("b1") ), ) )), store(sizes[2], c, "r", 2, c.i64_rem_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)) ), c.setLocal("c", c.i64_add( c.i64_add( c.i64_div_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)), c.i64_mul( c.getLocal("a1"), c.getLocal("b2")) ), c.i64_mul( c.getLocal("a2"), c.getLocal("b1") ), )), store(sizes[2], c, "r", 3, c.i64_rem_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)) ), c.setLocal("c", c.i64_add( c.i64_mul( c.getLocal("a2"), c.getLocal("b2") ), c.i64_div_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)), )), store(sizes[2], c, "r", 4, c.i64_rem_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)) ), store(sizes[2], c, "r", 5, c.i64_div_s( c.getLocal("c"), c.i64_const(CHUNK_BASE)), ), ); } function buildNeg(n, sizes) { const fnName = prefix+"_neg"+n+sizes; if (definedFunctions[fnName]) return; definedFunctions[fnName] = true; const f = module.addFunction(fnName); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); for (let i=0; i=0; i--) { f.addCode( c.setLocal("c", c.i64_add( c.i64_mul( c.i64_rem_s( c.getLocal("c"), c.getLocal("s64") ), c.i64_const(CHUNK_BASE) ), load(sizes[0], c, "x", i) ) ), store(sizes[1], c, "r", i, c.i64_div_s( c.getLocal("c"), c.getLocal("s64") ) ) ); } } function buildRecompose(n, sizes) { const fnName = prefix+"_recompose"+n+sizes; if (definedFunctions[fnName]) return; definedFunctions[fnName] = true; const sn = n/3; const f = module.addFunction(fnName); f.addParam("s", "i32"); f.addParam("r", "i32"); f.addLocal("c", "i64"); f.addLocal("aux", "i64"); const c = f.getCodeBuilder(); /* 0 sn sn*2 sn*3 sn*4 sn*5 0 sn sn*2 sn*3 sn*4 sn*5 sn+6 sn*7 sn*8 sn*9 b= Math.floor(i/sn) b*2*sn + (i-b*sn) b*2*sn + (i-b*sn) - sn */ f.addCode(c.setLocal("c", c.i64_const(0))); for (let i=0; i