ffwasm
Version:
Finite Field Library In Web Assembly
716 lines (662 loc) • 24.5 kB
JavaScript
module.exports = function (ctx) {
function buildRawFixedShl() {
const f = ctx.module.addFunction(ctx.prefix+"_fixedShl");
f.addParam("a", "i64");
f.addParam("b", "i64");
f.setReturnType("i64");
const c = f.getCodeBuilder();
f.addCode(
// i64.shr_u does not return 0 when shifted 64 pos we force here
c.if(
c.i64_ge_u(c.getLocal("b"), c.i64_const(64)),
c.ret(c.i64_const(0))
),
c.i64_shl(
c.getLocal("a"),
c.getLocal("b")
)
);
}
function buildRawFixedShr() {
const f = ctx.module.addFunction(ctx.prefix+"_fixedShr");
f.addParam("a", "i64");
f.addParam("b", "i64");
f.setReturnType("i64");
const c = f.getCodeBuilder();
f.addCode(
// i64.shr_u does not return 0 when shifted 64 pos we force here
c.if(
c.i64_ge_u(c.getLocal("b"), c.i64_const(64)),
c.ret(c.i64_const(0))
),
c.i64_shr_u(
c.getLocal("a"),
c.getLocal("b")
)
);
}
function buildRawGetChunck() {
const f = ctx.module.addFunction(ctx.prefix+"_rawgetchunk");
f.addParam("pA", "i32");
f.addParam("i", "i32");
f.setReturnType("i64");
const c = f.getCodeBuilder();
f.addCode(
// i64.shr_u does not return 0 when shifted 64 pos we force here
c.if(
c.i32_lt_u(c.getLocal("i"), c.i32_const(ctx.n64)),
c.ret(
c.i64_load(
c.i32_add(
c.getLocal("pA"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(8)
)
)
)
)
),
c.i64_const(0)
);
}
function buildAdjustBinResult() {
const f = ctx.module.addFunction(ctx.prefix+"_adjustBinResult");
f.addParam("pA", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.i64_store(
c.getLocal("pA"),
ctx.n64*8,
c.i64_and(
c.i64_load(
c.getLocal("pA"),
ctx.n64*8
),
c.i64_const(ctx.binMask)
)
),
c.if(
c.call(
ctx.prefixI + "_gte",
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.i32_const(ctx.pPrime)
),
c.drop(
c.call(
ctx.prefixI + "_sub",
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.i32_const(ctx.pPrime),
c.i32_add(c.getLocal("pA"), c.i32_const(8))
)
)
)
);
}
function buildRawShiftRightL() {
const f = ctx.module.addFunction(ctx.prefix+"_rawshrl");
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("n", "i32");
f.addLocal("oWords1", "i32");
f.addLocal("oBits1", "i64");
f.addLocal("oWords2", "i32");
f.addLocal("oBits2", "i64");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"oWords1",
c.i32_shr_u(
c.getLocal("n"),
c.i32_const(6)
)
),
c.setLocal(
"oWords2",
c.i32_add(
c.getLocal("oWords1"),
c.i32_const(1)
)
),
c.setLocal(
"oBits1",
c.i64_and(
c.i64_extend_i32_u(c.getLocal("n")),
c.i64_const(0x3F)
)
),
c.setLocal(
"oBits2",
c.i64_sub(
c.i64_const(64),
c.getLocal("oBits1")
)
),
c.setLocal(
"i",
c.i32_const(0)
),
c.block(c.loop(
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(ctx.n64))),
c.i64_store(
c.i32_add(
c.getLocal("pR"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(8)
)
),
c.i64_or(
c.call(
ctx.prefix + "_fixedShr",
c.call(
ctx.prefix + "_rawgetchunk",
c.getLocal("pA"),
c.i32_add(
c.getLocal("oWords1"),
c.getLocal("i")
)
),
c.getLocal("oBits1")
),
c.call(
ctx.prefix + "_fixedShl",
c.call(
ctx.prefix + "_rawgetchunk",
c.getLocal("pA"),
c.i32_add(
c.getLocal("oWords2"),
c.getLocal("i")
)
),
c.getLocal("oBits2")
)
)
),
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
}
function buildRawShiftLeftL() {
const f = ctx.module.addFunction(ctx.prefix+"_rawshll");
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("n", "i32");
f.addLocal("oWords1", "i32");
f.addLocal("oBits1", "i64");
f.addLocal("oWords2", "i32");
f.addLocal("oBits2", "i64");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"oWords1",
c.i32_sub(
c.i32_const(0),
c.i32_shr_u(
c.getLocal("n"),
c.i32_const(6)
)
)
),
c.setLocal(
"oWords2",
c.i32_sub(
c.getLocal("oWords1"),
c.i32_const(1)
)
),
c.setLocal(
"oBits1",
c.i64_and(
c.i64_extend_i32_u(c.getLocal("n")),
c.i64_const(0x3F)
)
),
c.setLocal(
"oBits2",
c.i64_sub(
c.i64_const(64),
c.getLocal("oBits1")
)
),
c.setLocal(
"i",
c.i32_const(0)
),
c.block(c.loop(
c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(ctx.n64))),
c.i64_store(
c.i32_add(
c.getLocal("pR"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(8)
)
),
c.i64_or(
c.call(
ctx.prefix + "_fixedShl",
c.call(
ctx.prefix + "_rawgetchunk",
c.getLocal("pA"),
c.i32_add(
c.getLocal("oWords1"),
c.getLocal("i")
),
),
c.getLocal("oBits1")
),
c.call(
ctx.prefix + "_fixedShr",
c.call(
ctx.prefix + "_rawgetchunk",
c.getLocal("pA"),
c.i32_add(
c.getLocal("oWords2"),
c.getLocal("i")
),
),
c.getLocal("oBits2")
)
)
),
c.setLocal(
"i",
c.i32_add(
c.getLocal("i"),
c.i32_const(1)
)
),
c.br(0)
))
);
}
function buildRawShiftRight() {
const f = ctx.module.addFunction(ctx.prefix+"_rawshr");
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("n", "i32");
const c = f.getCodeBuilder();
f.addCode(
ctx.ifLong(c, "pA",
[
...ctx.toNormal(c, "pA"),
...c.call(
ctx.prefix + "_rawshrl",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.getLocal("n"),
),
...ctx.setType(c, "pR", 0x80)
],[
...ctx.ifNegative(c, "pA",
[
...ctx.toLong(c, "pA"),
...c.call(
ctx.prefix + "_rawshrl",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.getLocal("n"),
),
...ctx.setType(c, "pR", 0x80)
],
[
...c.if(
c.i32_lt_u(
c.getLocal("n"),
c.i32_const(32)
),
c.i32_store(
c.getLocal("pR"),
c.i32_shr_u(
c.i32_load(c.getLocal("pA")),
c.getLocal("n")
)
),
c.i32_store(
c.getLocal("pR"),
c.i32_const(0)
),
),
...ctx.setType(c, "pR", 0)
]
)
]
)
);
}
function buildRawShiftLeft() {
const f = ctx.module.addFunction(ctx.prefix+"_rawshl");
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("n", "i32");
f.addLocal("r", "i64");
f.addLocal("overflow", "i64");
const c = f.getCodeBuilder();
f.addCode(
ctx.ifLong(c, "pA",
[
...ctx.toNormal(c, "pA"),
...c.call(
ctx.prefix + "_rawshll",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.getLocal("n"),
),
...c.call(
ctx.prefix + "_adjustBinResult",
c.getLocal("pR")
),
...ctx.setType(c, "pR", 0x80)
],[
...ctx.ifNegative(c, "pA",
[
...ctx.toLong(c, "pA"),
...c.call(
ctx.prefix + "_rawshll",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.getLocal("n"),
),
...c.call(
ctx.prefix + "_adjustBinResult",
c.getLocal("pR")
),
...ctx.setType(c, "pR", 0x80)
],
[
...c.if(
c.i32_gt_u(c.getLocal("n"), c.i32_const(30)),
[
...ctx.toLong(c, "pA"),
...c.call(
ctx.prefix + "_rawshll",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.getLocal("n"),
),
...c.call(
ctx.prefix + "_adjustBinResult",
c.getLocal("pR")
),
...ctx.setType(c, "pR", 0x80)
],[
...c.setLocal(
"r",
c.i64_shl(
c.i64_load32_s(c.getLocal("pA")),
c.i64_extend_i32_u(c.getLocal("n"))
)
),
...c.setLocal(
"overflow",
c.i64_shr_s(
c.getLocal("r"),
c.i64_const(31)
)
),
...c.if(
c.i32_or(
c.i64_eqz(c.getLocal("overflow")),
c.i64_eqz(c.i64_add(
c.getLocal("overflow"),
c.i64_const(1)
))
),
[
...c.i64_store32(
c.getLocal("pR"),
c.getLocal("r")
),
...c.i32_store(
c.getLocal("pR"),
4,
c.i32_const(0)
)
],[ // Fix overflow
...ctx.setType(c, "pR", 0x80),
...c.call(
ctx.prefix + "_rawCopyS2L",
c.i32_add(c.getLocal("pR"), c.i32_const(8)),
c.getLocal("r")
)
]
)
]
)
]
)
]
)
);
}
function buldShift(op) {
const f = ctx.module.addFunction(ctx.prefix+"_" + op);
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
const oop = op == "shr" ? "shl" : "shr";
const c = f.getCodeBuilder();
f.addCode(
ctx.ifNegative(c, "pB",
[
...c.call(
ctx.prefix + "_neg",
c.i32_const(ctx.pTmp2),
c.getLocal("pB"),
),
...c.call(
ctx.prefix + "_lt",
c.i32_const(ctx.pTmp),
c.i32_const(ctx.pTmp2),
c.i32_const(ctx.pNBits),
),
...c.if(
c.i32_load(c.i32_const(ctx.pTmp)),
[
...c.call(
ctx.prefix + "_raw" + oop,
c.getLocal("pR"),
c.getLocal("pA"),
c.call(
ctx.prefix + "_toInt",
c.i32_const(ctx.pTmp2)
)
)
],[
...c.call(
ctx.prefixI + "_zero",
c.getLocal("pR")
)
]
)
],[
...c.call(
ctx.prefix + "_lt",
c.i32_const(ctx.pTmp),
c.getLocal("pB"),
c.i32_const(ctx.pNBits),
),
...c.if(
c.i32_load(c.i32_const(ctx.pTmp)),
[
...c.call(
ctx.prefix + "_raw"+op,
c.getLocal("pR"),
c.getLocal("pA"),
c.call(
ctx.prefix + "_toInt",
c.getLocal("pB")
)
)
],[
...c.call(
ctx.prefixI + "_zero",
c.getLocal("pR")
)
]
)
]
)
);
}
function buildRawBitOpL(op) {
const f = ctx.module.addFunction(ctx.prefix+"_rawb" + op + "l");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
f.addParam("pR", "i32");
const c = f.getCodeBuilder();
for (let i=0; i<ctx.n64; i++) {
f.addCode(
c.i64_store(
c.getLocal("pR"),
i*8,
c["i64_"+op](
c.i64_load(
c.getLocal("pA"),
i*8
),
c.i64_load(
c.getLocal("pB"),
i*8
)
)
)
);
}
}
function buildBitOp(op) {
buildRawBitOpL(op);
const f = ctx.module.addFunction(ctx.prefix+"_b" + op);
f.addParam("pR", "i32");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
const c = f.getCodeBuilder();
f.addCode(
ctx.ifLong(c, "pA",
[
...buildRawOp()
],[
...ctx.ifNegative(c, "pA",
[
...buildRawOp()
],[
...ctx.ifLong(c, "pB",
[
...buildRawOp()
],[
...ctx.ifNegative(c, "pB",
[
...buildRawOp()
],[
...c.i32_store(
c.getLocal("pR"),
c["i32_"+op](
c.i32_load(c.getLocal("pA")),
c.i32_load(c.getLocal("pB"))
)
),
...ctx.setType(c, "pR", 0x00)
]
)
]
)
]
)
]
)
);
function buildRawOp() {
return [
...ctx.toLong(c, "pA"),
...ctx.toNormal(c, "pA"),
...ctx.toLong(c, "pB"),
...ctx.toNormal(c, "pB"),
...c.call(
ctx.prefix+"_rawb"+op+"l",
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.i32_add(c.getLocal("pB"), c.i32_const(8)),
c.i32_add(c.getLocal("pR"), c.i32_const(8))
),
...ctx.setType(c, "pR", 0x80),
...c.call(
ctx.prefix + "_adjustBinResult",
c.getLocal("pR")
),
];
}
}
function buildRawBitNotL() {
const f = ctx.module.addFunction(ctx.prefix+"_rawbnotl");
f.addParam("pA", "i32");
f.addParam("pR", "i32");
const c = f.getCodeBuilder();
for (let i=0; i<ctx.n64; i++) {
f.addCode(
c.i64_store(
c.getLocal("pR"),
i*8,
c.i64_xor(
c.i64_load(
c.getLocal("pA"),
i*8
),
c.i64_const(-1)
)
)
);
}
}
function buildBitNot() {
buildRawBitNotL();
const f = ctx.module.addFunction(ctx.prefix+"_bnot" );
f.addParam("pR", "i32");
f.addParam("pA", "i32");
const c = f.getCodeBuilder();
f.addCode(
ctx.toLong(c, "pA"),
ctx.toNormal(c, "pA"),
c.call(
ctx.prefix+"_rawbnotl",
c.i32_add(c.getLocal("pA"), c.i32_const(8)),
c.i32_add(c.getLocal("pR"), c.i32_const(8))
),
ctx.setType(c, "pR", 0x80),
c.call(
ctx.prefix + "_adjustBinResult",
c.getLocal("pR")
)
);
}
buildRawFixedShl();
buildRawFixedShr();
buildRawGetChunck();
buildRawShiftLeftL();
buildRawShiftRightL();
buildAdjustBinResult();
buildRawShiftLeft();
buildRawShiftRight();
buldShift("shl");
buldShift("shr");
buildBitOp("and");
buildBitOp("or");
buildBitOp("xor");
buildBitNot();
if (ctx.publish) {
ctx.module.exportFunction(ctx.prefix + "_shr");
ctx.module.exportFunction(ctx.prefix + "_shl");
ctx.module.exportFunction(ctx.prefix + "_band");
ctx.module.exportFunction(ctx.prefix + "_bor");
ctx.module.exportFunction(ctx.prefix + "_bxor");
ctx.module.exportFunction(ctx.prefix + "_bnot");
}
};