diff --git a/src/gen.cpp b/src/gen.cpp index b03850a..6a85331 100644 --- a/src/gen.cpp +++ b/src/gen.cpp @@ -1,6 +1,9 @@ #include "llvm_gen.hpp" +#include struct OnceCode : public mcl::Generator { + typedef std::map FunctionMap; + Operand Void; uint32_t unit; uint32_t bit; uint32_t N; @@ -9,6 +12,11 @@ struct OnceCode : public mcl::Generator { Function extractHigh; Function mulPos; Function makeNIST_P192; + Function mcl_fpDbl_mod_NIST_P192; + FunctionMap mcl_fp_addNCM; + FunctionMap mcl_fp_subNCM; + FunctionMap mcl_fp_addM; + FunctionMap mcl_fp_subM; void gen_mulUU() { @@ -56,16 +64,23 @@ struct OnceCode : public mcl::Generator { ret(xy); endFunc(); } + Operand extract192to64(const Operand& x, uint32_t shift) + { + Operand y = lshr(x, shift); + y = trunc(y, 64); + return y; + } void gen_makeNIST_P192() { resetGlobalIdx(); + Operand p(Int, 192); Operand p0(Int, 64); Operand p1(Int, 64); Operand p2(Int, 64); Operand _0 = makeImm(64, 0); Operand _1 = makeImm(64, 1); Operand _2 = makeImm(64, 2); - makeNIST_P192 = Function("makeNIST_P192", Operand()); + makeNIST_P192 = Function("makeNIST_P192", p); beginFunc(makeNIST_P192); p0 = sub(_0, _1); p1 = sub(_0, _2); @@ -75,30 +90,188 @@ struct OnceCode : public mcl::Generator { p2 = zext(p2, 192); p1 = shl(p1, 64); p2 = shl(p2, 128); - p0 = add(p0, p1); - p0 = add(p0, p2); - ret(p0); + p = add(p0, p1); + p = add(p, p2); + ret(p); endFunc(); } - void run(uint32_t unit, uint32_t bit) + void gen_mcl_fpDbl_mod_NIST_P192() + { + resetGlobalIdx(); + Operand out(IntPtr, 192); + Operand px(IntPtr, 192); + mcl_fpDbl_mod_NIST_P192 = Function("mcl_fpDbl_mod_NIST_P192", Void, out, px); + beginFunc(mcl_fpDbl_mod_NIST_P192); + + Operand L = load(px); + L = zext(L, 256); + + Operand pH = getelementptr(px, makeImm(32, 1)); + Operand H192 = load(pH); + Operand H = zext(H192, 256); + + Operand H10 = shl(H192, 64); + H10 = zext(H10, 256); + + Operand H2 = extract192to64(H192, 128); + H2 = zext(H2, 256); + Operand H102 = _or(H10, H2); + + H2 = shl(H2, 64); + + Operand t = add(L, H); + t = add(t, H102); + t = add(t, H2); + + Operand e = lshr(t, 192); + e = trunc(e, 64); + e = zext(e, 256); + Operand e2 = shl(e, 64); + e = _or(e, e2); + + t = trunc(t, 192); + t = zext(t, 256); + + Operand z = add(t, e); + Operand p = call(makeNIST_P192); + p = zext(p, 256); + Operand zp = sub(z, p); + Operand c = lshr(zp, 192); + c = trunc(c, 1); + z = select(c, z, zp); + z = trunc(z, 192); + store(z, out); + ret(Void); + endFunc(); + } + void gen_once() { - this->unit = unit; - this->bit = bit; - N = bit / unit; - unit2 = unit * 2; gen_mulUU(); gen_extractHigh(); gen_mulPos(); gen_makeNIST_P192(); + gen_mcl_fpDbl_mod_NIST_P192(); + } + Operand extract(const Operand& x, uint32_t shift) + { + Operand t = lshr(x, shift); + t = trunc(t, unit); + return t; + } + void gen_mcl_fp_addsubNC(bool isAdd) + { + resetGlobalIdx(); + Operand pz(IntPtr, bit); + Operand px(IntPtr, bit); + Operand py(IntPtr, bit); + std::string name; + if (isAdd) { + name = "mcl_fp_addNC" + cybozu::itoa(bit); + mcl_fp_addNCM[bit] = Function(name, Void, pz, px, py); + beginFunc(mcl_fp_addNCM[bit]); + } else { + name = "mcl_fp_subNC" + cybozu::itoa(bit); + mcl_fp_subNCM[bit] = Function(name, Void, pz, px, py); + beginFunc(mcl_fp_subNCM[bit]); + } + Operand x = load(px); + Operand y = load(py); + Operand z; + if (isAdd) { + add(x, y); + } else { + sub(x, y); + } + store(z, pz); + ret(Void); + endFunc(); + } + void gen_mcl_fp_add() + { + resetGlobalIdx(); + Operand pz(IntPtr, bit); + Operand px(IntPtr, bit); + Operand py(IntPtr, bit); + Operand pp(IntPtr, bit); + std::string name = "mcl_fp_add" + cybozu::itoa(bit); + mcl_fp_addM[bit] = Function(name, Void, pz, px, py, pp); + beginFunc(mcl_fp_addM[bit]); + Operand x = load(px); + Operand y = load(py); + Operand p = load(pp); + x = zext(x, bit + unit); + y = zext(y, bit + unit); + p = zext(p, bit + unit); + Operand t0 = add(x, y); + Operand t1 = sub(t0, p); + Operand t = lshr(t1, bit); + t = trunc(t, 1); + t = select(t, t0, t1); + t = trunc(t, bit); + store(t, pz); + ret(Void); + endFunc(); + } + void gen_mcl_fp_sub() + { + resetGlobalIdx(); + Operand pz(IntPtr, bit); + Operand px(IntPtr, bit); + Operand py(IntPtr, bit); + Operand pp(IntPtr, bit); + std::string name = "mcl_fp_sub" + cybozu::itoa(bit); + mcl_fp_subM[bit] = Function(name, Void, pz, px, py, pp); + beginFunc(mcl_fp_subM[bit]); + Operand x = load(px); + Operand y = load(py); + x = zext(x, bit + unit); + y = zext(y, bit + unit); + Operand vc = sub(x, y); + Operand v = trunc(vc, bit); // v = x - y + Operand c = lshr(vc, bit + unit - 1); + c = trunc(c, 1); + Operand p = load(pp); + Operand z = select(c, p, makeImm(bit, 0)); + v = add(v, z); + store(v, pz); + ret(Void); + endFunc(); + } + void gen_all() + { + gen_mcl_fp_addsubNC(true); + gen_mcl_fp_addsubNC(false); + } + void gen_short() + { + gen_mcl_fp_add(); + gen_mcl_fp_sub(); + } + void set(uint32_t unit, uint32_t bit) + { + this->unit = unit; + this->bit = bit; + N = bit / unit; + unit2 = unit * 2; + } + void gen() + { + set(64, 128); + gen_short(); + gen_once(); + for (int i = 128; i < 256; i += unit) { + set(64, i); + gen_all(); + gen_short(); + } } }; - int main() try { OnceCode c; - c.run(64, 256); + c.gen(); } catch (std::exception& e) { printf("ERR %s\n", e.what()); return 1; diff --git a/src/llvm_gen.hpp b/src/llvm_gen.hpp index 4f2d1ac..0f06f0f 100644 --- a/src/llvm_gen.hpp +++ b/src/llvm_gen.hpp @@ -6,6 +6,7 @@ @license modified new BSD license http://opensource.org/licenses/BSD-3-Clause */ +//#define CYBOZU_EXCEPTION_WITH_STACKTRACE #include #include #include @@ -53,7 +54,7 @@ File Param::f; } // mcl::impl struct Generator { - static const uint8_t Void = 0; + static const uint8_t None = 0; static const uint8_t Int = 1; static const uint8_t Imm = 2; static const uint8_t Ptr = 1 << 7; @@ -81,17 +82,12 @@ struct Generator { static inline int& getGlobalIdx() { static int globalIdx = 0; - return globalIdx; + return ++globalIdx; } static inline void resetGlobalIdx() { getGlobalIdx() = 0; } - static inline std::string getGlobalName() - { - int& idx = getGlobalIdx(); - return std::string("reg") + cybozu::itoa(idx++); - } static inline void put(const std::string& str) { impl::Param<>::f.write(str); @@ -105,46 +101,53 @@ struct Generator { Eval mul(const Operand& x, const Operand& y); Eval add(const Operand& x, const Operand& y); Eval sub(const Operand& x, const Operand& y); + Eval _and(const Operand& x, const Operand& y); + Eval _or(const Operand& x, const Operand& y); void ret(const Operand& r); Eval lshr(const Operand& x, uint32_t size); Eval shl(const Operand& x, uint32_t size); Eval trunc(const Operand& x, uint32_t size); Eval getelementptr(const Operand& p, const Operand& i); Eval load(const Operand& p); + void store(const Operand& r, const Operand& p); + Eval select(const Operand& c, const Operand& r1, const Operand& r2); Eval call(const Function& f); Eval call(const Function& f, const Operand& op1); Eval call(const Function& f, const Operand& op1, const Operand& op2); Eval call(const Function& f, const Operand& op1, const Operand& op2, const Operand& op3); Eval call(const Function& f, const Operand& op1, const Operand& op2, const Operand& op3, const Operand& op4); - static inline Operand makeImm(uint32_t bit, uint64_t imm); + Operand makeImm(uint32_t bit, int64_t imm); }; struct Generator::Operand { Type type; uint32_t bit; - uint64_t imm; + int64_t imm; uint32_t idx; - std::string name; - Operand() : type(Void), bit(0), imm(0), idx(0) {} - Operand(Type type, uint32_t bit, const std::string& name = "") - : type(type), bit(bit), imm(0), idx(0), name(name) + Operand() : type(None), bit(0), imm(0), idx(0) {} + Operand(Type type, uint32_t bit) + : type(type), bit(bit), imm(0), idx(getGlobalIdx()) { - if (name.empty()) { - this->name = getGlobalName(); - } } - Operand(const Eval& e); - void operator=(const Eval& e); - - // set (bit, type, imm) by rhs - void set(const Operand& rhs) + Operand(const Operand& rhs) + : type(rhs.type), bit(rhs.bit), imm(rhs.imm), idx(rhs.idx) + { + } + void operator=(const Operand& rhs) { - bit = rhs.bit; type = rhs.type; + bit = rhs.bit; imm = rhs.imm; + idx = rhs.idx; + } + void update() + { + idx = getGlobalIdx(); } - void update() { idx++; } + Operand(const Eval& e); + void operator=(const Eval& e); + std::string toStr() const { if (type.isPtr) { @@ -180,19 +183,14 @@ struct Generator::Operand { default: return ""; case Int: - { - std::string str("%"); - str += name; - if (idx > 0) str += "_" + cybozu::itoa(idx); - return str; - } + return std::string("%r") + cybozu::itoa(idx); case Imm: return cybozu::itoa(imm); } } }; -inline Generator::Operand Generator::makeImm(uint32_t bit, uint64_t imm) +inline Generator::Operand Generator::makeImm(uint32_t bit, int64_t imm) { Generator::Operand v(Generator::Imm, bit); v.imm = imm; @@ -221,10 +219,7 @@ inline Generator::Operand::Operand(const Generator::Eval& e) inline void Generator::Operand::operator=(const Generator::Eval& e) { - type = e.op.type; - bit = e.op.bit; - imm = e.op.imm; - if (name.empty()) name = e.op.name; + *this = e.op; update(); put(getName() + " = " + e.s); e.used = true; @@ -310,7 +305,6 @@ inline Generator::Eval aluSub(const char *name, const Generator::Operand& x, con Generator::Eval e; e.op.type = Generator::Int; e.op.bit = x.bit; - e.op.name = x.name; e.s = name; e.s += " "; e.s += x.toStr() + ", " + y.getName(); @@ -360,6 +354,16 @@ inline Generator::Eval Generator::sub(const Generator::Operand& x, const Generat return impl::aluSub("sub", x, y); } +inline Generator::Eval Generator::_and(const Generator::Operand& x, const Generator::Operand& y) +{ + return impl::aluSub("and", x, y); +} + +inline Generator::Eval Generator::_or(const Generator::Operand& x, const Generator::Operand& y) +{ + return impl::aluSub("or", x, y); +} + inline void Generator::ret(const Generator::Operand& x) { std::string s = "ret " + x.toStr(); @@ -406,6 +410,30 @@ inline Generator::Eval Generator::load(const Generator::Operand& p) return e; } +inline void Generator::store(const Generator::Operand& r, const Generator::Operand& p) +{ + if (!p.type.isPtr) throw cybozu::Exception("Generator:store:not pointer") << p.type; + std::string s = "store "; + s += r.toStr(); + s += ", "; + s += p.toStr(); + put(s); +} + +inline Generator::Eval Generator::select(const Generator::Operand& c, const Generator::Operand& r1, const Generator::Operand& r2) +{ + if (c.bit != 1) throw cybozu::Exception("Generator:select:bad bit") << c.bit; + Eval e; + e.op = r1; + e.s = "select "; + e.s += c.toStr(); + e.s += ", "; + e.s += r1.toStr(); + e.s += ", "; + e.s += r2.toStr(); + return e; +} + inline Generator::Eval Generator::call(const Generator::Function& f) { return impl::callSub(f, 0, 0);